AndyC
AndyC

Reputation: 31

C++ string parsing to Delphi

I have a C++ Builder XE5 code that I am converting to Delphi. Although I am able to compile, the value of KeyNum seems to always return 0 in my Delphi code. The problem could be in the parsing of the strings.

The function takes a text file and transfer the information to a C++ struct. I converted that to a packed record in Delphi.

C++ code

int __fastcall TFastSift::fastSift(UnicodeString fileName)
{
//
STARTUPINFO StartInfo;        // name structure
PROCESS_INFORMATION ProcInfo; // name structure
memset(&ProcInfo, 0, sizeof(ProcInfo)); // Set up memory block
memset(&StartInfo, 0 , sizeof(StartInfo)); // Set up memory block
StartInfo.cb = sizeof(StartInfo); // Set structure size
//UnicodeString app = "C:\\windows\\system32\\cmd.exe";
//
UnicodeString app = getenv("COMSPEC");
//
UnicodeString args = "/C "+progPath+"siftfast.exe     <"+workPath+fileName+".pgm>"+workPath+fileName+".kds";
StartInfo.dwFlags = STARTF_USESHOWWINDOW;
StartInfo.wShowWindow = SW_HIDE;
int res = CreateProcessW(app.w_str(), args.w_str(), NULL, NULL, NULL, NULL, NULL, NULL, &StartInfo, &ProcInfo); // starts MyApp
if (res)
   {
    WaitForSingleObject(ProcInfo.hThread, INFINITE);
   }
//
//TODO: check if file kds existis
//
TStringList *list = new TStringList(this);
list->LoadFromFile(workPath+fileName+".kds");
FormatSettings.DecimalSeparator = '.';
if (list->Count < 1)
   {
   // error
   delete list;
   return 0;
   }
TStringDynArray tokens;
// key num, key length
tokens =  SplitString(list->Strings[0], " ");
int line_pos, tok_pos;
int keynum    = tokens[0].ToInt();
kfDesc = new FeatureDescriptor[keynum];
UnicodeString line, tok_test;
line_pos = 1;
for (int i = 0; i < keynum; i++)    //
    {
    line = list->Strings[line_pos++];
    tokens = SplitString(line, " ");
    tok_pos = 0;
    try {
       kfDesc[i].x = tokens[tok_pos++].ToDouble();      // x
       kfDesc[i].y = tokens[tok_pos++].ToDouble();      // y
       kfDesc[i].scale = tokens[tok_pos++].ToDouble();  // scale
       kfDesc[i].orientation = tokens[tok_pos++].ToDouble();    // orientation
       // values
       tok_pos = 0;
       while (tok_pos < KLEN)
             {
             line = list->Strings[line_pos++];
             tokens = SplitString(line, " ");
             int tok_len = tokens.get_length() - 1; // usually 16
             for (int j = 0; j < tok_len; j++)
                   {
                   tok_test = tokens[j];
                   kfDesc[i].value[tok_pos] = tokens[j].ToDouble();
                   tok_pos++;
                   }
             }
       line_pos++;  // skip separator line
       }
    catch (...) {
       keynum = 0;
       break;
      }
    }
delete list;
return keynum;
}

Delphi Code (Corrected)

function TFastSift.FastSift(const FileName: string): Integer;
var
  StartInfo: TStartupInfo;
  ProcInfo: TProcessInformation;
  ApplicationName: string;
  CommandLine: string;
  Created: Boolean;
  List: TStringList;
  Tokens: TArray<string>;
  LinePos: Integer;
  TokenPos: Integer;
  KfDesc: TArrOfTFeatureDescriptor;
  Line: string;
  TokenTest: string;
  I: Integer;
  TokenLen: Integer;
  KeyNum: Integer;
  J: Integer;
begin
  FillChar(ProcInfo, SizeOf(ProcInfo), 0);      // Set up memory block
  FillChar(StartInfo, SizeOf(StartInfo), 0);    // Set up memory block
  StartInfo.cb := SizeOf(StartInfo);            // Set structure size
  ApplicationName := GetEnvironmentVariable('COMSPEC');
  CommandLine := '/C ' + FProgPath + 'siftfast.exe <' + FWorkPath + FileName + '.pgm>' + FWorkPath + FileName + '.kds';
  StartInfo.dwFlags := STARTF_USESHOWWINDOW;
  StartInfo.wShowWindow := SW_HIDE;
  Created := CreateProcess(PChar(ApplicationName), PChar(CommandLine), nil, nil, False, 0, nil, nil, StartInfo, ProcInfo); // starts MyApp
  if (Created) then
  begin
    try
      WaitForSingleObject(ProcInfo.hProcess, INFINITE);
    finally
      CloseHandle(ProcInfo.hProcess);
      CloseHandle(ProcInfo.hThread);
    end;
  end;

  //
  // TODO: check if file kds existis
  //
  List := TStringList.Create();
  try
    List.LoadFromFile(TPath.Combine(FWorkPath, FileName + '.kds'));
    FormatSettings.DecimalSeparator := '.';
    if (List.Count < 1) then
    begin
      // error
      Exit(0);
    end;

    // key num, key length
    Tokens := List.Strings[0].Split([' ']);
    KeyNum := StrToInt(Tokens[0]);

    SetLength(KfDesc, KeyNum);
    LinePos := 1;
    for I := 0 to KeyNum - 1 do
    begin
      Line := List.Strings[LinePos];
      Tokens := Line.Split([' ']);
      TokenPos := 0;
      try
        KfDesc[I].X := StrToFloat(Tokens[TokenPos]); // x
        inc(TokenPos);
        KfDesc[I].Y := StrToFloat(Tokens[TokenPos]); // y
        inc(TokenPos);
        KfDesc[I].Scale := StrToFloat(Tokens[TokenPos]); // scale
        inc(TokenPos);
        KfDesc[I].Orientation := StrToFloat(Tokens[TokenPos]); // orientation
        // values
        TokenPos := 0;
        inc(LinePos);
        while (TokenPos < KLEN) do
        begin
          Line := List.Strings[LinePos];
          Tokens := Line.Split([' ']);
          TokenLen := Length(Tokens); // usually 16
          for J := 0 to TokenLen - 1 do
          begin
            TokenTest := Tokens[J];
            KfDesc[I].Value[TokenPos] := StrToFloat(Tokens[J]);
            inc(TokenPos);
          end;
          inc(LinePos); // skip separator line
        end;
        inc(LinePos); // skip separator line

      except
        KeyNum := 0;
        break;
      end;
    end;
  finally
    List.Free();
  end;
  Result := KeyNum;
end;

The text file data looks something like this

14219 128
817.027 1573.46 228.737 1.65905
0 0 0 25 41 0 0 0 16 17 19 94 111 0 0 0 
140 65 15 11 5 0 0 1 34 5 0 0 0 0 0 0 
0 0 0 66 90 5 0 0 44 30 12 140 140 19 0 2 
140 55 5 12 4 1 0 8 52 0 0 0 0 0 0 2 
0 0 0 64 104 12 0 0 61 5 2 64 140 64 5 20 
140 8 0 1 5 5 3 58 44 0 0 0 0 0 0 4 
0 0 1 51 81 44 13 0 40 2 1 61 36 30 76 46 
140 1 0 1 1 0 13 96 20 0 0 0 0 0 0 4 

712.401 2643.9 183.285 1.45477
0 0 5 32 54 116 16 0 106 24 3 12 63 135 13 15 
135 43 0 0 0 1 1 8 10 1 0 0 0 0 0 0 
0 4 53 70 106 15 1 0 69 29 35 78 125 39 11 12 
135 74 1 5 5 1 3 23 24 3 0 0 0 0 0 0 
0 0 16 21 111 94 79 10 19 3 15 25 20 19 135 98 
135 7 0 1 1 1 66 135 15 0 0 0 0 0 0 5 
0 0 0 0 2 26 48 3 0 0 0 0 0 2 91 23 
0 0 0 0 0 0 21 22 0 0 0 0 0 0 0 0 

I think the issue is that the C++ tokens[0].ToInt() value of KeyNum has a value whereas my Delphi StrToInt(Tokens[0]) returns 0 all the time.

I would appreciate if anyone can help me with this code and where I went wrong.

Thanking you in advance.

Upvotes: 0

Views: 396

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 596156

You are not incrementing LinePos after each time you read from List.Strings[LinePos].

When populating the X/Y/Scale/Orientation values, you are not incrementing TokenPos after each time you read from Tokens[TokenPos].

The C++ code performs those increments.

You are incrementing TokenPos before reading the X value, which is wrong. You are skipping the value in Tokens[0]. The C++ code uses post-increments, not pre-increments.

On a side note, you are also leaking the two handles returned by CreateProcess(). You must call CloseHandle() on ProcInfo.hThread and ProcInfo.hProcess after WaitForSingleObject() returns. And you should be waiting on ProcInfo.hProcess instead of ProcInfo.hThread.

Upvotes: 2

Related Questions