2

I work with Inno JSON Config (like in Pascal Script fails to retrieve wide string from a custom DLL) to read a simple JSON file named items.json:

{
    "Item_0":{
            "Key_1": "String 1",
            "Key_2": "1",
            "Key_3": "True"
    },
    "Item_1":{
            "Key_1": "String 2",
            "Key_2": "2",
            "Key_3": "False"
    }
}

Here is my code :

[Files]
Source: "JSONConfig.dll";            DestDir: "{tmp}\src";          Flags: dontcopy;       
Source: "json_lists\*";              DestDir: "{tmp}\json_lists";   Flags: dontcopy;

[Code]
var
  ItemList: array of WideString;

function JSONQueryString(FileName, Section, Key, Default: WideString;
  var Value: WideString; var ValueLength: Integer): Boolean;
  external 'JSONQueryString@files:jsonconfig.dll stdcall';

procedure AppendItem(var ItemArray: array of WideString; Item: WideString);
begin
  SetLength(ItemArray, GetArrayLength(ItemArray) + 1);
  ItemArray[GetArrayLength(ItemArray) - 1] := Item;
end;
  
function ParseJson(Filename: WideString; Item: String; Key: String; var ItemArray: array of WideString): Boolean;
var
  StrValue: WideString;
  StrLength: Integer;
  ItemNumber: Integer;
  Path: WideString;
begin  
  SetLength(StrValue, 32);
  StrLength := Length(StrValue);

  result := False;
  Path := ExpandConstant('{tmp}'+ '\json_lists\' + Filename);
  ItemNumber := 0;
  while JSONQueryString(Path, ExpandConstant(Item + '_' + IntToStr(ItemNumber)), Key, 'Default', StrValue, StrLength) do
  begin
    ItemNumber := ItemNumber + 1;
    AppendItem(ItemArray, StrValue);
    result := True;
  end;
end;

function NextButtonClick(CurPageID: Integer): Boolean;
var
  I: Integer;
  PathForNextFile: WideString;
begin
  if CurPageID = wpWelcome then
  begin
    if GetArrayLength(ItemList) = 0 then begin
      ExtractTemporaryFiles('{tmp}\json_lists\*');
      if ParseJson('items.json','Item', 'Key_1', ItemList) then begin
        for I := 0 to GetArrayLength(ItemList) - 1 do begin
          PathForNextFile := ItemList[I] + '.json';
          Log(PathForNextFile);     //**
        end;
      end else begin
        Log('Error while parsing')
      end;
    end;
  end;
  result := True;
end;

I have two issues at //** in the code (line Log(PathForNextFile);):

  • The Log only prompts 'String' without the following number (normally 0 or 1);
  • The Log doesn't prompt either the suffix '.json'. It is quite problematic because I need the variable PathForNextFile with the suffix '.json' to parse another file.

I don't know why this happens, any help is welcome!

Ideally I'd like to deal only with String and not WideString, so should I code a PowerShell script which, when called in Inno Setup, returns the right info as a String, if it is possible? I tried to use koldev's JsonParser Library but I couldn't figure out how it worked, even with How to parse a JSON string in Inno Setup? So yet again any help is welcome!

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Gryfbane
  • 23
  • 4

1 Answers1

2

Even the original code from Inno Setup: Working with JSON returns the value truncated. The comment there by @yuval from 2015 (!) says it:

Also JSONQueryString never retrieves the last character


I recommend you to use JsonParser library.

The following is an equivalent of your code implemented using JsonParser library (and my convenience functions from How to parse a JSON string in Inno Setup?):

function ParseJsonFile(
  Filename: string; Item: string; Key: string; var ItemArray: array of string):
  Boolean;
var
  JsonLines: TStringList;
  JsonParser: TJsonParser;
  ItemNumber: Integer;
  JsonRoot, ItemObject: TJsonObject;
  StrValue: TJsonString; // = WideString = string
  ItemKey: string;
begin
  JsonLines := TStringList.Create;
  JsonLines.LoadFromFile(Filename);

  Result := False;
  if ParseJsonAndLogErrors(JsonParser, JsonLines.Text) then
  begin
    JsonRoot := GetJsonRoot(JsonParser.Output);
    ItemNumber := 0;
    while True do
    begin
      ItemKey := Format('%s_%d', [Item, ItemNumber]);
      if FindJsonObject(JsonParser.Output, JsonRoot, ItemKey, ItemObject) and
         FindJsonString(JsonParser.Output, ItemObject, Key, StrValue) then
      begin
        Inc(ItemNumber);
        SetLength(ItemArray, GetArrayLength(ItemArray) + 1);
        ItemArray[GetArrayLength(ItemArray) - 1] := StrValue;
        Result := True;
      end
        else Break;
    end;
  end;

  ClearJsonParser(JsonParser);
end;
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • Your answer is really helpful, I think I understand better the use of this lib. Thanks a lot for your help ! – Gryfbane Apr 19 '23 at 07:30