String Manipulation of Binary Data

Request Parameterization

Example code contained in a recording of a TCP session:

WebTcpipSendBin(hWeb0, "\h0000104F0000005065746572FFFF",
14); // ···O···Peter
		

The actual business data sent here, the data that should be parameterized, is "Peter" = 0x50 65 74 65 72, but that will not work here. "\h0000104F000000" + sName + "\hFFFF" will not yield the results you might expect. The problem is caused by the zero (0x00) bytes in this string, which Silk Performer (like C) uses for string termination. Therefore all bytes after the first zero byte in a string are ignored when performing such string concatenation.

For manipulation of binary data that may contain zero bytes, you should use the function SetMem. Using the function library detailed below, the above request can be broken into the following lines:

ResetRequestData();
AppendRequestData("\h0000104f000000", 7);
AppendRequestData(sName); // e.g., "Peter"
AppendRequestData("\hFFFF");
SendTcpipRequest(hSend);

The function library is included using an include file (*.bdh). It uses two global variables for the request data and request data length. The function AppendRequestData appends a string (which may contain zero bytes) to the request buffer, and SendTcpipRequest sends the request data using an open TCP connection.

Here are the contents of the include file, which consists of three functions:

const 
  BUFSIZE := 10000; // maximal size for request data
var 
  // global variables for Request data contents and length
  gsRequestData : string(BUFSIZE);
  gnRequestLen  : number init 0;

dclfunc                               
  // start a new request string
  function ResetRequestData
  begin
    gnRequestLen := 0;    
  end ResetRequestData;

  // append data (of length nLen) to the request string
  // if nLen=0, use strlen(sData) instead
  function AppendRequestData(sData: string; 
                             nLen: number optional): number
  begin
    if nLen = 0 then nLen := strlen(sData); end;    
    if nLen + gnRequestLen <= BUFSIZE then          
      // append sData to gsRequestData
      SetMem(gsRequestData, gnRequestLen + 1, sData, nLen);
      // the request length has grown by nLen bytes:
      gnRequestLen := gnRequestLen + nLen;
    else
      RepMessage("Request buffer too small!",
                  SEVERITY_ERROR);
    end;
    AppendRequestData := gnRequestLen;    
  end AppendRequestData;
  
  // Send the request buffer
  // (TCP-connection identified by hTcp)
  function SendTcpipRequest (hTcp: number): boolean
  begin
    SendTcpipRequest := 
      WebTcpipSendBin(hTcp, gsRequestData, gnRequestLen);
  end SendTcpipRequest;

Searching in Response Data

When zero bytes are contained in response data, it makes it difficult to search for strings. The reason is that the StrSearch and StrSearchDelimited functions search in a source string only until they hit the first zero byte, which is interpreted as the string terminator.

Silk Performer offers the function BinSearch, which works on binary data exactly as StrSearch does on strings. You can search for a string (or a sequence of binary data) in response data as follows:
nPos := BinSearch(sResponseData, nResponseLength, sSearch);
		

There is no binary counterpart for the StrSearchDelimited function. If you only want to search for strings (as opposed to binary data containing zero bytes), a workaround is to introduce a function that first eliminates all zero bytes from the response data by mapping them (for example, to the byte 0xFF).

Here is a simple version of such a function. Note that it works only if sLeftVal, sRightVal and the string you are searching are strings (meaing, they don't contain zero bytes).

function BinSearchDelimited(sSource   : string;
                            nSrcLength: number;
                            sLeftVal  : string;
                            sRightVal : string)
                           :string(BUFSIZE)
var
  i : number;
begin
  // eliminate zero bytes in the source string
  for i:=1 to nSrcLength do
    if ord(sSource[i]) = 0 then 
      sSource[i] := chr(255); 
    end;
  end;
  StrSearchDelimited(BinSearchDelimited, BUFSIZE, sSource,
                    sLeftVal, 1, sRightVal, 1,
                    STR_SEARCH_FIRST);
end BinSearchDelimited;