使用INDY TCP组件实现基于协议采用XML方式的文件传输

原创 2007年09月20日 11:38:00

 我实现了个,传输的文件大小都没问题,但是除了文本类型的文件打开后查看正常外,其它的文件比如PDF,rar文件等都无法打开。

问题我已经找到并解决了,问题的原因是:因为考虑到XML的编码问题,所以我对传输的文件数据部分的内容进行了加密,在客户端解密,但是可能是加密解密过程中丢失了某些信息,所以才会无法打开。现在我已经把加密解密过程换成采用Mime编码和解码。

编码:

ItemChildNode.NodeValue := MimeEncodeString(ATask_File_Tran_Response.DataString);

解码:

Result.DataString := MimeDecodeString(ItemChildNode.NodeValue);



具体采用的编码解码单元为:

unit EDCode;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

function MimeEncodeString (const s: AnsiString): AnsiString;
function MimeEncodeStringNoCRLF (const s: AnsiString): AnsiString;
function MimeDecodeString (const s: AnsiString): AnsiString;
procedure MimeEncodeStream (const InputStream: TStream; const OutputStream: TStream);
procedure MimeEncodeStreamNoCRLF (const InputStream: TStream; const OutputStream: TStream);
procedure MimeDecodeStream (const InputStream: TStream; const OutputStream: TStream);
function MimeEncodedSize (const i: Cardinal): Cardinal;
function MimeEncodedSizeNoCRLF (const i: Cardinal): Cardinal;
function MimeDecodedSize (const i: Cardinal): Cardinal;
procedure DecodeHttpBasicAuthentication (const BasicCredentials: AnsiString;
out UserId, PassWord: AnsiString);
procedure MimeEncode (const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer);
procedure MimeEncodeNoCRLF (const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer);
procedure MimeEncodeFullLines (const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer);
function MimeDecode (const InputBuffer; const InputBytesCount: Cardinal; out OutputBuffer): Cardinal;
function MimeDecodePartial (const InputBuffer; const InputBytesCount: Cardinal;
out OutputBuffer; var ByteBuffer: Cardinal; var ByteBufferSpace: Cardinal): Cardinal;
function MimeDecodePartialEnd (out OutputBuffer; const ByteBuffer: Cardinal;
const ByteBufferSpace: Cardinal): Cardinal;
procedure Base64Encode(InputFile, OutputFile: string);
procedure Base64Decode(InputFile, OutputFile: string);

const
MIME_ENCODED_LINE_BREAK = 76;
MIME_DECODED_LINE_BREAK = MIME_ENCODED_LINE_BREAK div 4 * 3;
BUFFER_SIZE = MIME_DECODED_LINE_BREAK * 3 * 4 * 16;
MIME_ENCODE_TABLE : array[0..63] of Byte = (
065, 066, 067, 068, 069, 070, 071, 072, // 00 - 07
073, 074, 075, 076, 077, 078, 079, 080, // 08 - 15
081, 082, 083, 084, 085, 086, 087, 088, // 16 - 23
089, 090, 097, 098, 099, 100, 101, 102, // 24 - 31
103, 104, 105, 106, 107, 108, 109, 110, // 32 - 39
111, 112, 113, 114, 115, 116, 117, 118, // 40 - 47
119, 120, 121, 122, 048, 049, 050, 051, // 48 - 55
052, 053, 054, 055, 056, 057, 043, 047); // 56 - 63

MIME_PAD_CHAR = Byte ('=');

MIME_DECODE_TABLE : array[Byte] of Cardinal = (
255, 255, 255, 255, 255, 255, 255, 255, // 00 - 07
255, 255, 255, 255, 255, 255, 255, 255, // 08 - 15
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, // 32 - 39
255, 255, 255, 062, 255, 255, 255, 063, // 40 - 47
052, 053, 054, 055, 056, 057, 058, 059, // 48 - 55
060, 061, 255, 255, 255, 255, 255, 255, // 56 - 63
255, 000, 001, 002, 003, 004, 005, 006, // 64 - 71
007, 008, 009, 010, 011, 012, 013, 014, // 72 - 79
015, 016, 017, 018, 019, 020, 021, 022, // 80 - 87
023, 024, 025, 255, 255, 255, 255, 255, // 88 - 95
255, 026, 027, 028, 029, 030, 031, 032, // 96 - 103
033, 034, 035, 036, 037, 038, 039, 040, // 104 - 111
041, 042, 043, 044, 045, 046, 047, 048, // 112 - 119
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,
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,
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;
TByte3 = packed record
b1: Byte;
b2: Byte;
b3: Byte;
end;

implementation

function MimeEncodeString (const s: AnsiString): AnsiString;
var
l : Cardinal;
begin
if Pointer (s) <> nil then
begin
l := Cardinal (Pointer (Cardinal (s) - 4)^);
SetLength (Result, MimeEncodedSize (l));
MimeEncode (Pointer (s)^, l, Pointer (Result)^);
end
else
Result := '';
end;

function MimeEncodeStringNoCRLF (const s: AnsiString): AnsiString;
var
l : Cardinal;
begin
if Pointer (s) <> nil then
begin
l := Cardinal (Pointer (Cardinal (s) - 4)^);
SetLength (Result, MimeEncodedSizeNoCRLF (l));
MimeEncodeNoCRLF (Pointer (s)^, l, Pointer (Result)^);
end
else
Result := '';
end;

function MimeDecodeString (const s: AnsiString): AnsiString;
var
ByteBuffer, ByteBufferSpace: Cardinal;
l : Cardinal;
begin
if Pointer (s) <> nil then
begin
l := Cardinal (Pointer (Cardinal (s) - 4)^);
SetLength (Result, (l + 3) div 4 * 3);
ByteBuffer := 0;
ByteBufferSpace := 4;
l := MimeDecodePartial (Pointer (s)^, l, Pointer (Result)^, ByteBuffer, ByteBufferSpace);
Inc (l, MimeDecodePartialEnd (Pointer (Cardinal (Result) + l)^,
ByteBuffer, ByteBufferSpace));
SetLength (Result, l);
end
else
Result := '';
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 + BUFFER_SIZE div
MIME_DECODED_LINE_BREAK * 2 - 1] of Byte;
BytesRead : Cardinal;
IDelta, ODelta : Cardinal;
begin
BytesRead := InputStream.Read (InputBuffer, SizeOf (InputBuffer));

while BytesRead = SizeOf (InputBuffer) do
begin
MimeEncodeFullLines (InputBuffer, SizeOf (InputBuffer), OutputBuffer);
OutputStream.Write (OutputBuffer, SizeOf (OutputBuffer));
BytesRead := InputStream.Read (InputBuffer, SizeOf (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;
MimeEncodeNoCRLF(Pointer(Cardinal (@InputBuffer) + IDelta)^, BytesRead - IDelta,
Pointer (Cardinal (@OutputBuffer) + ODelta)^);

OutputStream.Write (OutputBuffer, MimeEncodedSize (BytesRead));
end;

procedure MimeEncodeStreamNoCRLF (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 : Cardinal;
begin
BytesRead := InputStream.Read (InputBuffer, SizeOf (InputBuffer));
while BytesRead = SizeOf (InputBuffer) do
begin
MimeEncodeNoCRLF (InputBuffer, SizeOf (InputBuffer), OutputBuffer);
OutputStream.Write (OutputBuffer, SizeOf (OutputBuffer));
BytesRead := InputStream.Read (InputBuffer, SizeOf (InputBuffer));
end;

MimeEncodeNoCRLF (InputBuffer, BytesRead, OutputBuffer);
OutputStream.Write (OutputBuffer, (BytesRead + 2) div 3 * 4);
end;

procedure MimeDecodeStream (const InputStream: TStream; const OutputStream: TStream);
var
ByteBuffer, ByteBufferSpace: Cardinal;
InputBuffer : array[0..BUFFER_SIZE - 1] of Byte;
OutputBuffer : array[0.. (BUFFER_SIZE + 3) div 4 * 3 - 1] of Byte;
BytesRead : Cardinal;
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;

procedure DecodeHttpBasicAuthentication (const BasicCredentials: AnsiString; out UserId, PassWord: AnsiString);
label
Fail;
const
LBasic = 6; { Length ('Basic ') }
var
DecodedPtr, p : PAnsiChar;
i, l : Cardinal;
begin
p := Pointer (BasicCredentials);
if p = nil then goto Fail;

l := Cardinal (Pointer (p - 4)^);
if l <= LBasic then goto Fail;

Dec (l, LBasic);
Inc (p, LBasic);

GetMem (DecodedPtr, (l + 3) div 4 * 3 { MimeDecodedSize (l) });
l := MimeDecode (p^, l, DecodedPtr^);
i := 0;
p := DecodedPtr;
while (l > 0) and (p[i] <> ':') do
begin
Inc (i);
Dec (l);
end;
SetString (UserId, DecodedPtr, i);
if l > 1 then
SetString (PassWord, DecodedPtr + i + 1, l - 1)
else
PassWord := '';

FreeMem (DecodedPtr);
Exit;

Fail:
UserId := '';
PassWord := '';
end;

function MimeEncodedSize (const i: Cardinal): Cardinal;
begin
Result := (i + 2) div 3 * 4 + (i - 1) div MIME_DECODED_LINE_BREAK * 2;
end;

function MimeEncodedSizeNoCRLF (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;

procedure MimeEncode (const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer);
var
IDelta, ODelta : Cardinal;
begin
MimeEncodeFullLines (InputBuffer, InputByteCount, OutputBuffer);
IDelta := InputByteCount div MIME_DECODED_LINE_BREAK;
ODelta := IDelta * (MIME_ENCODED_LINE_BREAK + 2);
IDelta := IDelta * MIME_DECODED_LINE_BREAK;
MimeEncodeNoCRLF (Pointer (Cardinal (@InputBuffer) + IDelta)^,
InputByteCount - IDelta, Pointer (Cardinal (@OutputBuffer) + ODelta)^);
end;

procedure MimeEncodeFullLines (const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer);
var
b, OuterLimit : Cardinal;
InPtr, InnerLimit : ^Byte;
OutPtr : PByte4;
begin
if InputByteCount = 0 then Exit;
InPtr := @InputBuffer;
OutPtr := @OutputBuffer;

InnerLimit := InPtr;
Inc (Cardinal (InnerLimit), MIME_DECODED_LINE_BREAK);

OuterLimit := Cardinal (InPtr);
Inc (OuterLimit, InputByteCount);

while Cardinal (InnerLimit) <= OuterLimit do
begin

while InPtr <> InnerLimit do
begin
b := InPtr^;
b := b shl 8;
Inc (InPtr);
b := b or InPtr^;
b := b shl 8;
Inc (InPtr);
b := b or InPtr^;
Inc (InPtr);
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);
end;
OutPtr^.b1 := 13;
OutPtr^.b2 := 10;
Inc (Cardinal (OutPtr), 2);

Inc (InnerLimit, MIME_DECODED_LINE_BREAK);
end;

end;

procedure MimeEncodeNoCRLF (const InputBuffer; const InputByteCount: Cardinal; out OutputBuffer);
var
b, OuterLimit : Cardinal;
InPtr, InnerLimit : ^Byte;
OutPtr : PByte4;
begin
if InputByteCount = 0 then Exit;
InPtr := @InputBuffer;
OutPtr := @OutputBuffer;

OuterLimit := InputByteCount div 3 * 3;

InnerLimit := @InputBuffer;
Inc (Cardinal (InnerLimit), OuterLimit);
while InPtr <> InnerLimit do
begin
b := InPtr^;
b := b shl 8;
Inc (InPtr);
b := b or InPtr^;
b := b shl 8;
Inc (InPtr);
b := b or InPtr^;
Inc (InPtr);
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);
end;
case InputByteCount - OuterLimit of
1:
begin
b := InPtr^;
b := b shl 4;
OutPtr.b2 := MIME_ENCODE_TABLE[b and $3F];
b := b shr 6;
OutPtr.b1 := MIME_ENCODE_TABLE[b];
OutPtr.b3 := MIME_PAD_CHAR;
OutPtr.b4 := MIME_PAD_CHAR;
end;
2:
begin
b := InPtr^;
Inc (InPtr);
b := b shl 8;
b := b or InPtr^;
b := b shl 2;
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];
OutPtr.b4 := MIME_PAD_CHAR; { Pad remaining byte. }
end;
end;
end;

function MimeDecode (const InputBuffer; const InputBytesCount: Cardinal;
out OutputBuffer): Cardinal;
var
ByteBuffer, ByteBufferSpace: Cardinal;
begin
ByteBuffer := 0;
ByteBufferSpace := 4;
Result := MimeDecodePartial(InputBuffer, InputBytesCount,
OutputBuffer, ByteBuffer, ByteBufferSpace);
Inc (Result, MimeDecodePartialEnd(Pointer (Cardinal(@OutputBuffer) + Result)^,
ByteBuffer, ByteBufferSpace));
end;

function MimeDecodePartial (const InputBuffer; const InputBytesCount: Cardinal;
out OutputBuffer; var ByteBuffer: Cardinal; var ByteBufferSpace: Cardinal): Cardinal;
var
lByteBuffer, lByteBufferSpace, c: Cardinal;
InPtr, OuterLimit : ^Byte;
OutPtr : PByte3;
begin
if InputBytesCount > 0 then
begin
InPtr := @InputBuffer;
Cardinal (OuterLimit) := Cardinal (InPtr) + InputBytesCount;
OutPtr := @OutputBuffer;
lByteBuffer := ByteBuffer;
lByteBufferSpace := ByteBufferSpace;
while InPtr <> OuterLimit do
begin
c := MIME_DECODE_TABLE[InPtr^];
Inc (InPtr);
if c = $FF then Continue;
lByteBuffer := lByteBuffer shl 6;
lByteBuffer := lByteBuffer or c;
Dec (lByteBufferSpace);
if lByteBufferSpace <> 0 then Continue;
OutPtr^.b3 := Byte (lByteBuffer);
lByteBuffer := lByteBuffer shr 8;
OutPtr^.b2 := Byte (lByteBuffer);
lByteBuffer := lByteBuffer shr 8;
OutPtr^.b1 := Byte (lByteBuffer);
lByteBuffer := 0;
Inc (OutPtr);
lByteBufferSpace := 4;
end;
ByteBuffer := lByteBuffer;
ByteBufferSpace := lByteBufferSpace;
Result := Cardinal (OutPtr) - Cardinal (@OutputBuffer);
end
else
Result := 0;
end;

function MimeDecodePartialEnd (out OutputBuffer; const ByteBuffer: Cardinal;
const ByteBufferSpace: Cardinal): Cardinal;
var
lByteBuffer : Cardinal;
begin
case ByteBufferSpace of
1:
begin
lByteBuffer := ByteBuffer shr 2;
PByte3 (@OutputBuffer)^.b2 := Byte (lByteBuffer);
lByteBuffer := lByteBuffer shr 8;
PByte3 (@OutputBuffer)^.b1 := Byte (lByteBuffer);
Result := 2;
end;
2:
begin
lByteBuffer := ByteBuffer shr 4;
PByte3 (@OutputBuffer)^.b1 := Byte (lByteBuffer);
Result := 1;
end;
else
Result := 0;
end;
end;

procedure Base64Encode(InputFile, OutputFile: string);
var
Ms: TMemoryStream;
Ss: TStringStream;
Str: string;
List: TStringList;
begin {Base64 encode}
Ms := TMemoryStream.Create;
try
Ms.LoadFromFile(InputFile);
Ss := TStringStream.Create(Str);
try
MimeEncodeStream(Ms, Ss);
List := TStringList.Create;
try
List.Text := Ss.DataString;
List.SaveToFile(OutputFile);
finally
List.Free;
end;
finally
Ss.Free;
end;
finally
Ms.Free;
end;
end;

procedure Base64Decode(InputFile, OutputFile: string);
var
Ms: TMemoryStream;
Ss: TStringStream;
List: TStringList;
begin {Base64 decode}
List := TStringList.Create;
try
List.LoadFromFile(InputFile);
Ss := TStringStream.Create(List.Text);
try
Ms := TMemoryStream.Create;
try
MimeDecodeStream(Ss, Ms);
Ms.SaveToFile(OutputFile);
finally
Ms.Free;
end;
finally
Ss.Free;
end;
finally
List.Free;
end;
end;

end.

相关文章推荐

彻底解决delphi Indy10接收邮件汉字显示乱码的问题

使用indy组件接收邮件时,遇到汉字大多显示为乱码,网上很多询问同类型的问题。这几天做一个邮件客户端的小项目,研究了一下Indy10的代码,发现有办法根本解决这个问题,感觉牵涉的知识点挺多的,在这里讲...

Delphi的Indy通信中发送流文件的注意事项

 客户端发送流到服务器端有几种方式,这里讨论两种:  1.客户端连接到服务器后,发送一个流,服务器接收一个流。{*-------------------------------------------...
  • bbok11
  • bbok11
  • 2009年05月27日 19:57
  • 306

使用TCP协议实现文件传输

使用TCP协议实现文件传输。程序会分为服务器端和客户端,首先运行服务器端,监听来自客户端的连接,客户端运行后会通过程序内的服务器端IP地址,向服务器发送连接请求。双方建立请求之后,客户端将所需文件的文...

TCP协议实现文件传输

使用TCP协议实现传输文件     程序分为发送端和接收端。首先在传输文件数据之前,发送端会把将装有文件名称和文件长度等 信息的数据包发送至接收端。接收端收到文件名称和文件长度信息后会创建好空白文...

在QT中使用TCP协议进行文件传输(可以单向循环传输)

大致步骤如下: 1、服务器端设置监听套接字,开始监听; 2、客户端在连接成功时开始传送文件,有connected()信号连接send()槽,send()发送文件头信息,包括文件名、文件总大小和文件...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用INDY TCP组件实现基于协议采用XML方式的文件传输
举报原因:
原因补充:

(最多只允许输入30个字)