Sock.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:44k
- unit Sock;
- // *****************************************************************************
- // Sock.Pas (TSock)
- // Freeware Windows Socket Component For Delphi & C++ Builder
- // Version 1.0k, tested with Delphi 2.0, 3.0 & 4.0
- // Written By Tom Bradford
- // Maintained By Ward van Wanrooij
- // (ward@ward.nu, http://www.ward.nu)
- //
- // Copyright (C) 1997-2000, Beach Dog Software, Inc.
- // Copyright (C) 2000-2003, Ward van Wanrooij
- // All Rights Reserved
- // Latest version can be obtained at http://www.ward.nu/computer/tsock
- // *****************************************************************************
- interface
- uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- WinSock, BaseClass;
- type
- TSocketInfo = (siLookUp, siConnect, siClose, siListen, siReceive, siSend,
- siAccept, siError);
- TSocketType = (stStream, stDatagram);
- TLineBreak = (lbCRLF, lbCR, lbLF, lbSmart);
- const
- WM_SOCK = WM_USER + 75; // Hopefully, Your App Won't Use This Message
- type
- TSock = class; // Forward Declared For Event Types
- ESockException = class(Exception);
- TNotifyReadEvent = procedure(Sender: TObject; Count: Integer) of object;
- TNotifyAutoEvent = procedure(Sender: TObject; NewSock: TSock) of object;
- TNotifyInfoEvent = procedure(sender: TObject; SocketInfo: TSocketInfo; Msg:
- string) of object;
- TSock = class(TCustomControl)
- private
- FSockAddrIn: TSockAddrIn; // Address Information Block
- FRecvAddrIn: TSockAddrIn; // Address Information Block For RecvFrom
- FLastChar: Char; // Last Character Read For Line-Input
- FPicture: TBitmap; // Holder For Design-Time Image
- FBmp_TCP: TBitmap; // TCP Bitmap
- FBmp_UDP: TBitmap; // UDP Bitmap
- FBmp_Listen: TBitmap; // Listening Bitmap
- // Character Buffer (Most WINSOCK.DLLs Max At 32k)
- // FCharBuf : Array[1..32768] Of Char;
- FCharBuf: array[1..750] of Char; // small buffer works more stable
- FSocketType: TSocketType; // Socket Type (Stream Or Datagram)
- FLineBreak: TLineBreak; // Line Break Style For Line Input
- FHostName: string; // Host Name Or IP Address
- FPortName: string; // Port Name Or Well-Known Number
- FLocalPortName: string;
- // Local Port Name Or Well-Known Number, Defaults To 1 (=FPortName) For Backward Compatibility
- FSocket: TSocket; // Socket Handle
- FInBuffer: string; // Input Buffer
- FOutBuffer: string; // Output Buffer For Non-Blocking
- FListen: Boolean; // Socket Listens?
- FBlocking: Boolean; // Do Blocking Calls?
- FAutoAccept: Boolean; // Automatically Accept Incomings
- FConnected: Boolean; // Are We Connected?
- FBlockTime: Integer; // How Long To Wait For Blocking Operation
- FStream: TStream; // Associated TSockStream Object
- FFreeOnClose: Boolean;
- // Free after closure of socket? (Non-blocking, auto-accepted sockets!)
- FOnConnect: TNotifyEvent;
- FOnDisconnect: TNotifyEvent;
- FOnInfo: TNotifyInfoEvent;
- FOnRead: TNotifyReadEvent;
- FOnWrite: TNotifyEvent;
- FOnAccept: TNotifyEvent;
- FOnAutoAccept: TNotifyAutoEvent;
- m_receiveForm: TForm;
- m_lock: TBCCritSec;
- // Property Set/Get Routines
- procedure SetHostName(Value: string);
- procedure SetPortName(Value: string);
- procedure SetLocalPortName(Value: string);
- function GetText: string;
- procedure SetText(Value: string);
- procedure SetListen(Value: Boolean);
- procedure SetBlocking(Value: Boolean);
- procedure SetAutoAccept(Value: Boolean);
- procedure SetConnected(Value: Boolean);
- function GetConnected: Boolean;
- procedure SetSocket(Value: TSocket);
- procedure SetSocketType(Value: TSocketType);
- function GetRemoteHost: string;
- function GetEOF: Boolean;
- // Private Support Methods
- procedure DoInfo(SocketInfo: TSocketInfo; Msg: string);
- procedure SetBitmap;
- protected
- // Event Handlers
- procedure WMSock(var Message: TMessage); message WM_SOCK;
- procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
- procedure WMSize(var Message: TWMSize); message WM_SIZE;
- // Loaded Handles Starting Listening Mode After Streaming The Properties
- procedure Loaded; override;
- // Protected Constructor Can Only Be Called By TSock Class
- constructor CreateWithSocket(AOwner: TComponent; NewSocket: TSocket);
- virtual;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- function Open: Boolean;
- function Close: Boolean;
- function Send(Value: string): Boolean;
- function SendLine(Value: string): Boolean;
- function ReceiveCount(Count: Integer): string;
- function Receive: string;
- function ReceiveLine: string;
- function SendDatagram(Value, HostName: string): Boolean;
- function ReceiveDatagram(var HostName: string): string;
- // The Accept Method Will Create NewSock, But User Must Free
- function Accept(var NewSock: TSock): Boolean;
- // Public Support Methods
- function HostLookup(Value: string): TInAddr;
- function PortLookup(Value: string): U_Short;
- // StartListen And StopListen Are A Robust Form Of Setting Listen
- function StartListen: Boolean;
- function StopListen: Boolean;
- property Text: string read GetText write SetText;
- property Connected: Boolean read GetConnected write SetConnected;
- // Used To Read FConnected
- property EndOfFile: Boolean read GetEOF;
- property Socket: TSocket read FSocket write SetSocket;
- property Stream: TStream read FStream;
- // RemoteHost Returns The Remote IP If SocketType=stStream
- // And Will Return The Most Recent Incoming Datagram IP If
- // SocketType=stDatagram
- property RemoteHost: string read GetRemoteHost;
- // RemoteHost = INet_NToA(RecvAddrIn.SIn_Addr); Provided as property for easy-of-use and backward compatibility
- property RecvAddrIn: TSockAddrIn read FRecvAddrIn;
- published
- property SocketType: TSocketType read FSocketType write SetSocketType;
- property HostName: string read FHostName write SetHostName;
- property PortName: string read FPortName write SetPortName;
- property LocalPortName: string read FLocalPortName write SetLocalPortName;
- property Blocking: Boolean read FBlocking write SetBlocking;
- property AutoAccept: Boolean read FAutoAccept write SetAutoAccept;
- property Listen: Boolean read FListen write SetListen;
- property LineBreak: TLineBreak read FLineBreak write FLineBreak;
- property BlockingTimeout: Integer read FBlockTime write FBlockTime;
- property OnConnect: TNotifyEvent read FOnConnect write FOnConnect;
- property OnDisconnect: TNotifyEvent read FOnDisconnect write FOnDisconnect;
- property OnInfo: TNotifyInfoEvent read FOnInfo write FOnInfo;
- property OnRead: TNotifyReadEvent read FOnRead write FOnRead;
- property OnWrite: TNotifyEvent read FOnWrite write FOnWrite;
- property OnAccept: TNotifyEvent read FOnAccept write FOnAccept;
- property OnAutoAccept: TNotifyAutoEvent read FOnAutoAccept write
- FOnAutoAccept;
- end;
- // Global IP Caching Mechanism. Uses A String List That Stores The 32-Bit IP
- // Address Of It's Associated Hostname In The Object Property Of The List. You
- // Should Never Have To Manipulate This Object Directly, But It Is Made Public
- // For The Purpose Of Calling The Clear Method To Empty It.
- var
- IPCache: TStringList;
- function WSDescription: string; // Returns A Description Of The WinSock Driver
- function WSSystemStatus: string; // Returns System Status From The WinSock Driver
- function GetLocalHostname: string; // Return Local Hostname
- function SocketInfoText(Value: TSocketInfo): string;
- // Converts TSocketInfo Values To Text
- function ErrToStr(Value: Integer): string; // Converts A WinSock Error To Text
- function Base64Encode(Value: string): string;
- // Converts Passed Value To MIME Base64
- function Base64Decode(Value: string): string;
- // Converts Passed Value From MIME Base64
- function URLEncode(Value: string): string;
- // Converts String To A URLEncoded String
- function URLDecode(Value: string): string;
- // Converts String From A URLEncoded String
- procedure Register;
- implementation
- uses config;
- const
- Base64Table =
- 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
- ValidURLChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$-_@.&+-!*"''(),;/#?:';
- SocketInfoMsg: array[siLookUp..siError] of string = ('Lookup', 'Connect',
- 'Close', 'Listen', 'Receive', 'Send', 'Accept', 'Error');
- type
- TSockStream = class(TStream)
- private
- Sock: TSock;
- public
- function Read(var Buffer; Count: Longint): Longint; override;
- function Write(const Buffer; Count: Longint): Longint; override;
- function Seek(Offset: Longint; Origin: Word): Longint; override;
- constructor Create(Sock: TSock); virtual;
- end;
- type
- TSockThread = class(TThread)
- private
- ParentSock: TSock;
- ClientSock: TSock;
- public
- procedure Execute; override;
- procedure ThreadTerminate(Sender: TObject);
- procedure RunThread(ParentSock, ClientSock: TSock);
- end;
- // WinSock Initialization Data
- var
- WSAData: TWSAData;
- //*** TSockStream Methods ******************************************************
- constructor TSockStream.Create(Sock: TSock);
- begin
- Self.Sock := Sock;
- end;
- function TSockStream.Read(var Buffer; Count: Longint): Longint;
- var
- Temp: string;
- begin
- Temp := Sock.ReceiveCount(Count);
- Move(Temp[1], Buffer, Length(Temp));
- Result := Length(Temp);
- end;
- function TSockStream.Write(const Buffer; Count: Longint): Longint;
- var
- Temp: string;
- begin
- SetLength(Temp, Count);
- Move(Buffer, Temp[1], Count);
- Sock.Send(Temp);
- Result := Count;
- end;
- function TSockStream.Seek(Offset: Longint; Origin: Word): Longint;
- begin
- Result := 0;
- end;
- //*** TSockThread Methods ******************************************************
- procedure TSockThread.Execute;
- begin
- FreeOnTerminate := True;
- OnTerminate := ThreadTerminate;
- ParentSock.OnAutoAccept(ParentSock, ClientSock);
- Terminate;
- end;
- procedure TSockThread.ThreadTerminate(Sender: TObject);
- begin
- ClientSock.Free;
- end;
- procedure TSockThread.RunThread(ParentSock, ClientSock: TSock);
- begin
- Self.ParentSock := ParentSock;
- Self.ClientSock := ClientSock;
- Resume;
- end;
- //*** Property Set/Get Procedures **********************************************
- procedure TSock.SetHostName(Value: string);
- begin
- if (FSocketType = stStream) and FConnected then
- DoInfo(SiLookup, 'Setting HostName While Connected Has No Effect');
- FHostName := Value;
- if (FSocketType = stDatagram) and FConnected then
- FSockAddrIn.SIn_Addr := HostLookup(Value);
- end;
- procedure TSock.SetPortName(Value: string);
- begin
- if FConnected then
- DoInfo(SiLookup, 'Setting PortName While Connected Has No Effect');
- FPortName := Value;
- end;
- procedure TSock.SetLocalPortName(Value: string);
- begin
- if FConnected then
- DoInfo(SiLookup, 'Setting LocalPortName While Connected Has No Effect');
- FLocalPortName := Value;
- end;
- function TSock.GetText: string;
- begin
- // Just Call The Receive Method
- Result := Receive;
- end;
- procedure TSock.SetText(Value: string);
- begin
- // Just Call The Send Method And Ignore The Boolean Result
- Send(Value);
- end;
- procedure TSock.SetListen(Value: Boolean);
- var
- WasListen: Boolean;
- Addr: TSockAddr;
- Res: Integer;
- begin
- if (csDesigning in ComponentState) then
- begin
- FListen := Value;
- if Value and (FSocketType = stDatagram) then
- // Listening Sockets Must Be Stream Sockets
- SetSocketType(stStream)
- else
- SetBitmap;
- Exit;
- end
- else if (csReading in ComponentState) then
- begin
- // If We Haven't Loaded Yet, Just Set The Value And Exit
- FListen := Value;
- Exit;
- end;
- WasListen := FListen;
- if (FSocket <> INVALID_SOCKET) and (not WasListen) then
- begin
- FListen := False;
- raise ESockException.Create('Listen - Socket Already In Use');
- end;
- if (FSocketType = stDatagram) and Value then
- begin
- FListen := False;
- raise ESockException.Create('Listen - Cannot Listen On A Datagram Socket');
- end;
- FListen := Value;
- if FListen then
- begin
- if not WasListen then
- begin
- // Have To Create A Socket Start Asynchronous Listening
- FListen := True;
- FSocket := WinSock.Socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
- FillChar(Addr, SizeOf(Addr), #0);
- Addr.SIn_Family := AF_INET;
- Addr.SIn_Port := PortLookup(FPortName);
- Addr.SIn_Addr.S_Addr := HToNL(INADDR_ANY);
- // SetBlocking Will Set The Asynchronous Mode
- SetBlocking(FBlocking);
- FListen := False;
- Res := WinSock.Bind(FSocket, Addr, SizeOf(Addr));
- if Res <> 0 then
- raise ESockException.Create('Listen - Error Binding Socket');
- Res := WinSock.Listen(FSocket, 5);
- if Res <> 0 then
- raise ESockException.Create('Listen - Error Starting Listen');
- FListen := True;
- DoInfo(SiListen, 'Listening Started');
- end
- else
- DoInfo(SiListen, 'Listening Already Running');
- end
- else
- begin
- Close;
- DoInfo(SiListen, 'Listening Stopped');
- end;
- end;
- procedure TSock.SetBlocking(Value: Boolean);
- var
- Il: U_Long;
- Ev: U_Long;
- begin
- if (not (csDesigning in ComponentState)) and (csReading in ComponentState)
- then
- begin
- // If We Haven't Fully Loaded Yet, Just Set The Value And Exit
- FBlocking := Value;
- Exit;
- end;
- if FSocket = INVALID_SOCKET then
- FBlocking := Value
- else
- begin
- Ev := 0;
- FBlocking := Value;
- if (Parent = nil) then
- begin
- // If The Component Has No Parent (Dynamically Created) We Adopt It
- Parent := Screen.Forms[0];
- HandleNeeded;
- end;
- if FBlocking and (not FListen) then
- begin
- Il := 0;
- // Turn Off Async Checking And Set Blocking On
- WinSock.WSAAsyncSelect(FSocket, Handle, WM_SOCK, Ev);
- WinSock.IOCtlSocket(FSocket, FIONBIO, Il);
- end
- else
- begin
- if FListen then
- // If We're Listening, We Only Care About Accept Messages
- Ev := FD_ACCEPT
- else
- begin
- Ev := FD_READ; // Datagram Sockets Only Care About Read Messages
- if FSocketType = stStream then
- Ev := Ev or FD_CLOSE or FD_CONNECT or FD_WRITE or FD_READ;
- end;
- WinSock.WSAAsyncSelect(FSocket, Handle, WM_SOCK, Ev);
- end;
- end;
- end;
- procedure TSock.SetAutoAccept(Value: Boolean);
- begin
- FAutoAccept := Value;
- end;
- procedure TSock.SetConnected(Value: Boolean);
- begin
- if Value then
- Open
- else
- Close;
- end;
- function TSock.GetConnected: Boolean;
- begin
- if FSocket = INVALID_SOCKET then
- FConnected := False;
- Result := FConnected;
- end;
- function TSock.GetEOF: Boolean;
- begin
- Result := (FInBuffer = '') and (not FConnected);
- end;
- procedure TSock.SetSocket(Value: TSocket);
- var
- Buf: array[1..10] of Char;
- Len: Integer;
- Res: Integer;
- begin
- FSocket := Value;
- if FSocket = INVALID_SOCKET then
- begin
- // If The Socket Is Unassigned Then Who Cares
- FConnected := False;
- FListen := False;
- end
- else
- begin
- // Otherwise, We Need To Check To See If It's Already Listening
- Len := SizeOf(Buf);
- Res := WinSock.GetSockOpt(FSocket, IPPROTO_TCP, SO_ACCEPTCONN, PChar(@Buf),
- Len);
- if (Res = 0) and (Buf[1] <> #0) then
- begin
- FSocket := INVALID_SOCKET;
- raise ESockException.Create('Socket - Can''t Assign A Listening Socket');
- end
- else
- FConnected := True;
- end;
- end;
- procedure TSock.SetSocketType(Value: TSocketType);
- begin
- if csDesigning in ComponentState then
- begin
- // At Design-Time, stDatagram And Listen Are Mutually Exclusive
- if (Value = stDatagram) and FListen then
- SetListen(False);
- FSocketType := Value;
- SetBitmap;
- end
- else
- begin
- if FListen then
- raise
- ESockException.Create('SocketType - Can''t Assign Socket Type While Listening');
- if FConnected then
- raise
- ESockException.Create('SocketType - Can''t Assign Socket Type While Connected');
- FSocketType := Value;
- end
- end;
- function TSock.GetRemoteHost: string;
- begin
- // Convert FRecvAddrIn To A String IP Address
- Result := INet_NToA(FRecvAddrIn.SIn_Addr);
- end;
- procedure TSock.DoInfo(SocketInfo: TSocketInfo; Msg: string);
- begin
- if Assigned(FOnInfo) then
- FOnInfo(Self, SocketInfo, Msg);
- end;
- procedure TSock.SetBitmap;
- begin
- // Determine The Design-Time Bitmap To Use
- if FSocketType = stDatagram then
- FPicture := FBmp_UDP
- else if FListen then
- FPicture := FBmp_Listen
- else
- FPicture := FBmp_TCP;
- Invalidate;
- end;
- //*** Constructor/Destructor ***************************************************
- constructor TSock.Create(AOwner: TComponent);
- begin
- m_receiveForm := TForm.Create(nil);
- inherited Create(m_receiveForm);
- m_lock := TBCCritSec.Create;
- Parent := TWinControl(m_receiveForm);
- // <<--- added by blacktrip, wild cast but
- // prevent crashes !!!
- if WinSock.WSAStartup($0101, WSAData) <> 0 then
- raise ESockException.Create('WSAStartup - Could Not Initialize WinSock');
- IPCache := TStringList.Create;
- IPCache.Clear;
- if (csDesigning in ComponentState) then
- begin
- // Get Bitmaps For Design-Time Image
- FBmp_TCP := TBitmap.Create;
- FBmp_UDP := TBitmap.Create;
- FBmp_Listen := TBitmap.Create;
- FBmp_TCP.Handle := LoadBitmap(hInstance, 'TCP');
- FBmp_UDP.Handle := LoadBitmap(hInstance, 'UDP');
- FBmp_Listen.Handle := LoadBitmap(hInstance, 'LISTEN');
- FPicture := FBmp_TCP;
- Width := FPicture.Width;
- Height := FPicture.Height;
- SetZOrder(True);
- end
- else
- begin
- Width := 0;
- Height := 0;
- SetZOrder(False);
- Visible := False;
- end;
- FHostName := '';
- FPortName := '';
- FLocalPortName := '-1';
- FSocket := INVALID_SOCKET;
- FLineBreak := lbSmart;
- FLastChar := #0;
- FInBuffer := '';
- FOutBuffer := '';
- FListen := False;
- FBlocking := False;
- FAutoAccept := False;
- FConnected := False;
- FStream := TSockStream.Create(Self);
- FFreeOnClose := False;
- end;
- // This Constructor Assumes NewSocket Is A Valid Socket Handle
- constructor TSock.CreateWithSocket(AOwner: TComponent; NewSocket: TSocket);
- begin
- Create(AOwner);
- FSocket := NewSocket;
- SetBlocking(TSock(AOwner).Blocking);
- FBlockTime := TSock(AOwner).BlockingTimeout;
- FOnRead := TSock(AOwner).OnRead;
- FOnWrite := TSock(AOwner).OnWrite;
- FOnDisconnect := TSock(AOwner).OnDisconnect;
- FOnInfo := TSock(AOwner).OnInfo;
- FConnected := True;
- FLineBreak := TSock(AOwner).LineBreak;
- FRecvAddrIn := TSock(AOwner).RecvAddrIn;
- FFreeOnClose := not FBlocking;
- end;
- destructor TSock.Destroy;
- begin
- if FListen or FConnected then
- Close;
- if (csDesigning in ComponentState) then
- begin
- FBmp_TCP.Free;
- FBmp_UDP.Free;
- FBmp_Listen.Free;
- end;
- FStream.Free;
- IPCache.Free;
- WinSock.WSACleanup;
- inherited Destroy;
- end;
- procedure TSock.Loaded;
- begin
- if not (csDesigning in ComponentState) then
- begin
- // If Component Has Been Loaded At Run-Time And Listen Then Start Listening
- SetBlocking(FBlocking);
- if FListen then
- begin
- FListen := False;
- SetListen(True);
- end;
- end;
- end;
- //*** Event Handling ***********************************************************
- procedure TSock.WMSock(var Message: TMessage);
- var
- Event: Word;
- Error: Word;
- Res: Integer;
- AcSck: TSocket;
- Addr: TSockAddrIn;
- AddrL: Integer;
- CSock: TSock;
- Spawn: TSockThread;
- begin
- m_lock.Lock;
- inherited;
- // Message Handling For Non-Blocking Sockets
- Event := WinSock.WSAGetSelectEvent(Message.LParam);
- Error := WinSock.WSAGetSelectError(Message.LParam);
- if (Error > WSABASEERR) then
- DoInfo(SiError, 'Error #' + IntToStr(Error) + ' (' + ErrToStr(Error) + ')');
- if (Error <= WSABASEERR) or (Event = FD_CLOSE) then
- // Messages Mean Different Things Depending On Whether You're Listening Or Not
- case Event of
- FD_ACCEPT:
- begin
- // Incoming Socket
- if FAutoAccept and Assigned(FOnAutoAccept) then
- begin
- // If AutoAccept Is Set To True And OnAutoAccept Is Set...
- // Create A New Socket Based On The Accepted One And Begin
- // AutoAccept As If It Were A Thread... The AutoAccept
- // Routine Is Responsible For Destroying The New Socket
- // Component.
- AddrL := SizeOf(Addr);
- FillChar(Addr, SizeOf(Addr), #0);
- {$IFDEF VER93}
- AcSck := WinSock.Accept(FSocket, Addr, AddrL);
- {$ELSE}
- {$IFDEF WIN32}
- AcSck := WinSock.Accept(FSocket, @Addr, @AddrL);
- {$ELSE}
- AcSck := WinSock.Accept(FSocket, Addr, AddrL);
- {$ENDIF}
- {$ENDIF}
- FRecvAddrIn := Addr;
- CSock := TSock.CreateWithSocket(Self, AcSck);
- CSock.PortName := FPortName;
- CSock.LocalPortName := FLocalPortName;
- CSock.HostName := INet_NToA(Addr.SIn_Addr);
- if FBlocking then
- begin
- Spawn := TSockThread.Create(True);
- Spawn.RunThread(Self, CSock);
- end
- else
- FOnAutoAccept(Self, CSock);
- end
- else if Assigned(FOnAccept) then
- FOnAccept(Self);
- end;
- FD_CONNECT:
- begin
- FConnected := True;
- DoInfo(SiConnect, 'Non-Blocking Socket Connected');
- if Assigned(FOnConnect) then
- FOnConnect(Self);
- end;
- FD_CLOSE:
- begin
- if Assigned(FOnDisconnect) then
- FOnDisconnect(Self);
- Close;
- end;
- FD_READ:
- begin
- if FSocketType = stStream then
- begin
- Res := WinSock.Recv(FSocket, FCharBuf, SizeOf(FCharBuf), 0);
- if Res > 0 then
- FInBuffer := FInBuffer + Copy(FCharBuf, 1, Res);
- DoInfo(SiReceive, 'Non-Blocking Incoming Data');
- if Assigned(FOnRead) then
- begin
- FOnRead(Self, Length(FInBuffer));
- end;
- end
- else if Assigned(FOnRead) then
- FOnRead(Self, Length(FInBuffer));
- end;
- FD_WRITE:
- begin
- if FOutBuffer <> '' then
- Send('');
- DoInfo(SiSend, 'Non-Blocking Outgoing Data');
- if Assigned(FOnWrite) then
- FOnWrite(Self);
- end;
- end;
- Message.Result := 0;
- m_lock.UnLock;
- end;
- procedure TSock.WMPaint(var Message: TWMPaint);
- begin
- inherited;
- if (csDesigning in ComponentState) then
- Canvas.Draw(0, 0, FPicture);
- Message.Result := 0;
- end;
- procedure TSock.WMSize(var Message: TWMSize);
- begin
- inherited;
- if (csDesigning in ComponentState) then
- begin
- if Width <> FPicture.Width then
- Width := FPicture.Width;
- if Height <> FPicture.Height then
- Height := FPicture.Height;
- end;
- Message.Result := 0;
- end;
- //*** Support Methods **********************************************************
- function TSock.Open: Boolean;
- var
- Res: Integer;
- ST: Integer;
- LAddrIn: TSockAddrIn;
- //optval: integer;
- begin
- if FSocket = INVALID_SOCKET then
- begin
- if FSocketType = stStream then
- ST := SOCK_STREAM
- else
- ST := SOCK_DGRAM;
- // Create The Socket
- FSocket := WinSock.Socket(AF_INET, ST, IPPROTO_IP);
- SetBlocking(FBlocking);
- // Set local options
- LAddrIn.SIn_Family := AF_INET;
- if FLocalPortName = '-1' then
- LAddrIn.SIn_Port := PortLookup(FPortName)
- // Default behaviour for backward compatibility
- else
- LAddrIn.SIn_Port := PortLookup(FLocalPortName);
- LAddrIn.SIn_Addr.S_Addr := HToNL(INADDR_ANY);
- // No HostLookup(...) Because INADDR_ANY Is A Windows Constant
- // Set Up The Remote Address And Port
- FSockAddrIn.SIn_Family := AF_INET;
- FSockAddrIn.SIn_Port := PortLookup(FPortName);
- FSockAddrIn.SIn_Addr := HostLookup(FHostName);
- if FSocketType = stStream then
- begin
- // Stream Sockets Require A Connect
- Res := WinSock.Bind(FSocket, LAddrIn, SizeOf(LAddrIn)) +
- WinSock.Connect(FSocket, FSockAddrIn, SizeOf(TSockAddrIn));
- if FBlocking then
- begin
- if Res = 0 then
- begin
- FConnected := True;
- DoInfo(SiConnect, 'Blocking Socket Connected');
- if Assigned(FOnConnect) then
- FOnConnect(Self);
- end
- else
- begin
- DoInfo(SiClose, 'Blocking Socket Can''t Connect');
- Close;
- end;
- end;
- end
- else
- begin
- //Datagram Sockets are connectionless, so they don't get connected.
- //It is possible to call WinSock.Connect, but it would produce extra overhead
- //as it only sets the default destination.
- Res := WinSock.Bind(FSocket, LAddrIn, SizeOf(LAddrIn));
- if Res = 0 then
- begin
- FConnected := True;
- DoInfo(SiConnect, 'Datagram Socket Connected');
- if Assigned(FOnConnect) then
- FOnConnect(Self);
- end
- else
- begin
- DoInfo(SiClose, 'Datagram Socket Can''t Connect');
- Close;
- end;
- end;
- end;
- Result := FConnected;
- end;
- function TSock.Close: Boolean;
- begin
- Result := (WinSock.CloseSocket(FSocket) = 0);
- FSocket := INVALID_SOCKET;
- FConnected := False;
- if not FListen then
- DoInfo(SiClose, 'Socket Closed');
- FListen := False;
- if FFreeOnClose then
- Free;
- end;
- function TSock.Send(Value: string): Boolean;
- var
- Remain: Integer;
- begin
- Result := True;
- if FSocket = INVALID_SOCKET then
- raise ESockException.Create('Send - Socket Not Connected');
- if FListen then
- raise ESockException.Create('Send - Cannot Send On A Listener Socket');
- if FSocketType = stStream then
- begin
- FOutBuffer := FOutBuffer + Value;
- if FOutBuffer = '' then
- Exit;
- if FBlocking then
- begin
- Remain := Length(FOutBuffer);
- // While Any Content Remains Or No Errors Have Happened, Then Loop
- while Remain > 0 do
- begin
- Remain := WinSock.Send(FSocket, FOutBuffer[1], Length(FOutBuffer), 0);
- if (Remain = SOCKET_ERROR) and (WinSock.WSAGetLastError <>
- WSAEINPROGRESS) then
- begin
- DoInfo(SiError, 'Socket Error On Send');
- raise ESockException.Create('Send - Socket Error');
- end
- else
- begin
- if Remain > 0 then
- Delete(FOutBuffer, 1, Remain);
- Remain := Length(FOutBuffer);
- DoInfo(SiSend, 'Blocking Outgoing Data');
- end;
- end;
- FOutBuffer := '';
- end
- else
- begin
- // Do Not Loop For A Non-Blocking Socket
- DoInfo(SiSend, 'Non-Blocking Outgoing Data');
- Remain := WinSock.Send(FSocket, FOutBuffer[1], Length(FOutBuffer), 0);
- if Remain > 0 then
- Delete(FOutBuffer, 1, Remain);
- end;
- end
- else
- SendDatagram(Value, FHostName);
- end;
- function TSock.SendLine(Value: string): Boolean;
- var
- Break: string;
- begin
- case FLineBreak of
- lbCR: Break := #13;
- lbLF: Break := #10;
- else
- Break := #13#10;
- end;
- Result := Send(Value + Break);
- end;
- function TSock.Receive: string;
- begin
- Result := ReceiveCount(-1);
- end;
- function TSock.ReceiveCount(Count: Integer): string;
- var
- Res: Integer;
- FDSet: PFDSet;
- TV: PTimeVal;
- Err: Integer;
- HostN: string;
- Cnt: Integer;
- begin
- if (FSocket = INVALID_SOCKET) and (FInBuffer = '') then
- raise ESockException.Create('Receive - Socket Not Connected');
- if FListen then
- raise
- ESockException.Create('Receive - Cannot Receive On A Listener Socket');
- Cnt := Count;
- if (Cnt = -1) or (Cnt > SizeOf(FCharBuf)) then
- Cnt := SizeOf(FCharBuf);
- if FSocketType = stStream then
- begin
- if FBlocking then
- begin
- FDSet := New(PFDSet);
- FDSet^.FD_Count := 1;
- FDSet^.FD_Array[0] := FSocket;
- if FBlockTime >= 0 then
- begin
- TV := New(PTimeVal);
- TV^.tv_sec := FBlockTime;
- end
- else
- TV := nil;
- // Used To Loop While We're Connected And Anything Is In The Input Queue
- if FConnected and (WinSock.Select(FSocket, FDSet, nil, nil, TV) > 0) then
- begin
- DoInfo(SiReceive, 'Blocking Incoming Data');
- Res := WinSock.Recv(FSocket, FCharBuf, Cnt, 0);
- if (Res = SOCKET_ERROR) then
- begin
- Err := WSAGetLastError;
- Result := '';
- FInBuffer := '';
- Dispose(FDSet);
- Dispose(TV);
- DoInfo(SiError, 'Socket Error On Receive');
- if (not (Err - WSABASEERR in [WSAEINTR - WSABASEERR, WSAEINPROGRESS -
- WSABASEERR, WSAEOPNOTSUPP - WSABASEERR, WSAEWOULDBLOCK - WSABASEERR,
- WSAEMSGSIZE - WSABASEERR])) then
- begin
- DoInfo(siClose, 'Socket Disconnected On Error On Receive');
- Close;
- if Assigned(FOnDisconnect) then
- FOnDisconnect(Self);
- end;
- raise ESockException.Create('Receive - Socket Error ' +
- ErrToStr(Err));
- end
- else
- begin
- if Res > 0 then
- FInBuffer := FInBuffer + Copy(FCharBuf, 1, Res)
- else if Res = 0 then
- begin
- DoInfo(siClose, 'Socket Disconnected On Receive');
- Close;
- if Assigned(FOnDisconnect) then
- FOnDisconnect(Self);
- end;
- end;
- end;
- Result := FInBuffer;
- FInBuffer := '';
- Dispose(FDSet);
- Dispose(TV);
- end
- else
- begin
- if ((Count <> -1) and (Length(FInBuffer) > Count)) then
- begin
- Result := Copy(FInBuffer, 1, Count);
- Delete(FInBuffer, 1, Count);
- end
- else
- begin
- Result := FInBuffer;
- FInBuffer := '';
- end;
- end;
- end
- else
- Result := ReceiveDatagram(HostN);
- end;
- function TSock.ReceiveLine: string;
- var
- CPos, CLen: LongInt;
- Temp: string;
- begin
- CPos := 0;
- Result := '';
- if FSocketType = stStream then
- begin
- if (FBlocking and FConnected) then
- begin
- Temp := FInBuffer;
- FInBuffer := '';
- Temp := Temp + Receive;
- FInBuffer := Temp;
- end;
- if (FLastChar = #13) and (FLineBreak = lbSmart) and (FInBuffer[1] = #10)
- then
- begin
- Delete(FInBuffer, 1, 1);
- FLastChar := #0;
- end;
- case FLineBreak of
- lbCR: CPos := Pos(#13, FInBuffer);
- lbLF: CPos := Pos(#10, FInBuffer);
- lbCRLF: CPos := Pos(#13#10, FInBuffer);
- lbSmart:
- begin
- CPos := Pos(#13, FInBuffer);
- if (CPos = 0) or (Pos(#10, FInBuffer) < CPos) then
- CPos := Pos(#10, FInBuffer);
- if CPos > 0 then
- FLastChar := FInBuffer[CPos]
- else
- FLastChar := #0;
- end;
- end;
- if FLineBreak = lbCRLF then
- CLen := 2
- else
- CLen := 1;
- if (CPos > 0) or (not FConnected) then
- begin
- if CPos > 0 then
- begin
- Result := Copy(FInBuffer, 1, CPos - 1);
- Delete(FInBuffer, 1, CPos + (CLen - 1));
- end
- else
- begin
- Result := FInBuffer;
- FInBuffer := '';
- end;
- end;
- end
- else
- Result := Receive;
- end;
- function TSock.SendDatagram(Value, HostName: string): Boolean;
- begin
- if FSocket = INVALID_SOCKET then
- raise ESockException.Create('SendDatagram - Socket Not Connected');
- if FSocketType = stStream then
- raise
- ESockException.Create('SendDatagram - Datagram Send Not Supported On Stream Sockets');
- Result := True;
- SetHostName(HostName);
- if Value = '' then
- Exit;
- WinSock.SendTo(FSocket, Value[1], Length(Value), 0, FSockAddrIn,
- SizeOf(TSockAddrIn));
- end;
- function TSock.ReceiveDatagram(var HostName: string): string;
- var
- Res: Integer;
- FDSet: PFDSet;
- TV: PTimeVal;
- FLen: Integer;
- begin
- if FSocket = INVALID_SOCKET then
- raise ESockException.Create('ReceiveDatagram - Socket Not Connected');
- if FSocketType = stStream then
- raise
- ESockException.Create('ReceiveDatagram - Datagram Receive Not Supported On Stream Sockets');
- FDSet := New(PFDSet);
- FDSet^.FD_Count := 1;
- FDSet^.FD_Array[0] := FSocket;
- Result := '';
- HostName := '';
- if FBlockTime >= 0 then
- begin
- TV := New(PTimeVal);
- TV^.tv_sec := FBlockTime;
- end
- else
- TV := nil;
- if WinSock.Select(FSocket, FDSet, nil, nil, TV) > 0 then
- begin
- FLen := Sizeof(FRecvAddrIn);
- Res := WinSock.RecvFrom(FSocket, FCharBuf, SizeOf(FCharBuf), 0, FRecvAddrIn,
- FLen);
- if Res > 0 then
- begin
- Result := Copy(FCharBuf, 1, Res);
- HostName := GetRemoteHost;
- end
- else
- raise ESockException.Create('Socket Error while Receiving Datagram:' +
- IntToStr(WSAGetLastError));
- end;
- Dispose(FDSet);
- Dispose(TV);
- end;
- function TSock.Accept(var NewSock: TSock): Boolean;
- var
- AcSck: TSocket;
- AddrL: Integer;
- Addr: TSockAddrIn;
- begin
- // Accept Creates A New Instance Of A TSock Component And Returns It To The
- // User Application. The User Is Responsible For Freeing The Component.
- if not FListen then
- raise ESockException.Create('Accept - Socket Not In Listening Mode');
- if FBlocking then
- DoInfo(SiAccept, 'Blocking Accept');
- AddrL := SizeOf(Addr);
- {$IFDEF VER93}
- AcSck := WinSock.Accept(FSocket, Addr, AddrL);
- {$ELSE}
- {$IFDEF WIN32}
- AcSck := WinSock.Accept(FSocket, @Addr, @AddrL);
- {$ELSE}
- AcSck := WinSock.Accept(FSocket, Addr, AddrL);
- {$ENDIF}
- {$ENDIF}
- FRecvAddrIn := Addr;
- if AcSck <> INVALID_SOCKET then
- begin
- NewSock := TSock.CreateWithSocket(Self, AcSck);
- NewSock.PortName := FPortName;
- NewSock.LocalPortName := FLocalPortName;
- NewSock.HostName := INet_NToA(Addr.SIn_Addr);
- Result := True;
- DoInfo(SiAccept, 'Created New TSock Structure');
- end
- else
- begin
- Result := False;
- DoInfo(SiAccept, 'Could Not Accept Connection');
- end;
- end;
- function TSock.HostLookup(Value: string): TInAddr;
- type
- PLongInt = ^LongInt;
- var
- PHost: PHostEnt;
- Res, I: Integer;
- AllNumeric: Boolean;
- begin
- if Value = '' then
- Exit;
- DoInfo(SiLookUp, 'Lookup Of Host ' + Value);
- FillChar(Result, SizeOf(TInAddr), #0);
- AllNumeric := True;
- for I := 1 to Length(Value) do
- if not (Value[I] in ['0'..'9', '.']) then
- begin
- AllNumeric := False;
- Break;
- end;
- if AllNumeric then
- Result := TInAddr(WinSock.Inet_Addr(PChar(Value)))
- // If It's Dot-Notation, Just Convert It From An IP Address
- else
- begin
- Res := IPCache.IndexOf(Value);
- if Res >= 0 then
- // It's Cached... Don't Bother Doing A Lookup
- Result.S_Addr := U_Long(IPCache.Objects[Res])
- else
- begin
- // Isn't Cached, Have To Do A GetHostByName
- if Value <> '' then
- begin
- PHost := WinSock.GetHostByName(PChar(Value));
- if PHost <> nil then
- begin
- Result.S_Addr := LongInt(PLongInt(PHost^.H_Addr_List^)^);
- IPCache.AddObject(Value, Pointer(Result.S_Addr));
- end
- else
- begin
- // If Assigned(FOnInfo) then // added by coder@dsplayer.de
- // FOnInfo(self,siError,'Host Lookup - Could Not Find Host Entry');
- //Raise ESockException.Create('Host Lookup - Could Not Find Host Entry');
- end;
- end
- else
- Result.S_Addr := HToNL(INADDR_ANY);
- end;
- end;
- end;
- function TSock.PortLookup(Value: string): U_Short;
- var
- PEnt: PServEnt;
- Prot: string;
- begin
- DoInfo(SiLookUp, 'Lookup Of Port ' + Value);
- if Pos(Value[1], '0123456789') > 0 then
- // It's Numeric, Just Convert It To A Network Byte Order Integer
- Result := HToNS(StrToInt(Value))
- else
- begin
- // Otherwise, Perform A GetServByName Based On The Protocol
- if FSocketType = stStream then
- Prot := 'tcp'
- else
- Prot := 'udp';
- PEnt := WinSock.GetServByName(PChar(Value), PChar(Prot));
- if PEnt <> nil then
- Result := PEnt^.S_Port
- else
- raise ESockException.Create('Port Lookup - Could Not Find Service Entry');
- end;
- end;
- function TSock.StartListen: Boolean;
- begin
- SetListen(True);
- Result := FListen;
- end;
- function TSock.StopListen: Boolean;
- begin
- Result := True;
- SetListen(False);
- end;
- //*** Additional General-Purpose Support Functions *****************************
- function WSDescription: string;
- begin
- Result := StrPas(WSAData.szDescription);
- end;
- function WSSystemStatus: string;
- begin
- Result := StrPas(WSAData.szSystemStatus);
- end;
- function GetLocalHostname: string;
- var
- CharHostname: array[0..255] of Char;
- begin
- Result := 'localhost';
- if WinSock.GetHostname(CharHostname, SizeOf(CharHostname)) = 0 then
- Result := CharHostname
- else
- raise
- ESockException.Create('GetLocalHostname - Could Not Retrieve Hostname');
- end;
- function SocketInfoText(Value: TSocketInfo): string;
- begin
- Result := SocketInfoMsg[Value];
- end;
- function ErrToStr(Value: Integer): string;
- begin
- Result := 'UNKNOWN ERROR';
- case Value of
- WSABASEERR + 4: Result := 'WSAEINTR';
- WSABASEERR + 9: Result := 'WSAEBADF';
- WSABASEERR + 13: Result := 'WSAEACCES';
- WSABASEERR + 14: Result := 'WSAEFAULT';
- WSABASEERR + 22: Result := 'WSAEINVAL';
- WSABASEERR + 24: Result := 'WSAEMFILE';
- WSABASEERR + 35: Result := 'WSAEWOULDBLOCK';
- WSABASEERR + 36: Result := 'WSAEINPROGRESS';
- WSABASEERR + 37: Result := 'WSAEALREADY';
- WSABASEERR + 38: Result := 'WSAENOTSOCK';
- WSABASEERR + 39: Result := 'WSAEDESTADDRREQ';
- WSABASEERR + 40: Result := 'WSAEMSGSIZE';
- WSABASEERR + 41: Result := 'WSAEPROTOTYPE';
- WSABASEERR + 42: Result := 'WSAENOPROTOOPT';
- WSABASEERR + 43: Result := 'WSAEPROTONOSUPPORT';
- WSABASEERR + 44: Result := 'WSAESOCKTNOSUPPORT';
- WSABASEERR + 45: Result := 'WSAEOPNOTSUPP';
- WSABASEERR + 46: Result := 'WSAEPFNOSUPPORT';
- WSABASEERR + 47: Result := 'WSAEAFNOSUPPORT';
- WSABASEERR + 48: Result := 'WSAEADDRINUSE';
- WSABASEERR + 49: Result := 'WSAEADDRNOTAVAIL';
- WSABASEERR + 50: Result := 'WSAENETDOWN';
- WSABASEERR + 51: Result := 'WSAENETUNREACH';
- WSABASEERR + 52: Result := 'WSAENETRESET';
- WSABASEERR + 53: Result := 'WSAECONNABORTED';
- WSABASEERR + 54: Result := 'WSAECONNRESET';
- WSABASEERR + 55: Result := 'WSAENOBUFS';
- WSABASEERR + 56: Result := 'WSAEISCONN';
- WSABASEERR + 57: Result := 'WSAENOTCONN';
- WSABASEERR + 58: Result := 'WSAESHUTDOWN';
- WSABASEERR + 59: Result := 'WSAETOOMANYREFS';
- WSABASEERR + 60: Result := 'WSAETIMEDOUT';
- WSABASEERR + 61: Result := 'WSAECONNREFUSED';
- WSABASEERR + 62: Result := 'WSAELOOP';
- WSABASEERR + 63: Result := 'WSAENAMETOOLONG';
- WSABASEERR + 64: Result := 'WSAEHOSTDOWN';
- WSABASEERR + 65: Result := 'WSAEHOSTUNREACH';
- WSABASEERR + 66: Result := 'WSAENOTEMPTY';
- WSABASEERR + 67: Result := 'WSAEPROCLIM';
- WSABASEERR + 68: Result := 'WSAEUSERS';
- WSABASEERR + 69: Result := 'WSAEDQUOT';
- WSABASEERR + 70: Result := 'WSAESTALE';
- WSABASEERR + 71: Result := 'WSAEREMOTE';
- WSABASEERR + 91: Result := 'WSASYSNOTREADY';
- WSABASEERR + 92: Result := 'WSAVERNOTSUPPORTED';
- WSABASEERR + 93: Result := 'WSANOTINITIALISED';
- WSABASEERR + 101: Result := 'WSAEDISCON';
- WSABASEERR + 1001: Result := 'WSAHOST_NOT_FOUND';
- WSABASEERR + 1002: Result := 'WSATRY_AGAIN';
- WSABASEERR + 1003: Result := 'WSANO_RECOVERY';
- WSABASEERR + 1004: Result := 'WSANO_DATA';
- end;
- end;
- // Base-64 Encoding Is The Process Of Taking An Input Stream And Converting
- // Every 3 Bytes Into 4 Bytes, Each Of Which Whose ASCII Value Fits Within
- // A 64-Bit Range. Base-64 Is Often Used For Encoding Binary Streams For
- // Attaching To Email, But Is Perfect For Converting Binary To A Character
- // Set That Can Be Used For URL-Encoding. The Base-64 Character Set Does Not
- // Include Characters That URLs Use For Delimiting Such As '=', '&', Carriage
- // Returns, Etc...
- function Base64Encode(Value: string): string;
- var
- AIn: array[1..3] of Byte;
- AOut: array[1..4] of Byte;
- AWork: array[1..3] of Byte;
- I: Integer;
- O: LongInt;
- begin
- Result := '';
- I := 1;
- O := Length(Value);
- case Length(Value) mod 3 of
- 1: Value := Value + #0 + #0;
- 2: Value := Value + #0;
- end;
- while I < Length(Value) do
- begin
- AIn[1] := Byte(Value[I]);
- AIn[2] := Byte(Value[I + 1]);
- AIn[3] := Byte(Value[I + 2]);
- AOut[1] := Byte(AIn[1] shr 2);
- AWork[1] := Byte(AIn[1] shl 4);
- AWork[2] := Byte(AWork[1] and $30);
- AWork[3] := Byte(AIn[2] shr 4);
- AOut[2] := Byte(AWork[2] or AWork[3]);
- AWork[1] := Byte(AIn[2] shl 2);
- AWork[2] := Byte(AWork[1] and $3C);
- AWork[3] := Byte(AIn[3] shr 6);
- AOut[3] := Byte(AWork[2] or AWork[3]);
- AOut[4] := Byte(AIn[3] and $3F);
- Inc(I, 3);
- Result := Result + Base64Table[AOut[1] + 1] + Base64Table[AOut[2] + 1] +
- Base64Table[AOut[3] + 1] + Base64Table[AOut[4] + 1];
- end;
- if O mod 3 > 0 then
- Result[Length(Result)] := '=';
- if O mod 3 = 1 then
- Result[Length(Result) - 1] := '=';
- end;
- function Base64Decode(Value: string): string;
- var
- AIn: array[1..4] of Byte;
- AOut: array[1..3] of Byte;
- AWork: array[1..3] of Byte;
- I: Integer;
- C: Integer;
- begin
- Result := '';
- I := 1;
- while I < Length(Value) do
- begin
- C := 3;
- FillChar(AWork, SizeOf(AWork), #0);
- FillChar(AOut, SizeOf(AWork), #0);
- AIn[1] := Byte(Pos(Value[I], Base64Table) - 1);
- AIn[2] := Byte(Pos(Value[I + 1], Base64Table) - 1);
- AIn[3] := Byte(Pos(Value[I + 2], Base64Table) - 1);
- AIn[4] := Byte(Pos(Value[I + 3], Base64Table) - 1);
- if Value[I + 3] = '=' then
- begin
- C := 2;
- AIn[4] := 0;
- if Value[I + 2] = '=' then
- begin
- C := 1;
- AIn[3] := 0;
- end;
- end;
- AWork[2] := Byte(AIn[1] shl 2);
- AWork[3] := Byte(AIn[2] shr 4);
- AOut[1] := Byte(AWork[2] or AWork[3]);
- AWork[2] := Byte(AIn[2] shl 4);
- AWork[3] := Byte(AIn[3] shr 2);
- AOut[2] := Byte(AWork[2] or AWork[3]);
- AWork[2] := Byte(AIn[3] shl 6);
- AOut[3] := Byte(AWork[2] or AIn[4]);
- Result := Result + Char(AOut[1]);
- if C > 1 then
- Result := Result + Char(AOut[2]);
- if C > 2 then
- Result := Result + Char(AOut[3]);
- Inc(I, 4);
- end;
- end;
- // This function converts a string into a RFC 1630 compliant URL,
- // provided that the string does not contain illegal characters at illegal
- // places, for example this URL is invalid because of the ! sign in the password:
- // ftp://ward:pass!word@ftp.ward.nu/my_documents/ward@mymail?
- function URLEncode(Value: string): string;
- var
- I: Integer;
- begin
- Result := '';
- for I := 1 to Length(Value) do
- begin
- if Pos(UpperCase(Value[I]), ValidURLChars) > 0 then
- Result := Result + Value[I]
- else
- begin
- if Value[I] = ' ' then
- Result := Result + '+'
- else
- begin
- Result := Result + '%';
- Result := Result + IntToHex(Byte(Value[I]), 2);
- end;
- end;
- end;
- end;
- function URLDecode(Value: string): string;
- const
- HexChars = '0123456789ABCDEF';
- var
- I: Integer;
- Ch, H1, H2: Char;
- begin
- Result := '';
- I := 1;
- while I <= Length(Value) do
- begin
- Ch := Value[I];
- case Ch of
- '%':
- begin
- H1 := Value[I + 1];
- H2 := Value[I + 2];
- Inc(I, 2);
- Result := Result + Chr(((Pos(H1, HexChars) - 1) * 16) + (Pos(H2,
- HexChars) - 1));
- end;
- '+': Result := Result + ' ';
- '&': Result := Result + #13 + #10;
- else
- Result := Result + Ch;
- end;
- Inc(I);
- end;
- end;
- //*** Registration And Initialization ******************************************
- procedure Register;
- begin
- RegisterComponents('Ward', [TSock]);
- end;
- initialization // (moved to create)
- // We're Looking To Use Version 1.1 Of WinSock Here
- { If WinSock.WSAStartup($0101, WSAData) <> 0 Then
- Raise ESockException.Create('WSAStartup - Could Not Initialize WinSock');
- IPCache := TStringList.Create;
- IPCache.Clear; }
- finalization // moved to destroy
- { IPCache.Free;
- WinSock.WSACleanup; }
- end.