バイナリ データの文字列操作

リクエストのパラメータ化

TCP セッションの記録に含まれるサンプル コードを示します。

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

ここで、実際に送信され、パラメータ化されるべいビジネス データは、"Peter" = 0x50 65 74 65 72 ですが、ここでは機能しません。"\h0000104F000000" + sName + "\hFFFF" は期待通りの結果にはなりません。問題は、この文字列中の 0 (0x00) バイトによって起こされます。 Silk Performer (C 言語のような) では、0 バイトは文字列の終端として使用されるためです。よって、文字列中の最初の 0 バイトのあとのすべてのバイトがこのような文字列結合の実行中に無視されます。

0 バイトを含む可能性のあるバイナリ データの操作には、関数 SetMem を使用するべきです。以下で詳細を示す関数ライブラリを使用して、上記のリクエストは次の行に分割できます。

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

関数ライブラリは、インクルード ファイル (*.bdh) を使ってインクルードします。リクエスト データとリクエスト データ長に対して 2 つのグローバル変数を使用します。関数 AppendRequestData は、リクエスト バッファに文字列を追加します (0 バイトを含むことができる)、そして SendTcpipRequest は、開いている TCP 接続を使用してリクエスト データを送信します。

インクルード ファイルの内容は、以下に示すように 3 つの関数で構成されています。

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;

レスポンス データの検索

レスポンス データに 0 バイトが含まれているとき、文字列を検索することが困難になります。それは、StrSearch および StrSearchDelimited 関数が、対象の文字列を最初の 0 バイトが見つかるまでしか検索を行わないためです。 0 バイトは文字列の終端として解釈されてしまいます。

Silk Performer では、関数 BinSearch を提供しており、文字列に対して StrSearch が行うのと同じようにバイナリ データに対して機能します。次のようにして、レスポンス データの文字列 (または、バイナリ データのシーケンス) を検索できます。
nPos := BinSearch(sResponseData, nResponseLength, sSearch);
		

StrSearchDelimited 関数と同等なバイナリ版の関数はありません。.文字列の検索のみを行いたい場合 (0 バイトを含むバイナリ データとは対照的に)、回避策は、レスポンス データからすべての 0 バイトをマッピングによって (たとえば、0xFF バイトに) 最初に削除する関数を導入することです。

このような関数の単純なバージョンを以下に示します。sLeftVal, sRightVal および検索する文字列が文字列である場合にのみ機能します (つまり、0 バイトを含まない)。

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;