Add JSON read/write support, update tests

This commit is contained in:
Marc Durdin 2017-11-30 14:26:18 +07:00
parent 5d1be46c37
commit 24fca1cd9f
10 changed files with 897 additions and 72 deletions

View file

@ -145,7 +145,8 @@ uses
VKeys in '..\..\global\delphi\general\VKeys.pas',
Windows8LanguageList in '..\..\global\delphi\general\Windows8LanguageList.pas',
BCP47SuppressScriptRegistry in '..\..\global\delphi\general\BCP47SuppressScriptRegistry.pas',
BCP47Tag in '..\..\global\delphi\general\BCP47Tag.pas';
BCP47Tag in '..\..\global\delphi\general\BCP47Tag.pas',
JsonUtil in '..\..\global\delphi\general\JsonUtil.pas';
{$R *.TLB}

View file

@ -252,6 +252,7 @@
<DCCReference Include="..\..\global\delphi\general\Windows8LanguageList.pas"/>
<DCCReference Include="..\..\global\delphi\general\BCP47SuppressScriptRegistry.pas"/>
<DCCReference Include="..\..\global\delphi\general\BCP47Tag.pas"/>
<DCCReference Include="..\..\global\delphi\general\JsonUtil.pas"/>
<RidlCompile Include="kmcomapi.ridl"/>
<BuildConfiguration Include="Debug">
<Key>Cfg_2</Key>

View file

@ -84,7 +84,7 @@ begin
if i < JSONValue.Count - 1 then
OutputStrings[OutputStrings.Count-1] := OutputStrings[OutputStrings.Count-1] + ','; // I4440
end;
OutputStrings.add(StringOfChar(' ', indent * INDENT_SIZE) + ']');
OutputStrings.add(StringOfChar(' ', (indent-1) * INDENT_SIZE) + ']');
end;
procedure PrettyPrintJSON(JSONValue: TJSONValue; OutputStrings: TStrings; indent: integer = 0);

View file

@ -40,6 +40,7 @@ uses
System.Classes,
System.Generics.Collections,
System.IniFiles,
System.JSON,
System.Sysutils,
Winapi.Windows,
Xml.XMLDoc,
@ -50,6 +51,8 @@ uses
{ Package Information Classes }
function GetJsonValueString(o: TJSONObject; const n: string): string;
type
TPackageInfoEntryType = (pietName, pietVersion, pietCopyright, pietAuthor, pietWebsite, pietOther);
@ -150,6 +153,8 @@ type
procedure SaveIni(AIni: TIniFile); virtual;
procedure LoadXML(ARoot: IXMLNode); virtual;
procedure SaveXML(ARoot: IXMLNode); virtual;
procedure LoadJSON(ARoot: TJSONObject); virtual;
procedure SaveJSON(ARoot: TJSONObject); virtual;
end;
{ Package Options }
@ -178,6 +183,8 @@ type
procedure SaveIni(AIni: TIniFile); virtual;
procedure LoadXML(ARoot: IXMLNode); virtual;
procedure SaveXML(ARoot: IXMLNode); virtual;
procedure LoadJSON(ARoot: TJSONObject); virtual;
procedure SaveJSON(ARoot: TJSONObject); virtual;
property LoadLegacy: Boolean read FLoadLegacy write FLoadLegacy;
property FileVersion: WideString read FFileVersion write SetFileVersion;
property ExecuteProgram: WideString read FExecuteProgram write SetExecuteProgram;
@ -218,6 +225,8 @@ type
procedure SaveIni(AIni: TIniFile); virtual;
procedure LoadXML(ARoot: IXMLNode); virtual;
procedure SaveXML(ARoot: IXMLNode); virtual;
procedure LoadJSON(ARoot: TJSONObject); virtual;
procedure SaveJSON(ARoot: TJSONObject); virtual;
function IndexOf(Name: WideString): Integer; overload;
@ -246,6 +255,8 @@ type
procedure SaveIni(AIni: TIniFile); virtual;
procedure LoadXML(ARoot: IXMLNode); virtual;
procedure SaveXML(ARoot: IXMLNode); virtual;
procedure LoadJSON(ARoot: TJSONObject); virtual;
procedure SaveJSON(ARoot: TJSONObject); virtual;
end;
TPackageStartMenu = class(TPackageBaseObject)
@ -261,6 +272,8 @@ type
procedure SaveIni(AIni: TIniFile); virtual;
procedure LoadXML(ARoot: IXMLNode); virtual;
procedure SaveXML(ARoot: IXMLNode); virtual;
procedure LoadJSON(ARoot: TJSONObject); virtual;
procedure SaveJSON(ARoot: TJSONObject); virtual;
end;
{ Package contained files }
@ -291,6 +304,8 @@ type
procedure SaveIni(AIni: TIniFile); virtual;
procedure LoadXML(ARoot: IXMLNode); virtual;
procedure SaveXML(ARoot: IXMLNode); virtual;
procedure LoadJSON(ARoot: TJSONObject); virtual;
procedure SaveJSON(ARoot: TJSONObject); virtual;
function IndexOfFileType(FFileType: TKMFileType): Integer;
function FromFileName(Filename: WideString): TPackageContentFile;
@ -338,6 +353,8 @@ type
procedure SaveIni(AIni: TIniFile); virtual;
procedure LoadXML(ARoot: IXMLNode); virtual;
procedure SaveXML(ARoot: IXMLNode); virtual;
procedure LoadJSON(ARoot: TJSONObject); virtual;
procedure SaveJSON(ARoot: TJSONObject); virtual;
end;
TPackageKeyboardLanguage = class(TPackageBaseObject)
@ -359,6 +376,8 @@ type
function XMLRootNode: WideString; virtual;
procedure DoLoadXML(ARoot: IXMLNode); virtual;
procedure DoSaveXML(ARoot: IXMLNode); virtual;
procedure DoLoadJSON(ARoot: TJSONObject); virtual;
procedure DoSaveJSON(ARoot: TJSONObject); virtual;
public
Options: TPackageOptions;
StartMenu: TPackageStartMenu;
@ -376,6 +395,9 @@ type
procedure LoadXML; //virtual;
procedure SaveXML; //virtual;
procedure LoadJSON;
procedure SaveJSON;
function SaveXMLToText: WideString;
procedure LoadXMLFromText(Text: WideString);
@ -393,6 +415,7 @@ uses
System.TypInfo,
System.Variants,
JsonUtil,
KeymanVersion,
utildir,
utilsystem,
@ -406,6 +429,78 @@ const
SDisplayFontNotOwnedCorrectly = 'The display font file ''%s'' referred to is not part of the package.';
SOSKFontNotOwnedCorrectly = 'The OSK font file ''%s'' referred to is not part of the package.';
const
SXML_PackageKeyboards = 'Keyboards';
SXML_PackageKeyboard_Name = 'Name';
SXML_PackageKeyboard_ID = 'ID';
SXML_PackageKeyboard_Version = 'Version';
SXML_PackageKeyboard_OSKFont = 'OSKFont';
SXML_PackageKeyboard_DisplayFont = 'DisplayFont';
SXML_PackageKeyboard_Languages = 'Languages';
SXML_PackageKeyboard_Language = 'Language';
SXML_PackageKeyboard_Language_ID = 'ID';
SXML_PackageKeyboard_Language_Name = 'Name';
const
SJSON_System = 'system';
SJSON_System_KeymanDeveloperVersion = 'keymanDeveloperVersion';
SJSON_System_FileVersion = 'fileVersion';
SJSON_Options = 'options';
SJSON_Options_ExecuteProgram = 'executeProgram';
SJSON_Options_ReadMeFile = 'readmeFile';
SJSON_Options_GraphicFile = 'graphicFile';
SJSON_Registry = 'registry';
SJSON_Registry_Root = 'root';
SJSON_Registry_Key = 'key';
SJSON_Registry_Name = 'name';
SJSON_Registry_ValueType = 'valueType';
SJSON_Registry_Value = 'value';
SJSON_StartMenu = 'startMenu';
SJSON_StartMenu_Folder = 'folder';
SJSON_StartMenu_AddUninstallEntry = 'addUninstallEntry';
SJSON_StartMenu_Items = 'items';
SJSON_StartMenu_Items_Name = 'name';
SJSON_StartMenu_Items_Filename = 'filename';
SJSON_StartMenu_Items_Arguments = 'arguments';
SJSON_StartMenu_Items_Icon = 'icon';
SJSON_StartMenu_Items_Location = 'location';
SJSON_Info = 'info';
SJSON_Info__Description = 'description';
SJSON_Info__URL = 'url';
SJSON_Info_Website = 'website';
SJSON_Info_Version = 'version';
SJSON_Info_Name = 'name';
SJSON_Info_Copyright = 'copyright';
SJSON_Info_Author = 'author';
SJSON_PackageInfoEntryTypeNames: array[TPackageInfoEntryType] of string =
(SJSON_Info_Name, SJSON_Info_Version, SJSON_Info_Copyright, SJSON_Info_Author, SJSON_Info_Website, '');
SJSON_Files = 'files';
SJSON_Files_Name = 'name';
SJSON_Files_Description = 'description';
SJSON_Files_CopyLocation = 'copyLocation';
SJSON_Keyboards = 'keyboards';
SJSON_Keyboard_Name = 'name';
SJSON_Keyboard_ID = 'id';
SJSON_Keyboard_Version = 'version';
SJSON_Keyboard_OSKFont = 'oskFont';
SJSON_Keyboard_DisplayFont = 'displayFont';
SJSON_Keyboard_Languages = 'languages';
SJSON_Keyboard_Language_ID = 'id';
SJSON_Keyboard_Language_Name = 'name';
{-------------------------------------------------------------------------------
- TPackageOptions -
------------------------------------------------------------------------------}
@ -482,6 +577,22 @@ begin
FRegistryKeys.LoadIni(AIni);
end;
procedure TPackageOptions.LoadJSON(ARoot: TJSONObject);
var
FSystem, FOptions: TJSONObject;
begin
FSystem := ARoot.Values[SJSON_System] as TJSONObject;
FOptions := ARoot.Values[SJSON_Options] as TJSONObject;
FileVersion := GetJsonValueString(FSystem, SJSON_System_FileVersion);
ExecuteProgram := GetJsonValueString(FOptions, SJSON_Options_ExecuteProgram);
ReadmeFile := Package.Files.FromFileName(GetJsonValueString(FOptions, SJSON_Options_ReadMeFile));
GraphicFile := Package.Files.FromFileName(GetJsonValueString(FOptions, SJSON_Options_GraphicFile));
if Assigned(ReadmeFile) then ReadmeFile.AddNotifyObject(ReadmeRemoved);
if Assigned(GraphicFile) then GraphicFile.AddNotifyObject(GraphicRemoved);
FRegistryKeys.LoadJSON(ARoot);
end;
procedure TPackageOptions.SaveIni(AIni: TIniFile);
begin
AIni.WriteString('Package', 'Version', FileVersion);
@ -493,6 +604,26 @@ begin
FRegistryKeys.SaveIni(AIni);
end;
procedure TPackageOptions.SaveJSON(ARoot: TJSONObject);
var
FOptions, FSystem: TJSONObject;
begin
FSystem := TJSONObject.Create;
ARoot.AddPair(SJSON_System, FSystem);
FSystem.AddPair(SJSON_System_KeymanDeveloperVersion, GetVersionString);
FSystem.AddPair(SJSON_System_FileVersion, FileVersion);
FOptions := TJSONObject.Create;
ARoot.AddPair(SJSON_Options, FOptions);
if ExecuteProgram <> '' then
FOptions.AddPair(SJSON_Options_ExecuteProgram, ExecuteProgram);
if Assigned(ReadmeFile) then
FOptions.AddPair(SJSON_Options_ReadMeFile, ReadmeFile.RelativeFileName);
if Assigned(GraphicFile) then
FOptions.AddPair(SJSON_Options_GraphicFile, GraphicFile.RelativeFileName);
FRegistryKeys.SaveJSON(ARoot);
end;
procedure TPackageOptions.SetExecuteProgram(Value: WideString);
begin
FExecuteProgram := Value;
@ -556,7 +687,7 @@ begin
FInfoType := pietOther;
for piet := Low(PackageInfoEntryTypeNames) to High(PackageInfoEntryTypeNames) do
if PackageInfoEntryTypeNames[piet] = LowerCase(FName) then
if SameText(PackageInfoEntryTypeNames[piet], FName) then
FInfoType := piet;
end;
@ -629,6 +760,34 @@ begin
end;
end;
procedure TPackageInfoEntryList.LoadJSON(ARoot: TJSONObject);
var
name: string;
i: Integer;
inf: TPackageInfoEntry;
FItems: TJSONObject;
FNode: TJSONObject;
v: TPackageInfoEntryType;
begin
Clear;
FItems := ARoot.Values[SJSON_Info] as TJSONObject;
for i := 0 to FItems.Count - 1 do
begin
name := FItems.Pairs[i].JsonString.Value;
for v := Low(TPackageInfoEntryType) to High(TPackageInfoEntryType) do
if SJSON_PackageInfoEntryTypeNames[v] = name then
begin
FNode := FItems.Pairs[i].JsonValue as TJSONObject;
inf := TPackageInfoEntry.Create(Package);
inf.Name := name;
inf.Description := GetJsonValueString(FNode, SJSON_Info__Description);
inf.URL := GetJsonValueString(FNode, SJSON_Info__URL);
Add(inf);
Break;
end;
end;
end;
procedure TPackageInfoEntryList.SaveIni(AIni: TIniFile);
var
i: Integer;
@ -637,6 +796,26 @@ begin
AIni.WriteString('Info', Items[i].Name, Format('"%s","%s"', [Items[i].Description, Items[i].URL]));
end;
procedure TPackageInfoEntryList.SaveJSON(ARoot: TJSONObject);
var
i: Integer;
AInfoRoot, ANode: TJSONObject;
begin
AInfoRoot := TJSONObject.Create;
ARoot.AddPair(SJSON_Info, AInfoRoot);
for i := 0 to Count - 1 do
begin
if SJSON_PackageInfoEntryTypeNames[Items[i].InfoType] <> '' then
begin
ANode := TJSONObject.Create;
AInfoRoot.AddPair(SJSON_PackageInfoEntryTypeNames[Items[i].InfoType], ANode);
ANode.AddPair(SJSON_Info__Description, Items[i].Description);
if Items[i].URL <> '' then
ANode.AddPair(SJSON_Info__URL, Items[i].URL);
end;
end;
end;
function TPackageInfoEntryList.DescIndexOf(Name: WideString): WideString;
var
i: Integer;
@ -729,16 +908,16 @@ end;
- TPackageStartMenuEntryList -
------------------------------------------------------------------------------}
procedure TPackageStartMenuEntryList.LoadXML(ARoot: IXMLNode);
function StrToStartMenuEntryLocation(s: WideString): TPackageStartMenuEntryLocation;
var
v: Integer;
begin
v := System.TypInfo.GetEnumValue(TypeInfo(TPackageStartMenuEntryLocation), s);
if v = -1 then Result := psmelStartMenu
else Result := TPackageStartMenuEntryLocation(v);
end;
function StrToStartMenuEntryLocation(s: WideString): TPackageStartMenuEntryLocation;
var
v: Integer;
begin
v := System.TypInfo.GetEnumValue(TypeInfo(TPackageStartMenuEntryLocation), s);
if v = -1 then Result := psmelStartMenu
else Result := TPackageStartMenuEntryLocation(v);
end;
procedure TPackageStartMenuEntryList.LoadXML(ARoot: IXMLNode);
var
sme: TPackageStartMenuEntry;
i: Integer;
@ -805,6 +984,31 @@ begin
end;
end;
procedure TPackageStartMenuEntryList.LoadJSON(ARoot: TJSONObject);
var
i: Integer;
AItems: TJSONArray;
AItem: TJSONObject;
sme: TPackageStartMenuEntry;
begin
AItems := ARoot.Values[SJSON_StartMenu_Items] as TJSONArray;
if not Assigned(AItems) then
Exit;
for i := 0 to AItems.Count - 1 do
begin
AItem := AItems.Items[i] as TJSONObject;
sme := TPackageStartMenuEntry.Create(Package);
sme.Name := GetJsonValueString(AItem, SJSON_StartMenu_Items_Name);
sme.Prog := GetJsonValueString(AItem, SJSON_StartMenu_Items_Filename);
sme.Params := GetJsonValueString(AItem, SJSON_StartMenu_Items_Arguments);
sme.Icon := GetJsonValueString(AItem, SJSON_StartMenu_Items_Icon);
sme.Location := StrToStartMenuEntryLocation(GetJsonValueString(AItem, SJSON_StartMenu_Items_Location));
Self.Add(sme);
end;
end;
procedure TPackageStartMenuEntryList.SaveIni(AIni: TIniFile);
var
i: Integer;
@ -813,6 +1017,30 @@ begin
AIni.WriteString('StartMenuEntries', Items[i].Name, Format('"%s","%s"', [Items[i].Prog, Items[i].Params]));
end;
procedure TPackageStartMenuEntryList.SaveJSON(ARoot: TJSONObject);
var
i: Integer;
AItems: TJSONArray;
AItem: TJSONObject;
begin
AItems := TJSONArray.Create;
ARoot.AddPair(SJSON_StartMenu_Items, AItems);
for i := 0 to Count - 1 do
begin
AItem := TJSONObject.Create;
AItems.Add(AItem);
AItem.AddPair(SJSON_StartMenu_Items_Name, Items[i].Name);
AItem.AddPair(SJSON_StartMenu_Items_Filename, Items[i].Prog);
if Items[i].Params <> '' then
AItem.AddPair(SJSON_StartMenu_Items_Arguments, Items[i].Params);
if Items[i].Icon <> '' then
AItem.AddPair(SJSON_StartMenu_Items_Icon, Items[i].Icon);
if Items[i].Location <> psmelStartMenu then
AItem.AddPair(SJSON_StartMenu_Items_Location,
System.TypInfo.GetEnumName(TypeInfo(TPackageStartMenuEntryLocation), Ord(Items[i].Location)));
end;
end;
procedure TPackageStartMenuEntryList.Assign(Source: TPackageStartMenuEntryList);
var
i: Integer;
@ -880,6 +1108,21 @@ begin
Entries.LoadIni(AIni);
end;
procedure TPackageStartMenu.LoadJSON(ARoot: TJSONObject);
var
ANode: TJSONObject;
begin
ANode := ARoot.Values[SJSON_StartMenu] as TJSONObject;
if not Assigned(ANode) then
Exit;
Path := GetJsonValueString(ANode, SJSON_StartMenu_Folder);
DoCreate := Path <> '';
AddUninstallEntry := Assigned(ANode.Values[SJSON_StartMenu_AddUninstallEntry]) and
(ANode.Values[SJSON_StartMenu_AddUninstallEntry] is TJSONTrue);
Entries.LoadJSON(ANode);
end;
procedure TPackageStartMenu.SaveIni(AIni: TIniFile);
begin
AIni.WriteString('StartMenu', 'Path', Path);
@ -888,6 +1131,22 @@ begin
Entries.SaveIni(AIni);
end;
procedure TPackageStartMenu.SaveJSON(ARoot: TJSONObject);
var
ANode: TJSONObject;
begin
if (Path = '') and (Entries.Count = 0) then
Exit;
ANode := TJSONObject.Create;
ARoot.AddPair(SJSON_StartMenu, ANode);
if Path <> '' then
ANode.AddPair(SJSON_StartMenu_Folder, Path);
if AddUninstallEntry then
ANode.AddPair(SJSON_StartMenu_AddUninstallEntry, TJSONBool.Create(True));
Entries.SaveJSON(ANode);
end;
{-------------------------------------------------------------------------------
- TPackageSubFile -
------------------------------------------------------------------------------}
@ -983,7 +1242,7 @@ begin
ChildNodes['Name'].NodeValue := Items[i].FileName;
ChildNodes['Description'].NodeValue := Items[i].Description;
ChildNodes['CopyLocation'].NodeValue := Ord(Items[i].CopyLocation);
ChildNodes['FileType'].NodeValue := ExtractFileExt(Items[i].FFileName);
ChildNodes['FileType'].NodeValue := ExtractFileExt(Items[i].FFileName);
end;
end;
end;
@ -1017,6 +1276,28 @@ begin
end;
end;
procedure TPackageContentFileList.LoadJSON(ARoot: TJSONObject);
var
subfile: TPackageContentFile;
i: Integer;
FItems: TJSONArray;
FItem: TJSONObject;
begin
Clear;
FItems := ARoot.Values[SJSON_Files] as TJSONArray;
for i := 0 to FItems.Count - 1 do
begin
FItem := FItems.Items[i] as TJSONObject;
subfile := TPackageContentFile.Create(Package);
subfile.FileName := GetJsonValueString(FItem, SJSON_Files_Name);
subfile.Description := GetJsonValueString(FItem, SJSON_Files_Description);
if Assigned(FItem.Values[SJSON_Files_CopyLocation]) then
subfile.FCopyLocation := TPackageFileCopyLocation((FItem.Values[SJSON_Files_CopyLocation] as TJSONNumber).AsInt);
Add(subfile);
end;
end;
procedure TPackageContentFileList.SaveIni(AIni: TIniFile);
var
i: Integer;
@ -1026,6 +1307,28 @@ begin
Items[i].FileName, Ord(Items[i].CopyLocation)]));
end;
procedure TPackageContentFileList.SaveJSON(ARoot: TJSONObject);
var
i: Integer;
AItems: TJSONArray;
AItem: TJSONObject;
begin
if Count = 0 then
Exit;
AItems := TJSONArray.Create;
ARoot.AddPair(SJSON_Files, AItems);
for i := 0 to Count - 1 do
begin
AItem := TJSONObject.Create;
AItems.Add(AItem);
AItem.AddPair(SJSON_Files_Name, Items[i].FileName);
AItem.AddPair(SJSON_Files_Description, Items[i].Description);
if Items[i].CopyLocation <> pfclPackage then
AItem.AddPair(SJSON_Files_CopyLocation, TJSONNumber.Create(Ord(Items[i].CopyLocation)));
end;
end;
procedure TPackageContentFileList.Assign(Source: TPackageContentFileList);
var
i: Integer;
@ -1130,6 +1433,21 @@ begin
end;
end;
procedure TPackage.LoadJSON;
var
FJSON: TJSONObject;
begin
with TStringStream.Create('', TEncoding.UTF8) do
try
LoadFromFile(FileName);
FJSON := TJSONObject.ParseJSONValue(DataString) as TJSONObject;
finally
Free;
end;
DoLoadJSON(FJSON);
end;
procedure PackageLoadError(Message: WideString);
begin
raise EPackageInfo.Create(Message);
@ -1209,13 +1527,21 @@ begin
end;
end;
procedure TPackage.DoLoadJSON(ARoot: TJSONObject);
begin
StartMenu.LoadJSON(ARoot);
Info.LoadJSON(ARoot);
Files.LoadJSON(ARoot);
Options.LoadJSON(ARoot);
Keyboards.LoadJSON(ARoot);
end;
procedure TPackage.DoLoadXML(ARoot: IXMLNode);
var
FVersion: WideString;
begin
FVersion := VarToWideStr(ARoot.ChildNodes['System'].ChildNodes['FileVersion'].NodeValue);
if (FVersion <> SKeymanVersion70) and (FVersion <> SKeymanVersion80) and (FVersion <> SKeymanVersion) then
if FVersion <> SKeymanVersion70 then
PackageLoadError('Package file version '+FVersion+' is not recognised.');
StartMenu.LoadXML(ARoot);
@ -1225,6 +1551,15 @@ begin
Keyboards.LoadXML(ARoot);
end;
procedure TPackage.DoSaveJSON(ARoot: TJSONObject);
begin
Options.SaveJSON(ARoot);
StartMenu.SaveJSON(ARoot);
Info.SaveJSON(ARoot);
Files.SaveJSON(ARoot);
Keyboards.SaveJSON(ARoot);
end;
procedure TPackage.DoSaveXML(ARoot: IXMLNode);
begin
ARoot.ChildNodes['System'].ChildNodes['KeymanDeveloperVersion'].NodeValue := GetVersionString;
@ -1254,6 +1589,34 @@ begin
end;
end;
procedure TPackage.SaveJSON;
var
FJSON: TJSONObject;
s: TStringList;
begin
if FileExists(FileName) then DeleteFileCleanAttr(FileName); // I4574
FJSON := TJSONObject.Create;
try
DoSaveJSON(FJSON);
s := TStringList.Create;
try
PrettyPrintJSON(FJSON, s);
with TStringStream.Create(s.Text, TEncoding.UTF8) do
try
// Use TStringStream to avoid BOM from TStringList
SaveToFile(FileName);
finally
Free;
end;
finally
s.Free;
end;
finally
FJSON.Free;
end;
end;
procedure TPackage.SaveXML;
var
doc: IXMLDocument;
@ -1418,6 +1781,48 @@ begin
end;
end;
procedure TPackageRegistryKeyList.LoadJSON(ARoot: TJSONObject);
var
i: Integer;
ANode: TJSONArray;
AKeyNode: TJSONObject;
pkr: TPackageRegistryKey;
name, value, root, key, valuetype: WideString;
begin
Clear;
ANode := ARoot.Values[SJSON_Registry] as TJSONArray;
if not Assigned(ANode) then Exit;
for i := 0 to ANode.Count - 1 do
begin
AKeyNode := ANode.Items[i] as TJSONObject;
pkr := TPackageRegistryKey.Create(Package);
name := GetJsonValueString(AKeyNode, SJSON_Registry_Name);
value := GetJsonValueString(AKeyNode, SJSON_Registry_Value);
root := GetJsonValueString(AKeyNode, SJSON_Registry_Root);
key := GetJsonValueString(AKeyNode, SJSON_Registry_Key);
if root = 'HKCU' then pkr.Root := HKEY_CURRENT_USER
else if root = 'HKLM' then pkr.Root := HKEY_LOCAL_MACHINE
else if root = 'HKCR' then pkr.Root := HKEY_CLASSES_ROOT
else pkr.Root := HKEY_CURRENT_USER;
pkr.Name := name;
pkr.Key := key;
valuetype := GetJsonValueString(AKeyNode, SJSON_Registry_ValueType);
if valuetype = 'D'
then pkr.ValueType := rkvtDWord
else pkr.ValueType := rkvtString;
pkr.Value := value;
Add(pkr);
end;
end;
procedure TPackageRegistryKeyList.SaveIni(AIni: TIniFile);
var
pkr: TPackageRegistryKey;
@ -1439,6 +1844,38 @@ begin
end;
end;
procedure TPackageRegistryKeyList.SaveJSON(ARoot: TJSONObject);
var
i: Integer;
AKeyNode: TJSONObject;
ANode: TJSONArray;
pkr: TPackageRegistryKey;
root, valuetype: WideString;
begin
if Count = 0 then
Exit;
ANode := TJSONArray.Create;
ARoot.AddPair(SJSON_Registry, ANode);
for i := 0 to Count - 1 do
begin
pkr := Items[i];
if pkr.Root = HKEY_CURRENT_USER then root := 'HKCU'
else if pkr.Root = HKEY_LOCAL_MACHINE then root := 'HKLM'
else if pkr.Root = HKEY_CLASSES_ROOT then root := 'HKCR'
else root := 'HKCU';
if pkr.ValueType = rkvtString then valuetype := 'S' else valuetype := 'D';
AKeyNode := TJSONObject.Create;
ANode.Add(AKeyNode);
AKeyNode.AddPair(SJSON_Registry_Root, root);
AKeyNode.AddPair(SJSON_Registry_Key, pkr.Key);
AKeyNode.AddPair(SJSON_Registry_Name, pkr.Name);
AKeyNode.AddPair(SJSON_Registry_ValueType, valuetype);
AKeyNode.AddPair(SJSON_Registry_Value, pkr.Value);
end;
end;
procedure TPackageRegistryKeyList.LoadXML(ARoot: IXMLNode);
var
i: Integer;
@ -1630,15 +2067,6 @@ begin
end;
end;
const
SPackageKeyboard_Name = 'Name';
SPackageKeyboard_ID = 'ID';
SPackageKeyboard_Version = 'Version';
SPackageKeyboard_OSKFont = 'OSKFont';
SPackageKeyboard_DisplayFont = 'DisplayFont';
SPackageKeyboard_Language = 'Language';
SPackageKeyboard_Language_ID = 'ID';
procedure TPackageKeyboardList.LoadIni(AIni: TIniFile);
var
s: TStringList;
@ -1659,15 +2087,15 @@ begin
Break;
keyboard := TPackageKeyboard.Create(Package);
keyboard.Name := AIni.ReadString(FSectionName, SPackageKeyboard_Name, '');
keyboard.ID := AIni.ReadString(FSectionName, SPackageKeyboard_ID, '');
keyboard.Version := AIni.ReadString(FSectionName, SPackageKeyboard_Version, '1.0');
keyboard.OSKFont := Package.Files.FromFileNameEx(AIni.ReadString(FSectionName, SPackageKeyboard_OSKFont, ''));
keyboard.DisplayFont := Package.Files.FromFileNameEx(AIni.ReadString(FSectionName, SPackageKeyboard_DisplayFont, ''));
keyboard.Name := AIni.ReadString(FSectionName, SXML_PackageKeyboard_Name, '');
keyboard.ID := AIni.ReadString(FSectionName, SXML_PackageKeyboard_ID, '');
keyboard.Version := AIni.ReadString(FSectionName, SXML_PackageKeyboard_Version, '1.0');
keyboard.OSKFont := Package.Files.FromFileNameEx(AIni.ReadString(FSectionName, SXML_PackageKeyboard_OSKFont, ''));
keyboard.DisplayFont := Package.Files.FromFileNameEx(AIni.ReadString(FSectionName, SXML_PackageKeyboard_DisplayFont, ''));
for j := 0 to MaxInt do
begin
ln := AIni.ReadString(FSectionName, SPackageKeyboard_Language+IntToStr(j), '');
ln := AIni.ReadString(FSectionName, SXML_PackageKeyboard_Language+IntToStr(j), '');
if ln = '' then
Break;
FLanguage := TPackageKeyboardLanguage.Create(Package);
@ -1683,6 +2111,49 @@ begin
end;
end;
procedure TPackageKeyboardList.LoadJSON(ARoot: TJSONObject);
var
keyboard: TPackageKeyboard;
i, j: Integer;
ALanguages, ANode: TJSONArray;
AKeyboard, ALanguage: TJSONObject;
FLanguage: TPackageKeyboardLanguage;
begin
Clear;
ANode := ARoot.Values[SJSON_Keyboards] as TJSONArray;
if not Assigned(ANode) then
Exit;
for i := 0 to ANode.Count - 1 do
begin
AKeyboard := ANode.Items[i] as TJSONObject;
keyboard := TPackageKeyboard.Create(Package);
keyboard.Name := GetJsonValueString(AKeyboard, SJSON_Keyboard_Name);
keyboard.ID := GetJsonValueString(AKeyboard,SJSON_Keyboard_ID);
keyboard.Version := GetJsonValueString(AKeyboard, SJSON_Keyboard_Version);
keyboard.OSKFont := Package.Files.FromFileNameEx(GetJsonValueString(AKeyboard, SJSON_Keyboard_OSKFont));
keyboard.DisplayFont := Package.Files.FromFileNameEx(GetJsonValueString(AKeyboard, SJSON_Keyboard_DisplayFont));
ALanguages := AKeyboard.Values[SJSON_Keyboard_Languages] as TJSONArray;
if Assigned(ALanguages) then
begin
for j := 0 to ALanguages.Count - 1 do
begin
ALanguage := ALanguages.Items[j] as TJSONObject;
FLanguage := TPackageKeyboardLanguage.Create(Package);
FLanguage.ID := GetJsonValueString(ALanguage, SJSON_Keyboard_Language_ID);
FLanguage.Name := GetJsonValueString(ALanguage, SJSON_Keyboard_Language_Name);
keyboard.Languages.Add(FLanguage);
end;
end;
Add(keyboard);
end;
end;
procedure TPackageKeyboardList.LoadXML(ARoot: IXMLNode);
var
keyboard: TPackageKeyboard;
@ -1698,11 +2169,11 @@ begin
AKeyboard := ANode.ChildNodes[i];
keyboard := TPackageKeyboard.Create(Package);
keyboard.Name := VarToStr(AKeyboard.ChildValues[SPackageKeyboard_Name]);
keyboard.ID := VarToStr(AKeyboard.ChildValues[SPackageKeyboard_ID]);
keyboard.Version := VarToStr(AKeyboard.ChildValues[SPackageKeyboard_Version]);
keyboard.OSKFont := Package.Files.FromFileNameEx(VarToStr(AKeyboard.ChildValues[SPackageKeyboard_OSKFont]));
keyboard.DisplayFont := Package.Files.FromFileNameEx(VarToStr(AKeyboard.ChildValues[SPackageKeyboard_DisplayFont]));
keyboard.Name := VarToStr(AKeyboard.ChildValues[SXML_PackageKeyboard_Name]);
keyboard.ID := VarToStr(AKeyboard.ChildValues[SXML_PackageKeyboard_ID]);
keyboard.Version := VarToStr(AKeyboard.ChildValues[SXML_PackageKeyboard_Version]);
keyboard.OSKFont := Package.Files.FromFileNameEx(VarToStr(AKeyboard.ChildValues[SXML_PackageKeyboard_OSKFont]));
keyboard.DisplayFont := Package.Files.FromFileNameEx(VarToStr(AKeyboard.ChildValues[SXML_PackageKeyboard_DisplayFont]));
ALanguages := AKeyboard.ChildNodes['Languages'];
if Assigned(ALanguages) then
@ -1712,7 +2183,7 @@ begin
ALanguage := ALanguages.ChildNodes[j];
FLanguage := TPackageKeyboardLanguage.Create(Package);
FLanguage.ID := ALanguage.Attributes[SPackageKeyboard_Language_ID];
FLanguage.ID := ALanguage.Attributes[SXML_PackageKeyboard_Language_ID];
FLanguage.Name := ALanguage.NodeValue;
keyboard.Languages.Add(FLanguage);
end;
@ -1730,17 +2201,54 @@ begin
for i := 0 to Count-1 do
begin
FSectionName := 'Keyboard'+IntToStr(i);
AIni.WriteString(FSectionName, SPackageKeyboard_Name, Items[i].Name);
AIni.WriteString(FSectionName, SPackageKeyboard_ID, Items[i].ID);
AIni.WriteString(FSectionName, SPackageKeyboard_Version, Items[i].Version);
AIni.WriteString(FSectionName, SXML_PackageKeyboard_Name, Items[i].Name);
AIni.WriteString(FSectionName, SXML_PackageKeyboard_ID, Items[i].ID);
AIni.WriteString(FSectionName, SXML_PackageKeyboard_Version, Items[i].Version);
if Assigned(Items[i].OSKFont) then
AIni.WriteString(FSectionName, SPackageKeyboard_OSKFont, ExtractFileName(Items[i].OSKFont.FileName));
AIni.WriteString(FSectionName, SXML_PackageKeyboard_OSKFont, Items[i].OSKFont.RelativeFileName);
if Assigned(Items[i].DisplayFont) then
AIni.WriteString(FSectionName, SPackageKeyboard_DisplayFont, ExtractFileName(Items[i].DisplayFont.FileName));
AIni.WriteString(FSectionName, SXML_PackageKeyboard_DisplayFont, Items[i].DisplayFont.RelativeFileName);
for j := 0 to Items[i].Languages.Count-1 do
begin
AIni.WriteString(FSectionName, SPackageKeyboard_Language+IntToStr(j), Items[i].Languages[j].ID+','+Items[i].Languages[j].Name);
AIni.WriteString(FSectionName, SXML_PackageKeyboard_Language+IntToStr(j), Items[i].Languages[j].ID+','+Items[i].Languages[j].Name);
end;
end;
end;
procedure TPackageKeyboardList.SaveJSON(ARoot: TJSONObject);
var
i, j: Integer;
AKeyboard, ALanguage: TJSONObject;
AKeyboards, ALanguages: TJSONArray;
begin
if Count = 0 then
Exit;
AKeyboards := TJSONArray.Create;
ARoot.AddPair(SJSON_Keyboards, AKeyboards);
for i := 0 to Count - 1 do
begin
AKeyboard := TJSONObject.Create;
AKeyboards.Add(AKeyboard);
AKeyboard.AddPair(SJSON_Keyboard_Name, Items[i].Name);
AKeyboard.AddPair(SJSON_Keyboard_ID, Items[i].ID);
AKeyboard.AddPair(SJSON_Keyboard_Version, Items[i].Version);
if Assigned(Items[i].OSKFont) then
AKeyboard.AddPair(SJSON_Keyboard_OSKFont, Items[i].OSKFont.RelativeFileName);
if Assigned(Items[i].DisplayFont) then
AKeyboard.AddPair(SJSON_Keyboard_DisplayFont, Items[i].DisplayFont.RelativeFileName);
ALanguages := TJSONArray.Create;
AKeyboard.AddPair(SJSON_Keyboard_Languages, ALanguages);
for j := 0 to Items[i].Languages.Count - 1 do
begin
ALanguage := TJSONObject.Create;
ALanguages.Add(ALanguage);
ALanguage.AddPair(SJSON_Keyboard_Language_Name, Items[i].Languages[j].Name);
ALanguage.AddPair(SJSON_Keyboard_Language_ID, Items[i].Languages[j].ID);
end;
end;
end;
@ -1756,22 +2264,32 @@ begin
begin
AKeyboard := ANode.AddChild('Keyboard');
AKeyboard.ChildNodes[SPackageKeyboard_Name].NodeValue := Items[i].Name;
AKeyboard.ChildNodes[SPackageKeyboard_ID].NodeValue := Items[i].ID;
AKeyboard.ChildNodes[SPackageKeyboard_Version].NodeValue := Items[i].Version;
AKeyboard.ChildNodes[SXML_PackageKeyboard_Name].NodeValue := Items[i].Name;
AKeyboard.ChildNodes[SXML_PackageKeyboard_ID].NodeValue := Items[i].ID;
AKeyboard.ChildNodes[SXML_PackageKeyboard_Version].NodeValue := Items[i].Version;
if Assigned(Items[i].OSKFont) then
AKeyboard.ChildNodes[SPackageKeyboard_OSKFont].NodeValue := ExtractFileName(Items[i].OSKFont.FileName);
AKeyboard.ChildNodes[SXML_PackageKeyboard_OSKFont].NodeValue := Items[i].OSKFont.RelativeFileName;
if Assigned(Items[i].DisplayFont) then
AKeyboard.ChildNodes[SPackageKeyboard_DisplayFont].NodeValue := ExtractFileName(Items[i].DisplayFont.FileName);
AKeyboard.ChildNodes[SXML_PackageKeyboard_DisplayFont].NodeValue := Items[i].DisplayFont.RelativeFileName;
ALanguages := AKeyboard.AddChild('Languages');
for j := 0 to Items[i].Languages.Count - 1 do
begin
ALanguage := ALanguages.AddChild('Language');
ALanguage.NodeValue := Items[i].Languages[j].Name;
ALanguage.Attributes[SPackageKeyboard_Language_ID] := Items[i].Languages[j].ID;
ALanguage.Attributes[SXML_PackageKeyboard_Language_ID] := Items[i].Languages[j].ID;
end;
end;
end;
function GetJsonValueString(o: TJSONObject; const n: string): string;
var
v: TJSONValue;
begin
v := o.Values[n];
if not Assigned(v)
then Result := ''
else Result := v.Value;
end;
end.

View file

@ -59,7 +59,7 @@ begin
end;
{-------------------------------------------------------------------------------
kmp.inf file format -
kmp.inf 5.0 file format -
=================== -
-
[Install] -

View file

@ -29,6 +29,7 @@ interface
uses
System.Classes,
System.IniFiles,
System.JSON,
System.SysUtils,
Winapi.Windows,
Xml.XMLIntf,
@ -47,6 +48,8 @@ type
procedure Assign(Source: TPackageOptions); override;
procedure LoadXML(ARoot: IXMLNode); override;
procedure SaveXML(ARoot: IXMLNode); override;
procedure LoadJSON(ARoot: TJSONObject); override;
procedure SaveJSON(ARoot: TJSONObject); override;
property MSIFileName: WideString read FMSIFileName write FMSIFileName;
property MSIOptions: WideString read FMSIOptions write FMSIOptions; // I3126
end;
@ -58,6 +61,8 @@ type
procedure Import(AIni: TIniFile); override;
procedure DoLoadXML(ARoot: IXMLNode); override;
procedure DoSaveXML(ARoot: IXMLNode); override;
procedure DoLoadJSON(ARoot: TJSONObject); override;
procedure DoSaveJSON(ARoot: TJSONObject); override;
public
function KPSOptions: TKPSOptions;
constructor Create;
@ -79,6 +84,12 @@ uses
utilfiletypes,
utilsystem;
const
SJSON_Options = 'options';
SJSON_Options_MSIFileName = 'msiFilename';
SJSON_Options_MSIOptions = 'msiOptions';
SJSON_Strings = 'strings';
{ TKPSFile }
constructor TKPSFile.Create;
@ -102,6 +113,24 @@ begin
Files[i].FileName := ExpandFileNameEx(FileName, Files[i].FileName);
end;
procedure TKPSFile.DoLoadJSON(ARoot: TJSONObject);
var
i: Integer;
ANode: TJSONObject;
begin
inherited;
if FileName <> '' then
for i := 0 to Files.Count - 1 do
Files[i].FileName := ExpandFileNameEx(FileName, Files[i].FileName);
FStrings.Clear;
ANode := ARoot.Values[SJSON_Strings] as TJSONObject;
if ANode <> nil then
for i := 0 to ANode.Count - 1 do
FStrings.Add(ANode.Pairs[i].JsonString.Value + '=' + ANode.Pairs[i].Value);
end;
procedure TKPSFile.DoLoadXML(ARoot: IXMLNode);
var
i: Integer;
@ -131,6 +160,32 @@ begin
Files[i].FileName := ExpandFileNameEx(FileName, Files[i].FileName);
end;
procedure TKPSFile.DoSaveJSON;
var
i: Integer;
ANode: TJSONObject;
begin
Options.FileVersion := SKeymanVersion70;
if FileName <> '' then
for i := 0 to Files.Count - 1 do
Files[i].FileName := ExtractRelativePath(FileName, Files[i].FileName);
inherited;
if FileName <> '' then
for i := 0 to Files.Count - 1 do
Files[i].FileName := ExpandFileNameEx(FileName, Files[i].FileName);
if FStrings.Count > 0 then
begin
ANode := TJSONObject.Create;
ARoot.AddPair(SJSON_Strings, ANode);
for i := 0 to FStrings.Count - 1 do
ANode.AddPair(FStrings.Names[i], FStrings.ValueFromIndex[i]);
end;
end;
procedure TKPSFile.DoSaveXML(ARoot: IXMLNode);
var
i: Integer;
@ -290,6 +345,16 @@ begin
FMSIOptions := (Source as TKPSOptions).MSIOptions; // I3126
end;
procedure TKPSOptions.LoadJSON(ARoot: TJSONObject);
var
FOptions: TJSONObject;
begin
inherited;
FOptions := ARoot.Values[SJSON_Options] as TJSONObject;
FMSIFileName := GetJsonValueString(FOptions, SJSON_Options_MSIFileName);
FMSIOptions := GetJsonValueString(FOptions, SJSON_Options_MSIOptions);
end;
procedure TKPSOptions.LoadXML(ARoot: IXMLNode);
begin
inherited;
@ -297,6 +362,18 @@ begin
FMSIOptions := VarToWideStr(ARoot.ChildNodes['Options'].ChildNodes['MSIOptions'].NodeValue); // I3126
end;
procedure TKPSOptions.SaveJSON(ARoot: TJSONObject);
var
FOptions: TJSONObject;
begin
inherited;
FOptions := ARoot.Values[SJSON_Options] as TJSONObject;
if FMSIFileName <> '' then
FOptions.AddPair(SJSON_Options_MSIFileName, FMSIFileName);
if FMSIOptions <> '' then
FOptions.AddPair(SJSON_Options_MSIOptions, FMSIOptions);
end;
procedure TKPSOptions.SaveXML(ARoot: IXMLNode);
begin
inherited;

View file

@ -26,6 +26,9 @@ type
[Test]
procedure TestXMLInOut;
[Test]
procedure TestJSONInOut;
[Test]
procedure TestRoundTrip;
@ -116,6 +119,16 @@ begin
try
p1.FileName := DataPath + 'test2.out.inf';
p1.LoadIni;
p1.FileName := DataPath + 'test2.out.json';
p1.SaveJSON;
finally
p1.Free;
end;
p1 := TKpsFile.Create;
try
p1.FileName := DataPath + 'test2.out.json';
p1.LoadJSON;
p1.FileName := DataPath + 'test2.out.xml';
p1.SaveXML;
finally
@ -143,6 +156,16 @@ begin
try
p1.FileName := DataPath + 'test3.out.xml';
p1.LoadXML;
p1.FileName := DataPath + 'test3.out.json';
p1.SaveJSON;
finally
p1.Free;
end;
p1 := TKpsFile.Create;
try
p1.FileName := DataPath + 'test3.out.json';
p1.LoadJSON;
p1.FileName := DataPath + 'test3.out.inf';
p1.SaveIni;
finally
@ -169,6 +192,23 @@ begin
DoCompare(DataPath + 'test.xml', DataPath + 'test4.out.xml');
end;
procedure TPackageInfoTest.TestJSONInOut;
var
p1: TPackage;
begin
p1 := TKpsFile.Create;
try
p1.FileName := DataPath + 'test.json';
p1.LoadJSON;
p1.FileName := DataPath + 'test5.out.json';
p1.SaveJSON;
finally
p1.Free;
end;
DoCompare(DataPath + 'test.json', DataPath + 'test5.out.json');
end;
procedure TPackageInfoTest.DoCompare(f1, f2: string);
var
k1, k2: TKpsFile;
@ -177,14 +217,14 @@ begin
k2 := TKpsFile.Create;
try
k1.FileName := f1;
if SameText(ExtractFileExt(f1), '.xml')
then k1.LoadXml
else k1.LoadIni;
if SameText(ExtractFileExt(f1), '.xml') then k1.LoadXml
else if SameText(ExtractFileExt(f1), '.json') then k1.LoadJSON
else k1.LoadIni;
k2.FileName := f2;
if SameText(ExtractFileExt(f2), '.xml')
then k2.LoadXml
else k2.LoadIni;
if SameText(ExtractFileExt(f2), '.xml') then k2.LoadXml
else if SameText(ExtractFileExt(f2), '.json') then k2.LoadJSON
else k2.LoadIni;
DoCompareKpsFiles(f1, f2, k1, k2);
finally

View file

@ -8,7 +8,6 @@ uses
{$IFDEF TESTINSIGHT}
TestInsight.DUnitX,
{$ENDIF }
PackageInfo in '..\..\global\delphi\general\PackageInfo.pas',
utilfiletypes in '..\..\global\delphi\general\utilfiletypes.pas',
utilstr in '..\..\global\delphi\general\utilstr.pas',
@ -23,11 +22,11 @@ uses
GetOsVersion in '..\..\global\delphi\general\GetOsVersion.pas',
kpsfile in '..\..\global\delphi\general\kpsfile.pas',
PackageFileFormats in '..\..\global\delphi\general\PackageFileFormats.pas',
DUnitX.Loggers.Console,
DUnitX.Loggers.Xml.NUnit,
DUnitX.TestFramework,
PackageInfoTest in 'PackageInfoTest.pas';
PackageInfoTest in 'PackageInfoTest.pas',
JsonUtil in '..\..\global\delphi\general\JsonUtil.pas';
var
runner : ITestRunner;

View file

@ -89,21 +89,22 @@
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="..\..\..\global\delphi\general\PackageInfo.pas"/>
<DCCReference Include="..\..\..\global\delphi\general\utilfiletypes.pas"/>
<DCCReference Include="..\..\..\global\delphi\general\utilstr.pas"/>
<DCCReference Include="..\..\..\global\delphi\cust\StockFileNames.pas"/>
<DCCReference Include="..\..\..\global\delphi\general\Unicode.pas"/>
<DCCReference Include="..\..\..\global\delphi\general\KeymanVersion.pas"/>
<DCCReference Include="..\..\..\global\delphi\general\VersionInfo.pas"/>
<DCCReference Include="..\..\..\global\delphi\general\utilsystem.pas"/>
<DCCReference Include="..\..\..\global\delphi\general\utilexecute.pas"/>
<DCCReference Include="..\..\..\global\delphi\general\utildir.pas"/>
<DCCReference Include="..\..\..\global\delphi\general\RegistryKeys.pas"/>
<DCCReference Include="..\..\..\global\delphi\general\GetOsVersion.pas"/>
<DCCReference Include="..\..\..\global\delphi\general\kpsfile.pas"/>
<DCCReference Include="..\..\..\global\delphi\general\PackageFileFormats.pas"/>
<DCCReference Include="..\..\global\delphi\general\PackageInfo.pas"/>
<DCCReference Include="..\..\global\delphi\general\utilfiletypes.pas"/>
<DCCReference Include="..\..\global\delphi\general\utilstr.pas"/>
<DCCReference Include="..\..\global\delphi\cust\StockFileNames.pas"/>
<DCCReference Include="..\..\global\delphi\general\Unicode.pas"/>
<DCCReference Include="..\..\global\delphi\general\KeymanVersion.pas"/>
<DCCReference Include="..\..\global\delphi\general\VersionInfo.pas"/>
<DCCReference Include="..\..\global\delphi\general\utilsystem.pas"/>
<DCCReference Include="..\..\global\delphi\general\utilexecute.pas"/>
<DCCReference Include="..\..\global\delphi\general\utildir.pas"/>
<DCCReference Include="..\..\global\delphi\general\RegistryKeys.pas"/>
<DCCReference Include="..\..\global\delphi\general\GetOsVersion.pas"/>
<DCCReference Include="..\..\global\delphi\general\kpsfile.pas"/>
<DCCReference Include="..\..\global\delphi\general\PackageFileFormats.pas"/>
<DCCReference Include="PackageInfoTest.pas"/>
<DCCReference Include="..\..\global\delphi\general\JsonUtil.pas"/>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
@ -515,6 +516,7 @@
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
</Deployment>
<Platforms>
<Platform value="Linux64">False</Platform>
<Platform value="Win32">True</Platform>
<Platform value="Win64">False</Platform>
</Platforms>

View file

@ -0,0 +1,187 @@
{
"system" : {
"keymanDeveloperVersion" : "0.0.0.0",
"fileVersion" : "7.0"
},
"options" : {
"readmeFile" : "readme.htm",
"graphicFile" : "sideimage.bmp"
},
"startMenu" : {
"folder" : "GFF Amharic Keyboard",
"addUninstallEntry" : true,
"items" : [
{
"name" : "Welcome",
"filename" : "..\\..\\..\\gff\\gff_amh_7\\source\\welcome.htm"
},
{
"name" : "Amharic Keyboard Manual (Amharic)",
"filename" : "AmharicTyping-Amharic.pdf"
},
{
"name" : "Amharic Keyboard Manual (English)",
"filename" : "AmharicTyping-English.pdf"
},
{
"name" : "OFL (Abyssinica SIL Licence)",
"filename" : "OFL.txt"
},
{
"name" : "GPL (WashRa + Free Serif Licence)",
"filename" : "GNU-GPLv2.txt"
}
]
},
"info" : {
"website" : {
"description" : "http://keyboards.ethiopic.org",
"url" : "http://keyboards.ethiopic.org"
},
"version" : {
"description" : "8.0.0"
},
"name" : {
"description" : "GFF Amharic Keyboard"
},
"copyright" : {
"description" : "Creative Commons Attribution 3.0"
},
"author" : {
"description" : "The Ge'ez Frontier Foundation",
"url" : "mailto:keyboards@ethiopic.org"
}
},
"files" : [
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\readme.htm",
"description" : "File readme.htm"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\sideimage.bmp",
"description" : "File sideimage.bmp"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\gff\\gff_amh_7\\source\\AmharicTyping-Amharic.pdf",
"description" : "File AmharicTyping-Amharic.pdf"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\gff\\gff_amh_7\\source\\AmharicTyping-English.pdf",
"description" : "File AmharicTyping-English.pdf"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\OFL.txt",
"description" : "File OFL.txt"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\GNU-GPLv2.txt",
"description" : "File GNU-GPLv2.txt"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\gff\\gff_amh_7\\source\\welcome.htm",
"description" : "File Welcome.htm"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\AbyssinicaSIL-R.ttf",
"description" : "Font Abyssinica SIL"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\fantuwua.ttf",
"description" : "Font Ethiopic Fantuwua"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\FreeSerif.otf",
"description" : "Font Free Serif"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\goffer.ttf",
"description" : "Font Ethiopic Yigezu Bisrat Goffer"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\hiwua.ttf",
"description" : "Font Ethiopic Hiwua"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\jiret.ttf",
"description" : "Font Ethiopia Jiret"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\jiretsl.ttf",
"description" : "Font Ethiopia Jiret Slant"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\tint.ttf",
"description" : "Font Ethiopic Tint"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\washrab.ttf",
"description" : "Font Ethiopic WashRa Bold"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\washrabsl.ttf",
"description" : "Font Ethiopic WashRa Bold Slant"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\washrasb.ttf",
"description" : "Font Ethiopic WashRa SemiBold"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\washrasbsl.ttf",
"description" : "Font Ethiopic WashRa SemiBold Slant"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\wookianos.ttf",
"description" : "Font Ethiopic Wookianos"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\shared\\fonts\\geez\\yebse.ttf",
"description" : "Font Ethiopic Yebse"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\gff\\gff_amh_7\\build\\gff_amh_7.kvk",
"description" : "File gff_amh_7.kvk"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\gff\\gff_amh_7\\build\\gff_amh_7.kmx",
"description" : "Keyboard Amharic"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\gff\\gff_ethiopic_7\\build\\gff_ethiopic_7.kvk",
"description" : "File gff_ethiopic_7.kvk"
},
{
"name" : "C:\\Projects\\keyman\\open\\windows\\src\\unit-tests\\package-info\\Win32\\Debug\\..\\..\\test\\..\\..\\..\\gff\\gff_ethiopic_7\\build\\gff_ethiopic_7.kmx",
"description" : "Keyboard Ethiopic - (Language Neutral)"
}
],
"keyboards" : [
{
"name" : "Amharic",
"id" : "gff_amh_7",
"version" : "8.0",
"oskFont" : "..\\..\\..\\shared\\fonts\\geez\\wookianos.ttf",
"displayFont" : "..\\..\\..\\shared\\fonts\\geez\\fantuwua.ttf",
"languages" : [
{
"name" : "Amharic",
"id" : "amh"
},
{
"name" : "Ge'ez",
"id" : "gez"
}
]
},
{
"name" : "Ethiopic Language Neutral",
"id" : "gff_ethiopic_7",
"version" : "8.0",
"languages" : [
{
"name" : "Ge'ez",
"id" : "gez"
}
]
}
]
}