sdlweb.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. unit sdlweb;
  2. {******************************************************************************}
  3. {
  4. $Id: sdlweb.pas,v 1.2 2005/01/02 19:03:15 savage Exp $
  5. }
  6. { }
  7. { Borland Delphi SDL_Net - A x-platform network library for use with SDL.}
  8. { Conversion of the Simple DirectMedia Layer Network Headers }
  9. { }
  10. { Portions created by Sam Lantinga <[email protected]> are }
  11. { Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga }
  12. { 5635-34 Springhouse Dr. }
  13. { Pleasanton, CA 94588 (USA) }
  14. { }
  15. { All Rights Reserved. }
  16. { }
  17. { The original files are : SDL_net.h }
  18. { }
  19. { The initial developer of this Pascal code was : }
  20. { Dean Ellis <[email protected]> }
  21. { }
  22. { Portions created by Dean Ellis are }
  23. { Copyright (C) 2000 - 2001 Dean Ellis. }
  24. { }
  25. { }
  26. { Contributor(s) }
  27. { -------------- }
  28. { }
  29. { }
  30. { Obtained through: }
  31. { Joint Endeavour of Delphi Innovators ( Project JEDI ) }
  32. { }
  33. { You may retrieve the latest version of this file at the Project }
  34. { JEDI home page, located at http://delphi-jedi.org }
  35. { }
  36. { The contents of this file are used with permission, subject to }
  37. { the Mozilla Public License Version 1.1 (the "License"); you may }
  38. { not use this file except in compliance with the License. You may }
  39. { obtain a copy of the License at }
  40. { http://www.mozilla.org/MPL/MPL-1.1.html }
  41. { }
  42. { Software distributed under the License is distributed on an }
  43. { "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or }
  44. { implied. See the License for the specific language governing }
  45. { rights and limitations under the License. }
  46. { }
  47. { Description }
  48. { ----------- }
  49. { }
  50. { }
  51. { }
  52. { }
  53. { }
  54. { }
  55. { }
  56. { Requires }
  57. { -------- }
  58. { sdl.pas and sdl_net.pas somehere in your search path }
  59. { }
  60. { Programming Notes }
  61. { ----------------- }
  62. { }
  63. { }
  64. { }
  65. { }
  66. { Revision History }
  67. { ---------------- }
  68. {
  69. $Log: sdlweb.pas,v $
  70. Revision 1.2 2005/01/02 19:03:15 savage
  71. Slight Bug fix due to stray closed comment ( Thanks Michalis Kamburelis )
  72. Revision 1.1 2004/12/31 00:30:12 savage
  73. Initial release of Dean's excellent SDL Web classes. Demo coming soon.
  74. }
  75. {******************************************************************************}
  76. interface
  77. uses
  78. SysUtils,
  79. sdl,
  80. sdl_net;
  81. const
  82. MAX_TIMEOUT = 5000;
  83. type
  84. TWebConnection = ( wcDefault, wcHTTP, wcFTP );
  85. TWebProgressEvent = procedure( Progress, Total : UInt32 ); cdecl;
  86. TSDLWebConnection = record
  87. Host : TIPAddress;
  88. HostName, Proxy : string;
  89. Port : UInt32;
  90. Socket : PTCPSocket;
  91. Type_ : TWebConnection;
  92. IsProxy : Boolean;
  93. ProxyUser, ProxyPassword : string;
  94. end;
  95. procedure SDLWeb_Init;
  96. procedure SDLWeb_Quit;
  97. // Connection Functions
  98. function SDLWeb_ConnectToSite( URL : string; AType : TWebConnection;
  99. var Connection : TSDLWebConnection ) : Boolean;
  100. function SDLWeb_ConnectToSiteViaProxy( URL, Proxy, Username, Password : string; AType : TWebConnection;
  101. var Connection : TSDLWebConnection ) : Boolean;
  102. function SDLWeb_Connected( var Connection : TSDLWebConnection ) : Boolean;
  103. procedure SDLWeb_Disconnect( var Connection : TSDLWebConnection );
  104. function SDLWeb_SendRequest( var Connection : TSDLWebConnection;
  105. Request : string ) : Boolean;
  106. function SDLWeb_ReadResponse( var Connection : TSDLWebConnection;
  107. var Response : string ) : UInt32;
  108. // Utility Functions
  109. function SDLWeb_IPToString( ip : TIPAddress ) : string;
  110. function SDLWeb_StringToIP( ip : string ) : TIPAddress;
  111. function SDLWeb_Pos( const SubString, Source : string; Count : SInt32 ) : SInt32;
  112. procedure SDLWeb_ParseURL( const url : string; var proto, user, pass, host, port, path : string );
  113. function SDLWeb_EncodeBase64( Value : string ) : string;
  114. function SDLWeb_DecodeBase64( Value : string ) : string;
  115. implementation
  116. const
  117. DefaultPorts : array[ TWebConnection ] of UInt32 = ( 80, 80, 21 );
  118. procedure SDLWeb_Init;
  119. begin
  120. SDLNet_Init;
  121. end;
  122. procedure SDLWeb_Quit;
  123. begin
  124. SDLNet_Quit;
  125. end;
  126. function SDLWeb_ConnectToSite( URL : string; AType : TWebConnection;
  127. var Connection : TSDLWebConnection ) : Boolean;
  128. var
  129. Protocol, User, Password, Host, Port, Path : string;
  130. begin
  131. Result := False;
  132. SDLWeb_ParseURL( URL, Protocol, User, Password, Host, Port, Path );
  133. Connection.IsProxy := False;
  134. Connection.HostName := Host;
  135. if SDLNet_ResolveHost( Connection.Host, PChar( Host ), DefaultPorts[ AType ] ) = 0 then
  136. begin
  137. Connection.Socket := SDLNet_TCP_Open( Connection.Host );
  138. Connection.Port := DefaultPorts[ AType ];
  139. if AType = wcDefault then
  140. begin
  141. if UpperCase( Protocol ) = 'HTTP' then
  142. Connection.Type_ := wcHTTP;
  143. if UpperCase( Protocol ) = 'FTP' then
  144. Connection.Type_ := wcFTP;
  145. end
  146. else
  147. Connection.Type_ := AType;
  148. Result := SDLWeb_Connected( Connection );
  149. end;
  150. end;
  151. function SDLWeb_ConnectToSiteViaProxy( URL, Proxy, Username, Password : string; AType : TWebConnection;
  152. var Connection : TSDLWebConnection ) : Boolean;
  153. begin
  154. Result := SDLWeb_ConnectToSite( Proxy, AType, Connection );
  155. if Result then
  156. begin
  157. Connection.Proxy := Proxy;
  158. Connection.HostName := URL;
  159. Connection.ProxyUser := Username;
  160. Connection.ProxyPassword := Password;
  161. Connection.IsProxy := True;
  162. end;
  163. end;
  164. function SDLWeb_Connected( var Connection : TSDLWebConnection ) : Boolean;
  165. begin
  166. Result := Connection.Socket <> nil;
  167. end;
  168. procedure SDLWeb_Disconnect( var Connection : TSDLWebConnection );
  169. begin
  170. SDLNet_TCP_Close( Connection.Socket );
  171. Connection.Socket := nil;
  172. end;
  173. function SDLWeb_SendRequest( var Connection : TSDLWebConnection;
  174. Request : string ) : Boolean;
  175. var
  176. Error, Len : UInt32;
  177. cdata : array[ 0..255 ] of char;
  178. begin
  179. StrPCopy( cdata, Request + #13#10 );
  180. Len := StrLen( cdata );
  181. Error := SDLNet_TCP_Send( Connection.Socket, @cdata, Len );
  182. Result := Error = Len;
  183. end;
  184. function SDLWeb_ReadResponse( var Connection : TSDLWebConnection;
  185. var Response : string ) : UInt32;
  186. var
  187. SocketSet : PSDLNet_SocketSet;
  188. function ReadLine : string;
  189. var
  190. Done : Boolean;
  191. C : Char;
  192. Error, SocketResult : Sint32;
  193. begin
  194. Result := EmptyStr;
  195. Done := False;
  196. SDLNet_TCP_AddSocket( SocketSet, Connection.Socket );
  197. while not Done do
  198. begin
  199. SocketResult := SDLNet_CheckSockets( SocketSet, MAX_TIMEOUT );
  200. if ( SocketResult <= 0 ) then
  201. begin
  202. Result := 'HTTP/1.1 400 Socket Timeout';
  203. Exit;
  204. end;
  205. if SDLNet_SocketReady( PSDLNet_GenericSocket( Connection.Socket ) ) then
  206. begin
  207. Error := SDLNet_TCP_Recv( Connection.Socket, @C, 1 );
  208. Done := ( Error < 1 );
  209. if C = #13 then
  210. else if C = #10 then
  211. Done := True
  212. else
  213. Result := Result + C;
  214. end;
  215. end;
  216. end;
  217. begin
  218. SocketSet := SDLNet_AllocSocketSet( 1 );
  219. try
  220. Response := ReadLine;
  221. Result := Length( Response );
  222. finally
  223. SDLNet_FreeSocketSet( SocketSet );
  224. end;
  225. end;
  226. function SDLWeb_IPToString( ip : TIPAddress ) : string;
  227. var
  228. IpAddress : UInt32;
  229. begin
  230. IpAddress := SDL_Swap32( ip.host );
  231. // output the IP address nicely
  232. Result := format( '%d.%d.%d.%d', [ IpAddress shr 24, ( IpAddress shr 16 ) and $000000FF,
  233. ( IpAddress shr 8 ) and $000000FF, IpAddress and $000000FF ] );
  234. end;
  235. function SDLWeb_StringToIP( ip : string ) : TIPAddress;
  236. begin
  237. SDLNet_ResolveHost( Result, PChar( ip ), 0 );
  238. end;
  239. function SDLWeb_Pos( const SubString, Source : string; Count : SInt32 ) : SInt32;
  240. var
  241. i, h, last : integer;
  242. u : string;
  243. begin
  244. u := Source;
  245. if count > 0 then
  246. begin
  247. result := length( Source );
  248. for i := 1 to count do
  249. begin
  250. h := pos( SubString, u );
  251. if h > 0 then
  252. u := copy( u, pos( SubString, u ) + 1, length( u ) )
  253. else
  254. begin
  255. u := '';
  256. inc( result );
  257. end;
  258. end;
  259. result := result - length( u );
  260. end
  261. else if count < 0 then
  262. begin
  263. last := 0;
  264. for i := length( Source ) downto 1 do
  265. begin
  266. u := copy( Source, i, length( Source ) );
  267. h := pos( SubString, u );
  268. if ( h <> 0 ) and ( h + i <> last ) then
  269. begin
  270. last := h + i - 1;
  271. inc( count );
  272. if count = 0 then
  273. BREAK;
  274. end;
  275. end;
  276. if count = 0 then
  277. result := last
  278. else
  279. result := 0;
  280. end
  281. else
  282. result := 0;
  283. end;
  284. procedure SDLWeb_ParseURL( const url : string; var proto, user, pass, host, port, path : string );
  285. var
  286. p, p2 : integer;
  287. s : string;
  288. begin
  289. host := '';
  290. path := '';
  291. proto := 'http';
  292. port := '80';
  293. p := Pos( '://', url );
  294. if p > 0 then
  295. begin
  296. // get protocol
  297. proto := Copy( url, 1, p - 1 );
  298. inc( p, 2 );
  299. s := copy( url, p + 1, length( url ) );
  300. // get path
  301. p := pos( '/', s );
  302. if p = 0 then
  303. p := length( s ) + 1;
  304. path := copy( s, p, length( s ) );
  305. s := copy( s, 1, p - 1 );
  306. // get host
  307. p := pos( ':', s );
  308. if p > Length( s ) then
  309. p := 0;
  310. p2 := SDLWeb_Pos( '@', s, -1 );
  311. if p2 > length( s ) then
  312. p2 := 0;
  313. if ( p = 0 ) and ( p2 = 0 ) then
  314. begin (* no user, password or port *)
  315. host := s;
  316. exit;
  317. end
  318. else if p2 < p then
  319. begin (* a port given *)
  320. port := copy( s, p + 1, length( s ) );
  321. host := copy( s, p2 + 1, p - p2 - 1 );
  322. if p2 = 0 then
  323. exit; (* no user, password *)
  324. s := copy( s, 1, p2 - 1 );
  325. end
  326. else
  327. begin
  328. host := copy( s, p2 + 1, length( s ) );
  329. s := copy( s, 1, p2 - 1 );
  330. end;
  331. p := pos( ':', s );
  332. if p = 0 then
  333. user := s
  334. else
  335. begin
  336. user := copy( s, 1, p - 1 );
  337. pass := copy( s, p + 1, length( s ) );
  338. end;
  339. end;
  340. end;
  341. function SDLWeb_EncodeBase64( Value : string ) : string;
  342. var
  343. Position, Total, Remaining : Integer;
  344. InBlock : array[ 0..2 ] of Byte;
  345. OutBlock : array[ 0..3 ] of Char;
  346. const
  347. Base64Chars : array[ 0..63 ] of Char = ( 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
  348. 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
  349. 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
  350. 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
  351. '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' );
  352. begin
  353. Result := '';
  354. Total := Length( Value );
  355. Position := 1;
  356. while True do
  357. begin
  358. Remaining := Total - Position + 1;
  359. if Remaining <= 0 then
  360. Break;
  361. FillChar( InBlock, SizeOf( InBlock ), #0 );
  362. InBlock[ 0 ] := Ord( Value[ Position + 0 ] );
  363. if Remaining >= 2 then
  364. InBlock[ 1 ] := Ord( Value[ Position + 1 ] );
  365. if Remaining >= 3 then
  366. InBlock[ 2 ] := Ord( Value[ Position + 2 ] );
  367. Inc( Position, 3 );
  368. FillChar( OutBlock, SizeOf( OutBlock ), '=' );
  369. OutBlock[ 0 ] := Base64Chars[ ( InBlock[ 0 ] and $FC ) shr 2 ];
  370. OutBlock[ 1 ] := Base64Chars[ ( ( InBlock[ 0 ] and $03 ) shl 4 ) or
  371. ( ( InBlock[ 1 ] and $F0 ) shr 4 ) ];
  372. if Remaining >= 2 then
  373. OutBlock[ 2 ] := Base64Chars[ ( ( InBlock[ 1 ] and $0F ) shl 2 ) or
  374. ( ( InBlock[ 2 ] and $C0 ) shr 6 ) ];
  375. if Remaining >= 3 then
  376. OutBlock[ 3 ] := Base64Chars[ InBlock[ 2 ] and $3F ];
  377. Result := Result + OutBlock;
  378. end;
  379. end;
  380. function SDLWeb_DecodeBase64( Value : string ) : string;
  381. var
  382. Position, Total, Remaining : Integer;
  383. InBlock : array[ 0..3 ] of Byte;
  384. OutBlock : array[ 0..2 ] of Char;
  385. function Base64Ord( Value : Char ) : Byte;
  386. const
  387. BASE64_FIRST_UPPER = 0;
  388. BASE64_FIRST_LOWER = 26;
  389. BASE64_FIRST_NUMBER = 52;
  390. BASE64_PLUS = 62;
  391. BASE64_SLASH = 63;
  392. begin
  393. if ( Ord( Value ) >= Ord( 'A' ) ) and ( Ord( Value ) <= Ord( 'Z' ) ) then
  394. Result := Ord( Value ) - Ord( 'A' ) + BASE64_FIRST_UPPER
  395. else if ( Ord( Value ) >= Ord( 'a' ) ) and ( Ord( Value ) <= Ord( 'z' ) ) then
  396. Result := Ord( Value ) - Ord( 'a' ) + BASE64_FIRST_LOWER
  397. else if ( Ord( Value ) >= Ord( '0' ) ) and ( Ord( Value ) <= Ord( '9' ) ) then
  398. Result := Ord( Value ) - Ord( '0' ) + BASE64_FIRST_NUMBER
  399. else if Ord( Value ) = Ord( '+' ) then
  400. Result := BASE64_PLUS
  401. else if Ord( Value ) = Ord( '/' ) then
  402. Result := BASE64_SLASH
  403. else
  404. Result := 0;
  405. end;
  406. begin
  407. Result := '';
  408. Total := Length( Value );
  409. Position := 1;
  410. while True do
  411. begin
  412. Remaining := Total - Position + 1;
  413. if Remaining <= 0 then
  414. Break;
  415. FillChar( InBlock, SizeOf( InBlock ), #0 );
  416. InBlock[ 0 ] := Base64Ord( Value[ Position + 0 ] );
  417. if Remaining >= 2 then
  418. InBlock[ 1 ] := Base64Ord( Value[ Position + 1 ] );
  419. if Remaining >= 3 then
  420. InBlock[ 2 ] := Base64Ord( Value[ Position + 2 ] );
  421. if Remaining >= 4 then
  422. InBlock[ 3 ] := Base64Ord( Value[ Position + 3 ] );
  423. Inc( Position, 4 );
  424. OutBlock[ 0 ] := Chr( ( ( InBlock[ 0 ] and $3F ) shl 2 ) or
  425. ( ( InBlock[ 1 ] and $30 ) shr 4 ) );
  426. OutBlock[ 1 ] := Chr( ( ( InBlock[ 1 ] and $0F ) shl 4 ) or
  427. ( ( InBlock[ 2 ] and $3C ) shr 2 ) );
  428. OutBlock[ 2 ] := Chr( ( ( InBlock[ 2 ] and $03 ) shl 6 ) or
  429. ( InBlock[ 3 ] and $3F ) );
  430. Result := Result + OutBlock;
  431. end;
  432. end;
  433. end.