home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2000 January / PCW0001.ISO / software / sw / outils / xitami.exe / STDCGI.BAS < prev    next >
Encoding:
BASIC Source File  |  1998-11-12  |  24.4 KB  |  566 lines

  1. Attribute VB_Name = "StdCGI_Framework"
  2. '====================================================================
  3. '           CGI WorkerMan for Visual Basic
  4. '====================================================================
  5. ' Author : Wei-dun Teng <tiberius@ms28.hinet.net>
  6. ' Version: 1.4 Release (November 12, 1998)
  7. ' Please report any comments or bugs to my E-Mail box, thanks.
  8. '--------------------------------------------------------------------
  9. ' Common routines needed to establish a VB environment for
  10. ' Standard CGI programs that run behind the web server.
  11. '--------------------------------------------------------------------
  12. ' The Common Gateway Interface (CGI) version 1.1 specifies
  13. ' a minial set of data that is made available to the back-
  14. ' end application by an HTTP (Web) server. It also specifies
  15. ' the details for passing this information to the back-end.
  16. ' The latter part of the CGI spec is specific to Unix-like
  17. ' environments. The NCSA httpd for Windows does supply the
  18. ' data items (and more) specified by CGI/1.1. This module uses
  19. ' WinAPIs to parse datas from your server by STDIN/STDOUT.
  20. '--------------------------------------------------------------------
  21. ' This module is based on Robert B. Denny's CGI32.BAS
  22. '--------------------------------------------------------------------
  23. ' USAGE: Include CGI32.BAS in your VB project. Set the
  24. ' project options for "Sub Main" startup. The Main() procedure
  25. ' is in this module, and it handles all of the setup of the
  26. ' VB CGI environment. Once all of this is done, the Main()
  27. ' calls YOUR main procedure which must be called CGI_Main().
  28. ' The output file is open, use Send() to write to it. The
  29. ' input file is NOT open, notice that. If this module doesn't
  30. ' detected any server is running, it will show a message box
  31. ' and then quit immediately. If you want to call another
  32. ' subroutine when server is not running, just take a look at
  33. ' Main() subroutine.
  34. '---------------------------------------------------------------------
  35. ' Future plans on this module:
  36. ' -> Cookie array/dictionary support
  37. ' -> Something works like ASP Session object
  38. '---------------------------------------------------------------------
  39. Option Explicit
  40. Option Compare Text
  41.  
  42. '=============================
  43. ' Standard Input/Output Stuff
  44. '=============================
  45. Const STD_INPUT_HANDLE& = -10
  46. Const STD_OUTPUT_HANDLE& = -11
  47. Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long
  48. Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, ByVal lpOverlapped As Long) As Long
  49. Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, ByVal lpOverlapped As Long) As Long
  50.  
  51. '====================
  52. ' Manifest Constants
  53. '====================
  54. Public Const MAX_FORM_TUPLES% = 255
  55. Public Const MAX_FORM_COOKIES% = 255
  56. Public Const DONT_ENCODE$ = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-*"
  57.  
  58. '=======
  59. ' Types
  60. '=======
  61. Type Tuple
  62.     Key As String
  63.     Value As String
  64. End Type
  65.  
  66. '============================
  67. '    CGI Global Variables
  68. '============================
  69. ' These values are explained
  70. ' in InitializeCGI section.
  71. '----------------------------
  72. Public ServerSoftware$
  73. Public ServerName$
  74. Public ServerPort%
  75. Public RequestProtocol$
  76. Public ServerAdmin$
  77. Public CGIVersion$
  78. Public RequestMethod$
  79. Public VirtualPath$
  80. Public LogicalPath$
  81. Public CGIProgramFile$
  82. Public CGIProgramPath$
  83. Public CGIProgramUrl$
  84. Public QueryString$
  85. Public CookieString$
  86. Public PostString$
  87. Public From$
  88. Public UserAgent$
  89. Public ContentType$
  90. Public ContentLength$
  91. Public AcceptTypes$
  92. Public DocumentRoot$
  93.  
  94. '================
  95. ' POST Form Data
  96. '================
  97. Public FormTuples(MAX_FORM_TUPLES) As Tuple
  98. Public FormCookies(MAX_FORM_COOKIES) As Tuple
  99. Public NumFormTuples As Integer
  100. Public NumFormCookies As Integer
  101.  
  102. '==================
  103. ' System Variables
  104. '==================
  105. Public GMTOffset As Variant
  106. Public STDIN As Long               ' STDIN Handler
  107. Public STDOUT As Long              ' STDOUT Handler
  108. Public rc As Long                  ' WinAPI Return Code
  109. Public ErrorString As String       ' Normal Error Message
  110.  
  111. '-================-
  112. ' STRING CONSTANTS
  113. '-================-
  114. '
  115. ' This section contains a lot of useful strings.
  116. '
  117. '-----------------------
  118. ' HTTP response headers
  119. '-----------------------
  120. Public Const Status200$ = "HTTP/1.0 200 OK" & vbCrLf
  121. Public Const Status204$ = "HTTP/1.0 204 No Content" & vbCrLf
  122. Public Const Status206$ = "HTTP/1.0 206 Partial Content" & vbCrLf
  123. Public Const Status301$ = "HTTP/1.0 301 Moved Permanently" & vbCrLf
  124. Public Const Status302$ = "HTTP/1.0 302 Found" & vbCrLf
  125. Public Const Status303$ = "HTTP/1.0 303 See Other" & vbCrLf
  126. Public Const Status304$ = "HTTP/1.0 304 Not Modified" & vbCrLf
  127. Public Const Status307$ = "HTTP/1.0 307 Temporary Redirect" & vbCrLf
  128. Public Const Status401$ = "HTTP/1.0 401 Unauthorized" & vbCrLf
  129. Public Const Status403$ = "HTTP/1.0 403 Forbidden" & vbCrLf
  130. Public Const Status404$ = "HTTP/1.0 404 Not Found" & vbCrLf
  131. Public Const Status411$ = "HTTP/1.0 411 Length Required" & vbCrLf
  132. Public Const Status416$ = "HTTP/1.0 416 Request Range Not Satisfiable" & vbCrLf
  133. Public Const Status500$ = "HTTP/1.0 500 Internal Server Error" & vbCrLf
  134. Public Const Status503$ = "HTTP/1.0 503 Service Unavailable" & vbCrLf
  135.  
  136. '---------------
  137. ' Content-Types
  138. '---------------
  139. Public Const ContainHTML$ = "Content-type: text/html" & vbCrLf
  140. Public Const ContainPlainText$ = "Content-type: text/plain" & vbCrLf
  141. Public Const ContainJPEGImage$ = "Content-type: image/jpeg" & vbCrLf
  142. Public Const ContainGIFImage$ = "Content-type: image/gif" & vbCrLf
  143. Public Const ContainOctetStream$ = "Content-type: application/octet-stream" & vbCrLf
  144.  
  145. '-=============================-
  146. ' DATA PROCESSING FUNCTIONS 1.5
  147. '-=============================-
  148. '
  149. '---------------------------------------------------------
  150. ' Send - Write a string to output (without CR/LF suffix!)
  151. '---------------------------------------------------------
  152. Sub Send(sInput As String)
  153.     Dim bOutput() As Byte, lStrPos&, lWritten&
  154.     ReDim bOutput(1 To Len(sInput))
  155.     For lStrPos = 1 To Len(sInput)
  156.         bOutput(lStrPos) = Asc(Mid(sInput, lStrPos, 1))
  157.     Next lStrPos
  158.     rc = WriteFile(STDOUT, bOutput(1), UBound(bOutput) - LBound(bOutput) + 1, lWritten, 0)
  159. End Sub
  160.  
  161. '----------------------------------------
  162. ' Param - Get the value of a form field.
  163. '----------------------------------------
  164. Function Param(sKey As String) As String
  165.     Param = TupleValue(sKey, FormTuples)
  166. End Function
  167.  
  168. '-------------------------------------------------
  169. ' ParamExist - Return True/False depending on
  170. '                whether a form field is exist.
  171. '-------------------------------------------------
  172. ' Typically used to detect if a checkbox in a form
  173. ' is checked or not. Unchecked checkboxes are
  174. ' omitted from the form content.
  175. '-------------------------------------------------
  176. Function ParamExist(sKey As String) As Integer
  177.     ParamExist = TupleExist(sKey, FormTuples)
  178. End Function
  179.  
  180. '-------------------------------------------------------------------------------------------
  181. ' SetCookie - Return a cookie header, you MUST send it in header not content area!
  182. '-------------------------------------------------------------------------------------------
  183. ' Usage: Send generated cookie header like this: Call Send(SetCookie(.......))
  184. '-------------------------------------------------------------------------------------------
  185. '   sKey:       Name for this cookie.
  186. '   sValue:     Value for this cookie.
  187. '       You can use Cookie() to read a cookie's value,
  188. '       and use CookieExist() to check whether a cookie is exist (with or without a value).
  189. '   sPath:      Path for which this cookie is valid.
  190. '       CGI programs can't read your cookie outside this path.
  191. '       You can save cookie in the same name but in different path,
  192. '       they will not confilict.
  193. '   sDomain:    Internet domain for which this cookie is valid.
  194. '       The rule for this argument is same as sPath.
  195. '   vExpires:   Expiry date in any valid date format (string, etc.)
  196. '       After this date/time the cookie will automatically deleted
  197. '       If omitted, cookie will deleted when browser closed.
  198. '       It will pre-processed by WebDate() automatically.
  199. '       You can use DateAdd() to calcuate expiry dates.
  200. '   bSecure:    If set to TRUE, cookies only pass through secure
  201. '               channel.
  202. '-------------------------------------------------------------------------------------------
  203. Function SetCookie(sKey As String, Optional sValue As String, Optional sPath As String, Optional sDomain As String, Optional sExpires As String, Optional bSecure As Boolean) As String
  204.     Dim sTemp$, sPair$
  205.     If sPath = "" Then sPath = CGIProgramFile
  206.     If sDomain = "" Then sDomain = ServerName
  207.     If sExpires <> "" Then sExpires = WebDate(CVar(sExpires))
  208.     If sValue = "" Then
  209.         sPair = Encode(sKey)
  210.     Else
  211.         sPair = Encode(sKey) & "=" & Encode(sValue)
  212.     End If
  213.     sTemp = "Set-cookie: " & sPair & "; "
  214.     sTemp = sTemp & "path=" & sPath & "; "
  215.     sTemp = sTemp & "domain=" & sDomain & ";"
  216.     If sExpires <> "" Then sTemp = sTemp & " expires=" & sExpires & ";"
  217.     If bSecure Then sTemp = sTemp & " secure;"
  218.     SetCookie = sTemp
  219. End Function
  220.  
  221. '------------------------------------------
  222. ' Cookie - Get the value of a HTTP cookie.
  223. '------------------------------------------
  224. Function Cookie(sKey As String) As String
  225.     Cookie = TupleValue(sKey, FormCookies)
  226. End Function
  227.  
  228. '-------------------------------------------------
  229. ' CookieExist - Return True/False depending on
  230. '                whether a cookie is exist.
  231. '-------------------------------------------------
  232. Function CookieExist(sKey As String) As Integer
  233.     CookieExist = TupleExist(sKey, FormCookies)
  234. End Function
  235.  
  236. '----------------------------------------------------
  237. ' MapPath - Convert virtual path to logical path
  238. '----------------------------------------------------
  239. ' Inputs:  Virtual Path (like "/cgi-bin")
  240. ' Returns: Converted Path ("D:\Inetpub\WWW\cgi-bin")
  241. '----------------------------------------------------
  242. ' You *MUST* include drive letter and full path in
  243. ' your server's "Document Root" configuration,
  244. ' or you will get an error result.
  245. '----------------------------------------------------
  246. Function MapPath(sPath As String) As String
  247.     Dim lStrPos&
  248.     For lStrPos = 1 To Len(sPath)   ' Convert "/" to "\" in virtual path string
  249.         If Mid$(sPath, lStrPos, 1) = "/" Then Mid$(sPath, lStrPos, 1) = "\"
  250.     Next lStrPos
  251.     If Left$(sPath, 1) = "\" Then
  252.         MapPath = DocumentRoot & sPath
  253.     Else
  254.         MapPath = CGIProgramPath & "\" & sPath
  255.     End If
  256. End Function
  257.  
  258. '--------------------------------------------------------------
  259. ' URLEncode - Convert a string to URL encoded
  260. '--------------------------------------------------------------
  261. ' Inputs:  String you want to encode (such as form URL creating
  262. ' Returns: Encoded text.
  263. '--------------------------------------------------------------
  264. Function URLEncode(sInput As String)
  265.     URLEncode = Encode(sInput)
  266. End Function
  267.  
  268. '---------------------------------------------------
  269. ' URLDecode - Decode a HTTP-encoded string
  270. '---------------------------------------------------
  271. ' Inputs:  String you want to decode
  272. '          (normally this module will automatically
  273. '           decode any needed data.)
  274. ' Returns: Decoded text.
  275. '---------------------------------------------------
  276. Function URLDecode(sInput As String)
  277.     URLDecode = Decode(sInput)
  278. End Function
  279.  
  280. '------------------------------------------------------------------
  281. ' WebDate - Return an HTTP/1.0 compliant date/time string
  282. '------------------------------------------------------------------
  283. ' Inputs:   Any valid date in string or varient (returned by Now())
  284. ' Returns:  Properly formatted HTTP/1.0 date/time in GMT
  285. '------------------------------------------------------------------
  286. Function WebDate(vInput As Variant) As String
  287.     Dim vOutput As Variant
  288.     vInput = CDate(vInput)
  289.     vOutput = CVDate(vInput - CVDate(Val(GMTOffset) / 86400#))
  290.     WebDate = Format$(vOutput, "ddd dd mmm yyyy hh:mm:ss") & " GMT"
  291. End Function
  292.  
  293. '-================-
  294. ' MODULE CORE v1.2
  295. '-================-
  296. '
  297. '-------------------------------------------------
  298. ' Main - CGI script back-end main procedure
  299. '-------------------------------------------------
  300. ' If it detected it's not running under a HTTP
  301. ' server, it will show a message box and exit.
  302. ' If you want a user interface such as
  303. ' configuration program, simply comment the
  304. ' MsgBox call and remove the next line's comment,
  305. ' then write your code in Inter_Main() subroutine.
  306. '-------------------------------------------------
  307. Sub Main()
  308.     Dim lSection&, lLastSect&, lLoop&, bTemp() As Byte
  309.     On Error GoTo ErrorHandler
  310.     If Trim$(Environ("REQUEST_METHOD")) = "" Then       ' Looks like it's not running under a server
  311.         Call MsgBox("This CGI program doesn't have user interface in this mode," & vbCrLf & "Please install it under HTTP server, and run it by your browser.", vbOKOnly, "CGI Workerman Module 1.1c")
  312. '       Inter_Main      ' If it's not running under a HTTP server, then go to GUI mode.
  313.         End
  314.     End If
  315.     InitializeCGI
  316.     CGI_Main
  317.     End
  318. ErrorHandler:
  319.     ErrorString = Err.Description
  320.     ErrorString = ErrorString & " (error #" & Err.Number & ")"
  321.     On Error GoTo 0
  322.     Call ErrorHandler
  323. End Sub
  324.  
  325. '---------------------------------------------------------
  326. ' InitializeCGI - Fill in all of the CGI variables, etc.
  327. '---------------------------------------------------------
  328. ' NOTE: Check the environments, and modify it to fit
  329. ' the server you used. Current config is setted to run in
  330. ' Xitami Web Server v2.3b or later.
  331. ' PLEASE ENSURE THE I/O FILE ENVIRONMENTS ARE RIGHT FIRST!
  332. '---------------------------------------------------------
  333. Private Sub InitializeCGI()
  334.     Dim lStrPos&, bPostData() As Byte, lReaded&, lCharPos&
  335.     ServerSoftware = Environ("SERVER_SOFTWARE")   ' Server Software's name
  336.     ServerName = Environ("SERVER_NAME")           ' Server's Host Name
  337.     RequestProtocol = Environ("SERVER_PROTOCOL")  ' Used connection protocol
  338. '   ServerAdmin = Environ("SERVER_ADMIN")         ' Server Administrator's e-mail
  339.     ServerAdmin = "tiberius@ms28.hinet.net"       ' If the server doesn't provided it, then please set manually yourself.
  340.     CGIVersion = Environ("GATEWAY_INTERFACE")     ' CGI Version Number
  341.     RequestMethod = Environ("REQUEST_METHOD")     ' Used Request Method
  342.     VirtualPath = Environ("PATH_INFO")            ' Path info after request URL
  343.     LogicalPath = Environ("PATH_TRANSLATED")      ' Decoded Path Info
  344.     CGIProgramFile = Environ("SCRIPT_NAME")       ' Running Script's Filename
  345.     CGIProgramPath = Environ("SCRIPT_PATH")       ' The folder contains current running script
  346.     CGIProgramUrl = Environ("CGI_URL")            ' CGI Directory's URL
  347.     QueryString = Environ("QUERY_STRING")         ' This environment contains GET data
  348.     CookieString = Environ("HTTP_COOKIE")         ' This environment contains HTTP cookie data
  349.     ContentType = Environ("CONTENT_TYPE")         ' POSTed Data's Content Type
  350.     ContentLength = Environ("CONTENT_LENGTH")     ' POSTed Data's Length
  351.     ServerPort = Environ("SERVER_PORT")           ' Server's Port
  352. '   GMTOffset = Environ("GMT_OFFSET")             ' GMT offset (in seconds!) Used to generate GMT times
  353.     GMTOffset = 28800                             ' Xitami doesn't provided it, so I set it manually (GMT +8 Hour, equal 28800 seconds)
  354.     AcceptTypes = Environ("HTTP_ACCEPT")          ' MIME Types that client can handle
  355.     DocumentRoot = Environ("DOCUMENT_ROOT")       ' Web page root
  356.     For lStrPos = 1 To Len(DocumentRoot)          ' Convert "/" to "\" in Document Root variable
  357.         If Mid$(DocumentRoot, lStrPos, 1) = "/" Then Mid$(DocumentRoot, lStrPos, 1) = "\"
  358.     Next lStrPos
  359.     For lStrPos = 1 To Len(CGIProgramPath)        ' Convert "/" to "\" in CGI Program's Pathname
  360.         If Mid$(CGIProgramPath, lStrPos, 1) = "/" Then Mid$(CGIProgramPath, lStrPos, 1) = "\"
  361.     Next lStrPos
  362.     For lStrPos = 1 To Len(LogicalPath)           ' Convert "/" to "\" in CGI Program's Pathname
  363.         If Mid$(LogicalPath, lStrPos, 1) = "/" Then Mid$(LogicalPath, lStrPos, 1) = "\"
  364.     Next lStrPos
  365.     If Right$(DocumentRoot, 1) = "\" Then DocumentRoot = Left$(DocumentRoot, Len(DocumentRoot) - 1)
  366.     STDOUT = GetStdHandle(STD_OUTPUT_HANDLE)
  367.     If RequestMethod = "POST" Then
  368.         ReDim bPostData(1 To Val(ContentLength))
  369.         STDIN = GetStdHandle(STD_INPUT_HANDLE)
  370.         Call ReadFile(STDIN, bPostData(1), Val(ContentLength), lReaded, 0)
  371.         For lCharPos = 1 To Val(ContentLength)
  372.             PostString = PostString & Chr(bPostData(lCharPos))
  373.         Next lCharPos
  374.         Call SplitTuples(PostString, FormTuples, "&", "=", 1, NumFormTuples, MAX_FORM_TUPLES)
  375.         Close #STDIN
  376.     End If
  377.     Call SplitTuples(QueryString, FormTuples, "&", "=", 1, NumFormTuples, MAX_FORM_TUPLES)
  378.     Call SplitTuples(CookieString, FormCookies, ";", "=", 2, NumFormCookies, MAX_FORM_COOKIES)
  379. End Sub
  380.  
  381. '------------------------------------------------
  382. ' ErrorHandler - Global error handler
  383. '------------------------------------------------
  384. ' If a VB runtime error occurs dusing execution
  385. ' of the program, this procedure generates an
  386. ' HTTP/1.0 HTML-formatted error message into the
  387. ' output file, then exits the program.
  388. '------------------------------------------------
  389. Private Sub ErrorHandler()
  390.     Dim sTemp$, bTemp() As Byte, lCharPos&, lNumWritten&
  391.     sTemp = sTemp & "<HTML><HEAD>" & vbCrLf
  392.     sTemp = sTemp & "<TITLE>Error in " + CGIProgramFile + "</TITLE>" & vbCrLf
  393.     sTemp = sTemp & "</HEAD><BODY>" & vbCrLf
  394.     sTemp = sTemp & "<H1>Error in " + CGIProgramFile + "</H1>" & vbCrLf
  395.     sTemp = sTemp & "An internal Visual Basic error has occurred in " + CGIProgramFile + "." & vbCrLf
  396.     sTemp = sTemp & "<PRE>" + ErrorString + "</PRE>" & vbCrLf
  397.     sTemp = sTemp & "<I>Please</I> note what you were doing when this problem occurred," & vbCrLf
  398.     sTemp = sTemp & "so we can identify and correct it. Write down the Web page you were using," & vbCrLf
  399.     sTemp = sTemp & "any data you may have entered into a form or search box, and" & vbCrLf
  400.     sTemp = sTemp & "anything else that may help us duplicate the problem. Then contact the" & vbCrLf
  401.     sTemp = sTemp & "administrator of this service: " & vbCrLf
  402.     sTemp = sTemp & "<A HREF=""mailto:" & ServerAdmin & """>" & vbCrLf
  403.     sTemp = sTemp & "<ADDRESS><" + ServerAdmin + "></ADDRESS>" & vbCrLf
  404.     sTemp = sTemp & "</A></BODY></HTML>"
  405.     ReDim bTemp(1 To Len(sTemp))
  406.     For lCharPos = 1 To Len(sTemp)
  407.         bTemp(lCharPos) = Asc(Mid(sTemp, lCharPos, 1))
  408.     Next lCharPos
  409.     rc = WriteFile(STDOUT, bTemp(1), UBound(bTemp) - LBound(bTemp) + 1, lNumWritten, 0)
  410.     End
  411. End Sub
  412.  
  413. '-===========================-
  414. ' TUPLE UTILITY FUNCTIONS 1.0
  415. '-===========================-
  416. '
  417. ' Please read README.HTM for hints to use these functions.
  418. '
  419. '----------------------------------------------------------------
  420. ' SplitTuples - General Utility for Tuple data format processing
  421. '----------------------------------------------------------------
  422. Sub SplitTuples(ByVal sSource As String, tDest() As Tuple, sSplit1 As String, sSplit2 As String, iShift As Integer, iCounter As Integer, iMaxCounter As Integer)
  423.     Dim sTemp$(), iOrigCounter%
  424.     Dim lPos&, iLoop%
  425.     ReDim sTemp$(iMaxCounter)
  426.     iOrigCounter = iCounter
  427.     Do While iCounter < iMaxCounter
  428.         lPos = InStr(sSource, sSplit1)
  429.         If lPos = 0 Then
  430.             sTemp(iCounter) = sSource
  431.             iCounter = iCounter + 1
  432.             Exit Do
  433.         End If
  434.         sTemp(iCounter) = Left$(sSource, lPos - 1)
  435.         sSource = Mid$(sSource, lPos + iShift)
  436.         iCounter = iCounter + 1
  437.     Loop
  438.     For iLoop = iOrigCounter To (iCounter - 1)
  439.         lPos = InStr(sTemp(iLoop), sSplit2)
  440.         If lPos = 0 Then
  441.             tDest(iLoop).Key = Decode(sTemp(iLoop))
  442.         Else
  443.             tDest(iLoop).Key = Decode(Left$(sTemp(iLoop), lPos - 1))
  444.             tDest(iLoop).Value = Decode(Mid$(sTemp(iLoop), lPos + 1))
  445.         End If
  446.     Next iLoop
  447. End Sub
  448.  
  449. '----------------------------------------------
  450. ' GetTupleValue - Get the value of a tuple
  451. '----------------------------------------------
  452. ' If this function doesn't found any field
  453. ' you specified, it will return a zero-length
  454. ' string.
  455. '----------------------------------------------
  456. Function TupleValue(sKey As String, tInput() As Tuple) As String
  457.     Dim iIndex As Integer
  458.     For iIndex = 0 To UBound(tInput)
  459.         If tInput(iIndex).Key = sKey Then
  460.             TupleValue = Trim$(tInput(iIndex).Value)
  461.             Exit Function
  462.         End If
  463.     Next iIndex
  464.     TupleValue = ""
  465. End Function
  466.  
  467. '-------------------------------------------------
  468. ' TupleExist - Return True/False depending on
  469. '                whether a tuple field is exist.
  470. '-------------------------------------------------
  471. Function TupleExist(sKey As String, tInput() As Tuple) As Integer
  472.     Dim iIndex As Integer
  473.     TupleExist = False            ' If doesn't found it, will return false
  474.     For iIndex = 0 To UBound(tInput)
  475.         If tInput(iIndex).Key = sKey Then
  476.             TupleExist = True     ' Found it
  477.             Exit Function           ' ** DONE **
  478.         End If
  479.     Next iIndex
  480. End Function
  481.  
  482. '-================================-
  483. ' URL CODING UTILITY FUNCTIONS 1.0
  484. '-================================-
  485. '
  486. ' Please read README.HTM for hints to use these functions.
  487. ' These functions is modified for better DBCS language
  488. ' system support.
  489. '
  490. '-------------------------------------------------------
  491. ' Decode - Decode URL escaped string
  492. '-------------------------------------------------------
  493. Private Function Decode(sInput As String)
  494.     Dim iPos As Integer, iLen As Integer
  495.     Dim sChar As String, sTemp As String
  496.     If InStr(sInput, "%") = 0 And InStr(sInput, "+") = 0 Then
  497.         Decode = sInput
  498.         Exit Function
  499.     End If
  500.     iLen = Len(sInput)
  501.     sTemp = ""
  502.     For iPos = 1 To iLen
  503.         sChar = Mid$(sInput, iPos, 1)
  504.         If sChar = "%" Then
  505.             If Mid$(sInput, iPos + 1, 1) = "%" Then
  506.                 sChar = "%"
  507.                 iPos = iPos + 1
  508.             Else
  509.                 If CInt("&H" & Mid$(sInput, iPos + 1, 2)) >= 127 Then
  510.                     If Mid$(sInput, iPos + 3, 1) = "%" Then
  511.                         sChar = Unescape(Mid$(sInput, iPos + 1, 2) & Mid$(sInput, iPos + 4, 2))
  512.                         iPos = iPos + 5
  513.                     Else
  514.                         sChar = Unescape(Mid$(sInput, iPos + 1, 2) & Hex(Asc(Mid$(sInput, iPos + 3, 1))))
  515.                         iPos = iPos + 3
  516.                     End If
  517.                 Else
  518.                     sChar = Unescape(Mid$(sInput, iPos + 1, 2))
  519.                     iPos = iPos + 2
  520.                 End If
  521.             End If
  522.         End If
  523.         If sChar = "+" Then
  524.             sChar = " "
  525.         End If
  526.         sTemp = sTemp & sChar
  527.     Next iPos
  528.     Decode = sTemp
  529. End Function
  530.  
  531. '------------------------------------------
  532. ' Encode - Convert a string to URL Encoded
  533. '------------------------------------------
  534. Private Function Encode(ByVal sInput As String) As String
  535.     Dim sHex As String, sOutput As String, sChar As String
  536.     Dim lLoop As Long
  537.     For lLoop = 1 To Len(sInput)
  538.         sChar = Mid$(sInput, lLoop, 1)
  539.         If InStr(DONT_ENCODE, sChar) = 0 Then
  540.             If sChar = " " Then
  541.                 sOutput = sOutput & "+"
  542.             Else
  543.                 sHex = Hex$(Asc(sChar))
  544.                 If Len(sHex) = 4 Then
  545.                     sOutput = sOutput & "%" & Left$(sHex, 2)
  546.                     sOutput = sOutput & "%" & Right$(sHex, 2)
  547.                 Else
  548.                     sOutput = sOutput & "%" & sHex
  549.                 End If
  550.             End If
  551.         Else
  552.             sOutput = sOutput & sChar
  553.         End If
  554.     Next lLoop
  555.     Encode = sOutput
  556. End Function
  557.  
  558. '----------------------------------------------
  559. ' UnEscape - Convert Hex Encoded Char to ASCII
  560. '----------------------------------------------
  561. Private Function Unescape(sInput As String) As String
  562.     Dim sHexCode As String
  563.     sHexCode = "&H" & sInput
  564.     Unescape = Chr$(CInt(sHexCode))
  565. End Function
  566.