Package file format changes + unit tests + unit test framework

This commit is contained in:
Marc Durdin 2017-11-29 12:01:07 +07:00
parent 1572616722
commit 9579d2d3a2
14 changed files with 1378 additions and 128 deletions

View file

@ -35,6 +35,7 @@ INSTALLPATH_KEYMANENGINE=%CommonProgramFiles(X86)%\Keyman\Keyman Engine 10.0
!IFDEF USE_PLUSMEMO
MAKEFLAG_USE_PLUSMEMO=-DUSE_PLUSMEMO
DELPHI_MSBUILD_FLAG_USE_PLUSMEMO=/p:USE_PLUSMEMO=USE_PLUSMEMO
!ENDIF
!IFDEF DELPHI_STARTER
@ -116,6 +117,8 @@ DCC32DPK=@$(DEVTOOLS) -dcc $(DELPHIDPKPARAMS) $(MAKEFLAG_USE_PLUSMEMO)
DCC64=dcc64.exe $(DELPHIDPRPARAMS64) -N0x64\ -Ex64\
DELPHI_MSBUILD=$(ROOT)\src\buildtools\msbuild-wrapper.bat $(DELPHI_MSBUILD_FLAG_USE_PLUSMEMO)
#
# Other program build commands
#

View file

@ -29,7 +29,7 @@ default:
TARGETS=ext global buildtools developer engine desktop support
RELEASE_TARGETS=desktop
CLEANS=test cleanroot
CLEANS=test cleanroot unit-tests
MANIFESTS=engine desktop developer
EXCLUDEPATHDEFINES=1
@ -83,6 +83,11 @@ test:
$(MAKE) $(TARGET)
cd $(ROOT)\src
unit-tests:
cd $(ROOT)\src\unit-tests
$(MAKE) $(TARGET)
cd $(ROOT)\src
# ----------------------------------------------------------------------
# release
# ----------------------------------------------------------------------
@ -161,7 +166,7 @@ update-version: build-tools mkver-app
build-release-wrapper: clean-output update-version
$(MAKE) dirs
$(MAKE) build-tools
$(MAKE) build
$(MAKE) build unit-tests
$(MAKE) build-release
$(MAKE) signcode
$(MAKE) -DTARGET=test test

View file

@ -0,0 +1,12 @@
@echo off
rem
rem This wrapper is for Delphi msbuild calls only. It sets up the msbuild environment
rem for Delphi, which is not compatible with the VS msbuild environment.
rem
rem Do not use this for VS builds.
rem
call rsvars.bat
msbuild.exe %*
exit /b %errorlevel%

View file

@ -41,7 +41,6 @@ uses
System.Generics.Collections,
System.IniFiles,
System.Sysutils,
Vcl.Graphics,
Winapi.Windows,
Xml.XMLDoc,
Xml.XMLIntf,
@ -81,13 +80,27 @@ type
pfclInstallTemp, // Used only for installation, temporary
pfclLocaleFolder); // For locale files
TPackage = class;
{ Base Classes }
TPackageBaseObject = class
strict private
FPackage: TPackage;
protected
property Package: TPackage read FPackage;
public
constructor Create(APackage: TPackage); virtual;
end;
TPackageBaseNotifyObject = class(TPackageBaseObject)
private
FNotifyObjects: TObjectList<TPackageNotifyEventWrapper>;
FTag: Integer;
function Notify(EventType: TPackageNotifyEventType): Boolean;
public
constructor Create;
constructor Create(APackage: TPackage); override;
destructor Destroy; override;
procedure AddNotifyObject(FEventHandler: TPackageNotifyEvent);
procedure RemoveNotifyObject(FEventHandler: TPackageNotifyEvent);
@ -95,7 +108,16 @@ type
property Tag: Integer read FTag write FTag;
end;
TPackage = class;
TPackageObjectList<T: TPackageBaseObject> = class(TObjectList<T>)
strict private
FPackage: TPackage;
protected
property Package: TPackage read FPackage;
public
constructor Create(APackage: TPackage);
end;
TPackageContentFile = class;
TPackageContentFileList = class;
@ -103,16 +125,15 @@ type
TPackageRegistryKeyValueType = (rkvtString, rkvtDWord);
TPackageRegistryKey = class
TPackageRegistryKey = class(TPackageBaseObject)
private
FPackage: TPackage;
FKey: WideString;
FValueType: TPackageRegistryKeyValueType;
FValue: WideString;
FRoot: HKEY;
FName: WideString;
public // I3311
constructor Create(APackage: TPackage);
constructor Create(APackage: TPackage); override;
destructor Destroy; override;
procedure Assign(Source: TPackageRegistryKey);
property Key: WideString read FKey write FKey;
@ -122,11 +143,8 @@ type
property ValueType: TPackageRegistryKeyValueType read FValueType write FValueType;
end;
TPackageRegistryKeyList = class(TObjectList<TPackageRegistryKey>)
private
FPackage: TPackage;
TPackageRegistryKeyList = class(TPackageObjectList<TPackageRegistryKey>)
public
constructor Create(APackage: TPackage);
procedure Assign(Source: TPackageRegistryKeyList); virtual;
procedure LoadIni(AIni: TIniFile); virtual;
procedure SaveIni(AIni: TIniFile); virtual;
@ -136,9 +154,8 @@ type
{ Package Options }
TPackageOptions = class
TPackageOptions = class(TPackageBaseObject)
private
FPackage: TPackage;
FFileVersion: WideString;
FExecuteProgram: WideString;
FReadmeFile: TPackageContentFile;
@ -153,12 +170,10 @@ type
EventType: TPackageNotifyEventType; var FAllow: Boolean);
procedure ReadmeRemoved(Sender: TObject;
EventType: TPackageNotifyEventType; var FAllow: Boolean);
protected
property Package: TPackage read FPackage;
public
procedure Assign(Source: TPackageOptions); virtual;
constructor Create(APackage: TPackage); virtual;
constructor Create(APackage: TPackage); override;
destructor Destroy; override;
procedure Assign(Source: TPackageOptions); virtual;
procedure LoadIni(AIni: TIniFile); virtual;
procedure SaveIni(AIni: TIniFile); virtual;
procedure LoadXML(ARoot: IXMLNode); virtual;
@ -174,9 +189,8 @@ type
{ Package Information }
TPackageInfoEntry = class
TPackageInfoEntry = class(TPackageBaseObject)
private
FPackage: TPackage;
FURL: WideString;
FDescription: WideString;
FName: WideString;
@ -185,7 +199,6 @@ type
procedure SetName(Value: WideString);
procedure SetURL(Value: WideString);
public
constructor Create(APackage: TPackage);
procedure Assign(Source: TPackageInfoEntry); virtual;
property InfoType: TPackageInfoEntryType read FInfoType;
property Name: WideString read FName write SetName;
@ -193,16 +206,13 @@ type
property URL: WideString read FURL write SetURL;
end;
TPackageInfoEntryList = class(TObjectList<TPackageInfoEntry>)
private
FPackage: TPackage;
TPackageInfoEntryList = class(TPackageObjectList<TPackageInfoEntry>)
protected
procedure SetDesc(Name, Desc: WideString);
procedure SetURL(Name, URL: WideString);
function DescIndexOf(Name: WideString): WideString;
function UrlIndexOf(Name: WideString): WideString;
public
constructor Create(APackage: TPackage);
procedure Assign(Source: TPackageInfoEntryList); virtual;
procedure LoadIni(AIni: TIniFile); virtual;
procedure SaveIni(AIni: TIniFile); virtual;
@ -213,32 +223,24 @@ type
property Desc[Name: WideString]: WideString read DescIndexOf write SetDesc;
property URL[Name: WideString]: WideString read URLIndexOf write SetURL;
function Add(Item: TPackageInfoEntry): Integer;
end;
{ Package Start Menu Classes }
TPackageStartMenuEntryLocation = (psmelStartMenu, psmelDesktop); //, psmelQuickLaunch);
TPackageStartMenuEntry = class
private
FPackage: TPackage;
TPackageStartMenuEntry = class(TPackageBaseObject)
public
Name: WideString;
Prog: WideString;
Params: WideString;
Icon: WideString;
Location: TPackageStartMenuEntryLocation;
constructor Create(APackage: TPackage);
procedure Assign(Source: TPackageStartMenuEntry); virtual;
end;
TPackageStartMenuEntryList = class(TObjectList<TPackageStartMenuEntry>)
private
FPackage: TPackage;
TPackageStartMenuEntryList = class(TPackageObjectList<TPackageStartMenuEntry>)
public
constructor Create(APackage: TPackage);
procedure Assign(Source: TPackageStartMenuEntryList); virtual;
procedure LoadIni(AIni: TIniFile); virtual;
procedure SaveIni(AIni: TIniFile); virtual;
@ -246,15 +248,13 @@ type
procedure SaveXML(ARoot: IXMLNode); virtual;
end;
TPackageStartMenu = class
private
FPackage: TPackage;
TPackageStartMenu = class(TPackageBaseObject)
public
Path: WideString;
DoCreate: Boolean;
AddUninstallEntry: Boolean;
Entries: TPackageStartMenuEntryList;
constructor Create(APackage: TPackage);
constructor Create(APackage: TPackage); override;
destructor Destroy; override;
procedure Assign(Source: TPackageStartMenu); virtual;
procedure LoadIni(AIni: TIniFile); virtual;
@ -265,9 +265,8 @@ type
{ Package contained files }
TPackageContentFile = class(TPackageBaseObject)
TPackageContentFile = class(TPackageBaseNotifyObject)
private
FPackage: TPackage;
FCopyLocation: TPackageFileCopyLocation;
FDescription: WideString;
FFileName: WideString;
@ -277,22 +276,16 @@ type
procedure SetFileType(const Value: TKMFileType);
procedure SetCopyLocation(const Value: TPackageFileCopyLocation);
public
constructor Create(APackage: TPackage);
procedure Assign(Source: TPackageContentFile); virtual;
function RelativeFileName: WideString;
property FileName: WideString read FFileName write SetFileName; // relative to .kps, or no path if inside .kmp or .exe
property FileType: TKMFileType read FFileType write SetFileType;
property Description: WideString read FDescription write SetDescription;
property CopyLocation: TPackageFileCopyLocation read FCopyLocation write SetCopyLocation;
property Package: TPackage read FPackage;
end;
TPackageContentFileList = class(TObjectList<TPackageContentFile>)
private
FPackage: TPackage;
TPackageContentFileList = class(TPackageObjectList<TPackageContentFile>)
public
constructor Create(APackage: TPackage);
procedure Assign(Source: TPackageContentFileList); virtual;
procedure LoadIni(AIni: TIniFile); virtual;
procedure SaveIni(AIni: TIniFile); virtual;
@ -305,6 +298,57 @@ type
procedure Delete(Index: Integer);
end;
{ TPackageKeyboard }
TPackageKeyboard = class;
TPackageKeyboardList = class;
TPackageKeyboardLanguage = class;
TPackageKeyboardLanguageList = class;
TPackageKeyboard = class(TPackageBaseObject)
private
FName: string;
FOSKFont: TPackageContentFile;
FID: string;
FDisplayFont: TPackageContentFile;
FLanguages: TPackageKeyboardLanguageList;
FVersion: string;
procedure SetDisplayFont(const Value: TPackageContentFile);
procedure SetOSKFont(const Value: TPackageContentFile);
procedure DisplayFontRemoved(Sender: TObject;
EventType: TPackageNotifyEventType; var FAllow: Boolean);
procedure OSKFontRemoved(Sender: TObject;
EventType: TPackageNotifyEventType; var FAllow: Boolean);
public
constructor Create(APackage: TPackage); override;
destructor Destroy; override;
procedure Assign(Source: TPackageKeyboard); virtual;
property Name: string read FName write FName;
property ID: string read FID write FID;
property Version: string read FVersion write FVersion;
property Languages: TPackageKeyboardLanguageList read FLanguages;
property OSKFont: TPackageContentFile read FOSKFont write SetOSKFont;
property DisplayFont: TPackageContentFile read FDisplayFont write SetDisplayFont;
end;
TPackageKeyboardList = class(TPackageObjectList<TPackageKeyboard>)
public
procedure Assign(Source: TPackageKeyboardList); virtual;
procedure LoadIni(AIni: TIniFile); virtual;
procedure SaveIni(AIni: TIniFile); virtual;
procedure LoadXML(ARoot: IXMLNode); virtual;
procedure SaveXML(ARoot: IXMLNode); virtual;
end;
TPackageKeyboardLanguage = class(TPackageBaseObject)
ID: string;
Name: string;
end;
TPackageKeyboardLanguageList = class(TPackageObjectList<TPackageKeyboardLanguage>);
{ TPackage }
TPackage = class
private
FFileName: WideString;
@ -320,6 +364,7 @@ type
StartMenu: TPackageStartMenu;
Files: TPackageContentFileList;
Info: TPackageInfoEntryList;
Keyboards: TPackageKeyboardList;
property FileName: WideString read FFileName write FFileName;
procedure Assign(Source: TPackage); virtual;
@ -358,6 +403,8 @@ const
SReadmeNotOwnedCorrectly = 'The readme file ''%s'' referred to is not part of the package.';
SGraphicNotOwnedCorrectly = 'The graphic file ''%s'' referred to is not part of the package.';
SFileNotOwnedCorrectly = 'The file ''%s'' referred to is not part of the package.';
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.';
{-------------------------------------------------------------------------------
- TPackageOptions -
@ -368,21 +415,20 @@ begin
FFileVersion := Source.FileVersion;
FExecuteProgram := Source.ExecuteProgram;
if Assigned(Source.ReadmeFile)
then ReadmeFile := FPackage.Files.FromFileName(Source.ReadmeFile.FileName)
then ReadmeFile := Package.Files.FromFileName(Source.ReadmeFile.FileName)
else ReadmeFile := nil;
if Assigned(Source.GraphicFile)
then GraphicFile := FPackage.Files.FromFileName(Source.GraphicFile.FileName)
then GraphicFile := Package.Files.FromFileName(Source.GraphicFile.FileName)
else GraphicFile := nil;
FRegistryKeys.Assign(Source.RegistryKeys);
end;
constructor TPackageOptions.Create(APackage: TPackage);
begin
inherited Create;
inherited Create(APackage);
FLoadLegacy := True;
FPackage := APackage;
FRegistryKeys := TPackageRegistryKeyList.Create(FPackage);
FFileVersion := SKeymanVersion;
FRegistryKeys := TPackageRegistryKeyList.Create(Package);
FFileVersion := SKeymanVersion70;
end;
destructor TPackageOptions.Destroy;
@ -407,8 +453,8 @@ procedure TPackageOptions.LoadXML(ARoot: IXMLNode);
begin
FileVersion := VarToWideStr(ARoot.ChildNodes['System'].ChildNodes['FileVersion'].NodeValue);
ExecuteProgram := VarToWideStr(ARoot.ChildNodes['Options'].ChildNodes['ExecuteProgram'].NodeValue);
ReadmeFile := FPackage.Files.FromFileName(VarToWideStr(ARoot.ChildNodes['Options'].ChildNodes['ReadMeFile'].NodeValue));
GraphicFile := FPackage.Files.FromFileName(VarToWideStr(ARoot.ChildNodes['Options'].ChildNodes['GraphicFile'].NodeValue));
ReadmeFile := Package.Files.FromFileName(VarToWideStr(ARoot.ChildNodes['Options'].ChildNodes['ReadMeFile'].NodeValue));
GraphicFile := Package.Files.FromFileName(VarToWideStr(ARoot.ChildNodes['Options'].ChildNodes['GraphicFile'].NodeValue));
if Assigned(ReadmeFile) then ReadmeFile.AddNotifyObject(ReadmeRemoved);
if Assigned(GraphicFile) then GraphicFile.AddNotifyObject(GraphicRemoved);
FRegistryKeys.LoadXML(ARoot);
@ -429,8 +475,8 @@ procedure TPackageOptions.LoadIni(AIni: TIniFile);
begin
FileVersion := AIni.ReadString('Package', 'Version', '');
ExecuteProgram := AIni.ReadString('Package', 'ExecuteProgram', '');
ReadmeFile := FPackage.Files.FromFileName(AIni.ReadString('Package', 'ReadMeFile', ''));
GraphicFile := FPackage.Files.FromFileName(AIni.ReadString('Package', 'GraphicFile', ''));
ReadmeFile := Package.Files.FromFileName(AIni.ReadString('Package', 'ReadMeFile', ''));
GraphicFile := Package.Files.FromFileName(AIni.ReadString('Package', 'GraphicFile', ''));
if Assigned(ReadmeFile) then ReadmeFile.AddNotifyObject(ReadmeRemoved);
if Assigned(GraphicFile) then GraphicFile.AddNotifyObject(GraphicRemoved);
FRegistryKeys.LoadIni(AIni);
@ -466,7 +512,7 @@ begin
FGraphicFile := nil
else
begin
if Value.FPackage <> FPackage then raise EPackageInfo.CreateFmt(SGraphicNotOwnedCorrectly, [Value]);
if Value.Package <> Package then raise EPackageInfo.CreateFmt(SGraphicNotOwnedCorrectly, [Value]);
FGraphicFile := Value;
FGraphicFile.AddNotifyObject(GraphicRemoved);
end;
@ -479,7 +525,7 @@ begin
FReadmeFile := nil
else
begin
if Value.FPackage <> FPackage then raise EPackageInfo.CreateFmt(SReadmeNotOwnedCorrectly, [Value]);
if Value.Package <> Package then raise EPackageInfo.CreateFmt(SReadmeNotOwnedCorrectly, [Value]);
FReadmeFile := Value;
FReadmeFile.AddNotifyObject(ReadmeRemoved);
end;
@ -497,12 +543,6 @@ begin
FInfoType := Source.InfoType;
end;
constructor TPackageInfoEntry.Create(APackage: TPackage);
begin
inherited Create;
FPackage := APackage;
end;
procedure TPackageInfoEntry.SetDescription(Value: WideString);
begin
FDescription := Value;
@ -540,7 +580,7 @@ begin
for i := 0 to ARoot.ChildNodes.Count - 1 do
begin
ANode := ARoot.ChildNodes[i];
inf := TPackageInfoEntry.Create(FPackage);
inf := TPackageInfoEntry.Create(Package);
inf.Name := ANode.NodeName;
inf.Description := VarToWideStr(ANode.NodeValue);
inf.URL := VarToWideStr(ANode.Attributes['URL']);
@ -578,7 +618,7 @@ begin
description := CommaToken(t);
url := CommaToken(t);
inf := TPackageInfoEntry.Create(FPackage);
inf := TPackageInfoEntry.Create(Package);
inf.Name := s[i];
inf.Description := description;
inf.URL := url;
@ -623,7 +663,7 @@ begin
i := IndexOf(Name);
if i = -1 then
begin
inf := TPackageInfoEntry.Create(FPackage);
inf := TPackageInfoEntry.Create(Package);
inf.Name := Name;
Add(inf);
end
@ -640,7 +680,7 @@ begin
i := IndexOf(Name);
if i = -1 then
begin
inf := TPackageInfoEntry.Create(FPackage);
inf := TPackageInfoEntry.Create(Package);
inf.Name := Name;
Add(inf);
end
@ -658,12 +698,6 @@ begin
if WideLowerCase(Items[i].Name) = WideLowerCase(Name) then Result := i;
end;
constructor TPackageInfoEntryList.Create(APackage: TPackage);
begin
inherited Create;
FPackage := APackage;
end;
procedure TPackageInfoEntryList.Assign(Source: TPackageInfoEntryList);
var
i: Integer;
@ -672,7 +706,7 @@ begin
Clear;
for i := 0 to Source.Count - 1 do
begin
pie := TPackageInfoEntry.Create(FPackage);
pie := TPackageInfoEntry.Create(Package);
pie.Assign(Source[i]);
Add(pie);
end;
@ -691,12 +725,6 @@ begin
Location := Source.Location;
end;
constructor TPackageStartMenuEntry.Create(APackage: TPackage);
begin
inherited Create;
FPackage := APackage;
end;
{-------------------------------------------------------------------------------
- TPackageStartMenuEntryList -
------------------------------------------------------------------------------}
@ -722,7 +750,7 @@ begin
begin
with ANode.ChildNodes[i] do
begin
sme := TPackageStartMenuEntry.Create(FPackage);
sme := TPackageStartMenuEntry.Create(Package);
sme.Name := VarToWideStr(ChildNodes['Name'].NodeValue);
sme.Prog := VarToWideStr(ChildNodes['FileName'].NodeValue);
sme.Params := VarToWideStr(ChildNodes['Arguments'].NodeValue);
@ -766,7 +794,7 @@ begin
prog := CommaToken(t);
params := CommaToken(t);
sme := TPackageStartMenuEntry.Create(FPackage);
sme := TPackageStartMenuEntry.Create(Package);
sme.Name := s[i];
sme.Prog := prog;
sme.Params := params;
@ -785,12 +813,6 @@ begin
AIni.WriteString('StartMenuEntries', Items[i].Name, Format('"%s","%s"', [Items[i].Prog, Items[i].Params]));
end;
constructor TPackageStartMenuEntryList.Create(APackage: TPackage);
begin
inherited Create;
FPackage := APackage;
end;
procedure TPackageStartMenuEntryList.Assign(Source: TPackageStartMenuEntryList);
var
i: Integer;
@ -799,7 +821,7 @@ begin
Clear;
for i := 0 to Source.Count - 1 do
begin
psme := TPackageStartMenuEntry.Create(FPackage);
psme := TPackageStartMenuEntry.Create(Package);
psme.Assign(Source[i]);
Add(psme);
end;
@ -819,9 +841,8 @@ end;
constructor TPackageStartMenu.Create(APackage: TPackage);
begin
inherited Create;
FPackage := APackage;
Entries := TPackageStartMenuEntryList.Create(FPackage);
inherited Create(APackage);
Entries := TPackageStartMenuEntryList.Create(Package);
end;
destructor TPackageStartMenu.Destroy;
@ -879,15 +900,9 @@ begin
FFileType := Source.FileType;
end;
constructor TPackageContentFile.Create(APackage: TPackage);
begin
inherited Create;
FPackage := APackage;
end;
function TPackageContentFile.RelativeFileName: WideString;
begin
Result := ExtractRelativePath(FPackage.FileName, FFileName);
Result := ExtractRelativePath(Package.FileName, FFileName);
end;
procedure TPackageContentFile.SetCopyLocation(const Value: TPackageFileCopyLocation);
@ -946,7 +961,7 @@ begin
begin
with ANode.ChildNodes[i] do
begin
subfile := TPackageContentFile.Create(FPackage);
subfile := TPackageContentFile.Create(Package);
subfile.FileName := VarToWideStr(ChildNodes['Name'].NodeValue);
subfile.Description := VarToWideStr(ChildNodes['Description'].NodeValue);
subfile.FCopyLocation := TPackageFileCopyLocation(StrToIntDef(VarToWideStr(ChildNodes['Location'].NodeValue), 0));
@ -991,7 +1006,7 @@ begin
description := CommaToken(t);
filename := CommaToken(t);
copylocation := TPackageFileCopyLocation(StrToIntDef(CommaToken(t), 0));// CommaToken(t) = '1';
subfile := TPackageContentFile.Create(FPackage);
subfile := TPackageContentFile.Create(Package);
subfile.FileName := filename;
subfile.Description := description;
subfile.FCopyLocation := copylocation;
@ -1011,12 +1026,6 @@ begin
Items[i].FileName, Ord(Items[i].CopyLocation)]));
end;
constructor TPackageContentFileList.Create(APackage: TPackage);
begin
inherited Create;
FPackage := APackage;
end;
procedure TPackageContentFileList.Assign(Source: TPackageContentFileList);
var
i: Integer;
@ -1025,7 +1034,7 @@ begin
Clear;
for i := 0 to Source.Count - 1 do
begin
psf := TPackageContentFile.Create(FPackage);
psf := TPackageContentFile.Create(Package);
psf.Assign(Source[i]);
Add(psf);
end;
@ -1071,6 +1080,7 @@ begin
Options.Assign(Source.Options);
StartMenu.Assign(Source.StartMenu);
Info.Assign(Source.Info);
Keyboards.Assign(Source.Keyboards);
end;
constructor TPackage.Create;
@ -1080,6 +1090,8 @@ begin
if not Assigned(Options) then Options := TPackageOptions.Create(Self);
if not Assigned(StartMenu) then StartMenu := TPackageStartMenu.Create(Self);
if not Assigned(Info) then Info := TPackageInfoEntryList.Create(Self);
if not Assigned(Keyboards) then Keyboards := TPackageKeyboardList.Create(Self);
end;
destructor TPackage.Destroy;
@ -1088,6 +1100,7 @@ begin
Options.Free;
StartMenu.Free;
Info.Free;
Keyboards.Free;
inherited Destroy;
end;
@ -1111,6 +1124,7 @@ begin
Files.LoadIni(ini);
Options.LoadLegacy := FLoadLegacy;
Options.LoadIni(ini);
Keyboards.LoadIni(ini);
finally
ini.Free;
end;
@ -1208,6 +1222,7 @@ begin
Info.LoadXML(ARoot);
Files.LoadXML(ARoot);
Options.LoadXML(ARoot);
Keyboards.LoadXML(ARoot);
end;
procedure TPackage.DoSaveXML(ARoot: IXMLNode);
@ -1217,6 +1232,7 @@ begin
StartMenu.SaveXML(ARoot);
Info.SaveXML(ARoot);
Files.SaveXML(ARoot);
Keyboards.SaveXML(ARoot);
end;
procedure TPackage.SaveIni;
@ -1231,6 +1247,7 @@ begin
StartMenu.SaveIni(ini);
Info.SaveIni(ini);
Files.SaveIni(ini);
Keyboards.SaveIni(ini);
ini.UpdateFile;
finally
ini.Free;
@ -1284,20 +1301,20 @@ end;
{ TPackageBaseObject }
constructor TPackageBaseObject.Create;
constructor TPackageBaseNotifyObject.Create(APackage: TPackage);
begin
inherited Create;
inherited Create(APackage);
FNotifyObjects := TObjectList<TPackageNotifyEventWrapper>.Create;
end;
destructor TPackageBaseObject.Destroy;
destructor TPackageBaseNotifyObject.Destroy;
begin
Notify(netDestroy);
FNotifyObjects.Free;
inherited Destroy;
end;
function TPackageBaseObject.Notify(EventType: TPackageNotifyEventType): Boolean;
function TPackageBaseNotifyObject.Notify(EventType: TPackageNotifyEventType): Boolean;
var
i: Integer;
fAllow: Boolean;
@ -1310,7 +1327,7 @@ begin
Result := True;
end;
procedure TPackageBaseObject.AddNotifyObject(FEventHandler: TPackageNotifyEvent);
procedure TPackageBaseNotifyObject.AddNotifyObject(FEventHandler: TPackageNotifyEvent);
var
ev: TPackageNotifyEventWrapper;
begin
@ -1320,7 +1337,7 @@ begin
FNotifyObjects.Add(ev);
end;
procedure TPackageBaseObject.RemoveNotifyObject(FEventHandler: TPackageNotifyEvent);
procedure TPackageBaseNotifyObject.RemoveNotifyObject(FEventHandler: TPackageNotifyEvent);
var
i: Integer;
begin
@ -1332,6 +1349,14 @@ begin
end;
end;
{ TPackageBaseObject }
constructor TPackageBaseObject.Create(APackage: TPackage);
begin
inherited Create;
FPackage := APackage;
end;
{ TPackageRegistryKeyList }
procedure TPackageRegistryKeyList.Assign(Source: TPackageRegistryKeyList);
@ -1342,18 +1367,12 @@ begin
Clear;
for i := 0 to Source.Count - 1 do
begin
prk := TPackageRegistryKey.Create(FPackage);
prk := TPackageRegistryKey.Create(Package);
prk.Assign(Source[i]);
Add(prk);
end;
end;
constructor TPackageRegistryKeyList.Create(APackage: TPackage);
begin
inherited Create;
FPackage := APackage;
end;
procedure TPackageRegistryKeyList.LoadIni(AIni: TIniFile);
var
i: Integer;
@ -1371,7 +1390,7 @@ begin
AIni.ReadSectionValues('Registry', FValues);
for i := 0 to FValues.Count - 1 do
begin
pkr := TPackageRegistryKey.Create(FPackage);
pkr := TPackageRegistryKey.Create(Package);
name := FValues.Names[i];
value := FValues.ValueFromIndex[i];
@ -1436,7 +1455,7 @@ begin
for i := 0 to ANode.ChildNodes.Count - 1 do
begin
AKeyNode := ANode.ChildNodes[i];
pkr := TPackageRegistryKey.Create(FPackage);
pkr := TPackageRegistryKey.Create(Package);
name := VarToWideStr(AKeyNode.Attributes['Name']);
value := VarToWideStr(AKeyNode.Attributes['Value']);
@ -1501,8 +1520,7 @@ end;
constructor TPackageRegistryKey.Create(APackage: TPackage);
begin
inherited Create;
FPackage := APackage;
inherited Create(APackage);
FRoot := HKEY_CURRENT_USER;
FValueType := rkvtString;
end;
@ -1512,5 +1530,240 @@ begin
inherited Destroy;
end;
{ TPackageObjectList<T> }
constructor TPackageObjectList<T>.Create(APackage: TPackage);
begin
inherited Create;
FPackage := APackage;
end;
{ TPackageKeyboard }
procedure TPackageKeyboard.Assign(Source: TPackageKeyboard);
var
i: Integer;
FLanguage: TPackageKeyboardLanguage;
begin
FName := Source.Name;
FID := Source.ID;
FVersion := Source.Version;
if Assigned(Source.OSKFont)
then FOSKFont := Package.Files.FromFileNameEx(Source.OSKFont.FileName)
else FOSKFont := nil;
if Assigned(Source.DisplayFont)
then FDisplayFont := Package.Files.FromFileNameEx(Source.DisplayFont.FileName)
else FDisplayFont := nil;
FLanguages.Clear;
for i := 0 to Source.Languages.Count - 1 do
begin
FLanguage := TPackageKeyboardLanguage.Create(Package);
FLanguage.ID := Source.Languages[i].ID;
FLanguage.Name := Source.Languages[i].Name;
FLanguages.Add(FLanguage);
end;
end;
procedure TPackageKeyboard.SetDisplayFont(const Value: TPackageContentFile);
begin
if Assigned(FDisplayFont) then FDisplayFont.RemoveNotifyObject(DisplayFontRemoved);
if not Assigned(Value) then
FDisplayFont := nil
else
begin
if Value.Package <> Package then raise EPackageInfo.CreateFmt(SDisplayFontNotOwnedCorrectly, [Value]);
FDisplayFont := Value;
FDisplayFont.AddNotifyObject(DisplayFontRemoved);
end;
end;
constructor TPackageKeyboard.Create(APackage: TPackage);
begin
inherited Create(APackage);
FLanguages := TPackageKeyboardLanguageList.Create(APackage);
end;
destructor TPackageKeyboard.Destroy;
begin
FreeAndNil(FLanguages);
inherited Destroy;
end;
procedure TPackageKeyboard.DisplayFontRemoved(Sender: TObject;
EventType: TPackageNotifyEventType; var FAllow: Boolean);
begin
FDisplayFont := nil;
end;
procedure TPackageKeyboard.SetOSKFont(const Value: TPackageContentFile);
begin
if Assigned(FOSKFont) then FOSKFont.RemoveNotifyObject(OSKFontRemoved);
if not Assigned(Value) then
FOSKFont := nil
else
begin
if Value.Package <> Package then raise EPackageInfo.CreateFmt(SOSKFontNotOwnedCorrectly, [Value]);
FOSKFont := Value;
FOSKFont.AddNotifyObject(OSKFontRemoved);
end;
end;
procedure TPackageKeyboard.OSKFontRemoved(Sender: TObject;
EventType: TPackageNotifyEventType; var FAllow: Boolean);
begin
FOSKFont := nil;
end;
{ TPackageKeyboardList }
procedure TPackageKeyboardList.Assign(Source: TPackageKeyboardList);
var
i: Integer;
pk: TPackageKeyboard;
begin
Clear;
for i := 0 to Source.Count - 1 do
begin
pk := TPackageKeyboard.Create(Package);
pk.Assign(Source[i]);
Add(pk);
end;
end;
const
SPackageKeyboard_Name = 'Name';
SPackageKeyboard_ID = 'ID';
SPackageKeyboard_Version = 'Version';
SPackageKeyboard_OSKFont = 'OSKFont';
SPackageKeyboard_DisplayFont = 'DisplayFont';
SPackageKeyboard_Language = 'Language';
procedure TPackageKeyboardList.LoadIni(AIni: TIniFile);
var
s: TStringList;
ln: WideString;
i, j: Integer;
FSectionName: string;
keyboard: TPackageKeyboard;
FLanguage: TPackageKeyboardLanguage;
begin
Clear;
s := TStringList.Create;
try
AIni.ReadSections(s);
for i := 0 to MaxInt do
begin
FSectionName := 'Keyboard'+IntToStr(i);
if s.IndexOf(FSectionName) < 0 then
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, ''));
for j := 0 to MaxInt do
begin
ln := AIni.ReadString(FSectionName, SPackageKeyboard_Language+IntToStr(j), '');
if ln = '' then
Break;
FLanguage := TPackageKeyboardLanguage.Create(Package);
FLanguage.ID := CommaToken(ln);
FLanguage.Name := CommaToken(ln);
keyboard.Languages.Add(FLanguage);
end;
Add(keyboard);
end;
finally
s.Free;
end;
end;
procedure TPackageKeyboardList.LoadXML(ARoot: IXMLNode);
var
keyboard: TPackageKeyboard;
i, j: Integer;
ANode: IXMLNode;
FLanguage: TPackageKeyboardLanguage;
ln: WideString;
FSectionName: string;
begin
Clear;
for i := 0 to MaxInt do
begin
FSectionName := 'Keyboard'+IntToStr(i);
if ARoot.ChildNodes.IndexOf(FSectionName) < 0 then
Break;
ANode := ARoot.ChildNodes[FSectionName];
keyboard := TPackageKeyboard.Create(Package);
keyboard.Name := VarToStr(ANode.ChildValues[SPackageKeyboard_Name]);
keyboard.ID := VarToStr(ANode.ChildValues[SPackageKeyboard_ID]);
keyboard.Version := VarToStr(ANode.ChildValues[SPackageKeyboard_Version]);
keyboard.OSKFont := Package.Files.FromFileNameEx(VarToStr(ANode.ChildValues[SPackageKeyboard_OSKFont]));
keyboard.DisplayFont := Package.Files.FromFileNameEx(VarToStr(ANode.ChildValues[SPackageKeyboard_DisplayFont]));
for j := 0 to MaxInt do
begin
ln := VarToStr(ANode.ChildValues[SPackageKeyboard_Language+IntToStr(j)]);
if ln = '' then
Break;
FLanguage := TPackageKeyboardLanguage.Create(Package);
FLanguage.ID := CommaToken(ln);
FLanguage.Name := CommaToken(ln);
keyboard.Languages.Add(FLanguage);
end;
Add(keyboard);
end;
end;
procedure TPackageKeyboardList.SaveIni(AIni: TIniFile);
var
i, j: Integer;
FSectionName: string;
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);
if Assigned(Items[i].OSKFont) then
AIni.WriteString(FSectionName, SPackageKeyboard_OSKFont, ExtractFileName(Items[i].OSKFont.FileName));
if Assigned(Items[i].DisplayFont) then
AIni.WriteString(FSectionName, SPackageKeyboard_DisplayFont, ExtractFileName(Items[i].DisplayFont.FileName));
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);
end;
end;
end;
procedure TPackageKeyboardList.SaveXML(ARoot: IXMLNode);
var
i, j: Integer;
begin
for i := 0 to Count - 1 do
begin
with ARoot.AddChild('Keyboard'+IntToStr(i)) do
begin
ChildNodes[SPackageKeyboard_Name].NodeValue := Items[i].Name;
ChildNodes[SPackageKeyboard_ID].NodeValue := Items[i].ID;
ChildNodes[SPackageKeyboard_Version].NodeValue := Items[i].Version;
if Assigned(Items[i].OSKFont) then
ChildNodes[SPackageKeyboard_OSKFont].NodeValue := ExtractFileName(Items[i].OSKFont.FileName);
if Assigned(Items[i].DisplayFont) then
ChildNodes[SPackageKeyboard_DisplayFont].NodeValue := ExtractFileName(Items[i].DisplayFont.FileName);
for j := 0 to Items[i].Languages.Count - 1 do
ChildNodes[SPackageKeyboard_Language+IntToStr(j)].NodeValue := Items[i].Languages[j].ID+','+Items[i].Languages[j].Name;
end;
end;
end;
end.

View file

@ -162,6 +162,11 @@ begin
//if LowerCase(AIni.ReadString('Install', 'StartMenuReadme', '')) = 'true' then -- already in [StartMenu]
Options.ReadmeFile := Files.FromFileName(AIni.ReadString('Install', 'ReadmeFile', ''));
Options.ExecuteProgram := AIni.ReadString('Install', 'ExecuteProgram', '');
// TODO
// Also remember to update version number if source files change
// Also do not permit different versions of same keyboard in compiled form!
finally
str.Free;
end;

View file

@ -0,0 +1,27 @@
#
# Unit Tests Makefile.
#
# ----------------------------------------------------------------------
TARGETS=package-info
CLEAN=package-info
test:
$(MAKE) -DTARGET=test $(TARGETS)
!include ..\Header.mak
# ----------------------------------------------------------------------
package-info:
cd $(ROOT)\src\unit-tests\package-info
$(MAKE) $(TARGET)
# ----------------------------------------------------------------------
!include ..\Target.mak
# ----------------------------------------------------------------------
# EOF
# ----------------------------------------------------------------------

View file

@ -0,0 +1,2 @@
test/*.out.*
Win32

View file

@ -0,0 +1,18 @@
#
# Test the PackageInfo file format read and write - xml and inf
#
!include ..\..\Defines.mak
test: build
Win32\Debug\packageinfotestsuite.exe -b
build:
$(DELPHI_MSBUILD) /p:CI=CI packageinfotestsuite.dproj
clean: def-clean
-rd /s/q Win32
-del dunitx-results.xml
-del test\*.out.*
!include ..\..\Target.mak

View file

@ -0,0 +1,259 @@
unit PackageInfoTest;
interface
uses
DUnitX.TestFramework,
PackageInfo,
kpsfile;
type
[TestFixture]
TPackageInfoTest = class(TObject)
private
DataPath: string;
procedure DoCompare(f1, f2: string);
procedure DoCompareKpsFiles(f1, f2: string; k1, k2: TKpsFile);
public
[Setup]
procedure Setup;
[TearDown]
procedure TearDown;
[Test]
procedure TestXMLInOut;
[Test]
procedure TestRoundTrip;
[Test]
procedure TestRoundTripInf;
[Test]
procedure TestInfInOut;
[Test]
procedure TestAssign;
end;
implementation
uses
System.Classes,
System.SysUtils,
System.Win.ComObj,
Winapi.ActiveX,
Xml.XmlDoc,
Xml.XmlIntf;
procedure TPackageInfoTest.Setup;
begin
CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
DataPath := ExtractFilePath(ParamStr(0)) + '..\..\test\';
end;
procedure TPackageInfoTest.TearDown;
begin
CoUninitialize;
end;
procedure TPackageInfoTest.TestAssign;
var
p1, p2: TPackage;
begin
p1 := TKpsFile.Create;
p2 := TKpsFile.Create;
try
p1.FileName := DataPath + 'test1.xml';
p1.LoadXML;
p2.Assign(p1);
p2.FileName := DataPath + 'testAssign.out.xml';
p2.SaveXML;
finally
p1.Free;
p2.Free;
end;
DoCompare(DataPath + 'test1.xml', DataPath + 'testAssign.out.xml');
end;
procedure TPackageInfoTest.TestInfInOut;
var
p1: TPackage;
begin
p1 := TKpsFile.Create;
try
p1.FileName := DataPath + 'test1.inf';
p1.LoadIni;
p1.FileName := DataPath + 'test1.out.inf';
p1.SaveIni;
finally
p1.Free;
end;
DoCompare(DataPath + 'test1.inf', DataPath + 'test1.out.inf');
end;
procedure TPackageInfoTest.TestRoundTrip;
var
p1: TPackage;
begin
p1 := TKpsFile.Create;
try
p1.FileName := DataPath + 'test1.xml';
p1.LoadXML;
p1.FileName := DataPath + 'test1.out.inf';
p1.SaveIni;
finally
p1.Free;
end;
p1 := TKpsFile.Create;
try
p1.FileName := DataPath + 'test1.out.inf';
p1.LoadIni;
p1.FileName := DataPath + 'test1.out.xml';
p1.SaveXML;
finally
p1.Free;
end;
DoCompare(DataPath + 'test1.xml', DataPath + 'test1.out.xml');
end;
procedure TPackageInfoTest.TestRoundTripInf;
var
p1: TPackage;
begin
p1 := TKpsFile.Create;
try
p1.FileName := DataPath + 'test1.inf';
p1.LoadIni;
p1.FileName := DataPath + 'test1.out.xml';
p1.SaveXML;
finally
p1.Free;
end;
p1 := TKpsFile.Create;
try
p1.FileName := DataPath + 'test1.out.xml';
p1.LoadXML;
p1.FileName := DataPath + 'test1.out.inf';
p1.SaveIni;
finally
p1.Free;
end;
DoCompare(DataPath + 'test1.inf', DataPath + 'test1.out.inf');
end;
procedure TPackageInfoTest.TestXMLInOut;
var
p1: TPackage;
begin
p1 := TKpsFile.Create;
try
p1.FileName := DataPath + 'test1.xml';
p1.LoadXML;
p1.FileName := DataPath + 'test1.out.xml';
p1.SaveXML;
finally
p1.Free;
end;
DoCompare(DataPath + 'test1.xml', DataPath + 'test1.out.xml');
end;
procedure TPackageInfoTest.DoCompare(f1, f2: string);
var
k1, k2: TKpsFile;
begin
k1 := TKpsFile.Create;
k2 := TKpsFile.Create;
try
k1.FileName := f1;
if SameText(ExtractFileExt(f1), '.xml')
then k1.LoadXml
else k1.LoadIni;
k2.FileName := f2;
if SameText(ExtractFileExt(f2), '.xml')
then k2.LoadXml
else k2.LoadIni;
DoCompareKpsFiles(f1, f2, k1, k2);
finally
k1.Free;
k2.Free;
end;
end;
procedure TPackageInfoTest.DoCompareKpsFiles(f1, f2: string; k1, k2: TKpsFile);
var
i: Integer;
t: TPackageInfoEntryType;
begin
Assert.AreEqual(k1.Options.FileVersion, k2.Options.FileVersion);
Assert.AreEqual(k1.Options.ExecuteProgram, k2.Options.ExecuteProgram);
Assert.IsTrue(
(
Assigned(k1.Options.ReadmeFile) and
Assigned(k2.Options.ReadmeFile) and
(k1.Options.ReadmeFile.FileName = k2.Options.ReadmeFile.FileName)
) or (
not Assigned(k1.Options.ReadmeFile) and
not Assigned(k2.Options.ReadmeFile)
),
'ReadmeFile does not match for '+f1+','+f2);
Assert.IsTrue(
(
Assigned(k1.Options.GraphicFile) and
Assigned(k2.Options.GraphicFile) and
(k1.Options.GraphicFile.FileName = k2.Options.GraphicFile.FileName)
) or (
not Assigned(k1.Options.GraphicFile) and
not Assigned(k2.Options.GraphicFile)
),
'GraphicFile does not match for '+f1+','+f2);
Assert.AreEqual(k1.Files.Count, k2.Files.Count);
for i := 0 to k1.Files.Count - 1 do
begin
Assert.AreEqual(k1.Files[i].FileName, k2.Files.FromFileNameEx(k1.Files[i].FileName).FileName);
Assert.AreEqual(k1.Files[i].Description, k2.Files.FromFileNameEx(k1.Files[i].FileName).Description);
end;
for t := Low(TPackageInfoEntryType) to High(TPackageInfoEntryType) do
begin
Assert.AreEqual(k1.Info.Desc[PackageInfoEntryTypeNames[t]], k2.Info.Desc[PackageInfoEntryTypeNames[t]]);
Assert.AreEqual(k1.Info.URL[PackageInfoEntryTypeNames[t]], k2.Info.URL[PackageInfoEntryTypeNames[t]]);
end;
Assert.AreEqual(k1.Keyboards.Count, k2.Keyboards.Count);
for i := 0 to k1.Keyboards.Count - 1 do
begin
Assert.AreEqual(k1.Keyboards[i].Name, k2.Keyboards[i].Name);
Assert.AreEqual(k1.Keyboards[i].ID, k2.Keyboards[i].ID);
Assert.AreEqual(k1.Keyboards[i].Version, k2.Keyboards[i].Version);
Assert.IsTrue(
(
Assigned(k1.Keyboards[i].OSKFont) and
Assigned(k2.Keyboards[i].OSKFont) and
(k1.Keyboards[i].OSKFont.FileName = k2.Keyboards[i].OSKFont.FileName)
) or (
not Assigned(k1.Keyboards[i].OSKFont) and
not Assigned(k2.Keyboards[i].OSKFont)
)
);
end;
end;
initialization
TDUnitX.RegisterTestFixture(TPackageInfoTest);
end.

View file

@ -0,0 +1,75 @@
program PackageInfoTestSuite;
{$IFNDEF TESTINSIGHT}
{$APPTYPE CONSOLE}
{$ENDIF}{$STRONGLINKTYPES ON}
uses
System.SysUtils,
{$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',
StockFileNames in '..\..\global\delphi\cust\StockFileNames.pas',
Unicode in '..\..\global\delphi\general\Unicode.pas',
KeymanVersion in '..\..\global\delphi\general\KeymanVersion.pas',
VersionInfo in '..\..\global\delphi\general\VersionInfo.pas',
utilsystem in '..\..\global\delphi\general\utilsystem.pas',
utilexecute in '..\..\global\delphi\general\utilexecute.pas',
utildir in '..\..\global\delphi\general\utildir.pas',
RegistryKeys in '..\..\global\delphi\general\RegistryKeys.pas',
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';
var
runner : ITestRunner;
results : IRunResults;
logger : ITestLogger;
nunitLogger : ITestLogger;
begin
{$IFDEF TESTINSIGHT}
TestInsight.DUnitX.RunRegisteredTests;
exit;
{$ENDIF}
try
//Check command line options, will exit if invalid
TDUnitX.CheckCommandLine;
//Create the test runner
runner := TDUnitX.CreateRunner;
//Tell the runner to use RTTI to find Fixtures
runner.UseRTTI := True;
//tell the runner how we will log things
//Log to the console window
logger := TDUnitXConsoleLogger.Create(true);
runner.AddLogger(logger);
//Generate an NUnit compatible XML File
nunitLogger := TDUnitXXMLNUnitFileLogger.Create(TDUnitX.Options.XMLOutputFile);
runner.AddLogger(nunitLogger);
runner.FailsOnNoAsserts := False; //When true, Assertions must be made during tests;
//Run tests
results := runner.Execute;
if not results.AllPassed then
System.ExitCode := EXIT_ERRORS;
{$IFNDEF CI}
//We don't want this happening when running under CI.
if TDUnitX.Options.ExitBehavior = TDUnitXExitBehavior.Pause then
begin
System.Write('Done.. press <Enter> key to quit.');
System.Readln;
end;
{$ENDIF}
except
on E: Exception do
System.Writeln(E.ClassName, ': ', E.Message);
end;
end.

View file

@ -0,0 +1,527 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{D450A640-6394-4474-BBBA-69C83A571086}</ProjectGuid>
<ProjectVersion>18.2</ProjectVersion>
<FrameworkType>None</FrameworkType>
<MainSource>PackageInfoTestSuite.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Console</AppType>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
<Base_Win64>true</Base_Win64>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
<Cfg_1_Win32>true</Cfg_1_Win32>
<CfgParent>Cfg_1</CfgParent>
<Cfg_1>true</Cfg_1>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<DCC_E>false</DCC_E>
<DCC_N>false</DCC_N>
<DCC_S>false</DCC_S>
<DCC_F>false</DCC_F>
<DCC_K>false</DCC_K>
<DCC_UsePackage>RESTComponents;FireDAC;FireDACSqliteDriver;soaprtl;FireDACIBDriver;soapmidas;FireDACCommon;RESTBackendComponents;soapserver;CloudService;FireDACCommonDriver;inet;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
<UsingDelphiRTL>true</UsingDelphiRTL>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
<DCC_UnitSearchPath>$(DUnitX);$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<SanitizedProjectName>PackageInfoTestSuite</SanitizedProjectName>
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
<DCC_Define>$(CI);$(USE_PLUSMEMO);$(DCC_Define)</DCC_Define>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_UsePackage>DBXSqliteDriver;bindcompdbx;IndyIPCommon;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;svnui;mbColorLibD10;dsnapcon;FireDACADSDriver;scFontCombo;DCPdelphi2009;FireDACMSAccDriver;fmxFireDAC;vclimg;Jcl;vcltouch;JvCore;vcldb;bindcompfmx;svn;FireDACPgDriver;inetdb;DbxCommonDriver;fmx;fmxdae;xmlrtl;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;IndyIPClient;bindcompvcl;EmbeddedWebBrowser_XE;VCLRESTComponents;dbxcds;VclSmp;JvDocking;adortl;JclVcl;vclie;bindengine;DBXMySQLDriver;dsnapxml;FireDACMySQLDriver;dbrtl;inetdbxpress;IndyProtocols;keyman_components;FireDACCommonODBC;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<VerInfo_Locale>1033</VerInfo_Locale>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>DBXSqliteDriver;bindcompdbx;IndyIPCommon;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;vclFireDAC;IndySystem;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;Jcl;vcltouch;vcldb;bindcompfmx;FireDACPgDriver;inetdb;DbxCommonDriver;fmx;fmxdae;xmlrtl;fmxobj;vclwinx;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;IndyIPClient;bindcompvcl;VCLRESTComponents;dbxcds;VclSmp;adortl;JclVcl;vclie;bindengine;DBXMySQLDriver;dsnapxml;FireDACMySQLDriver;dbrtl;inetdbxpress;IndyProtocols;FireDACCommonODBC;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
<DCC_DebugDCUs>true</DCC_DebugDCUs>
<DCC_Optimize>false</DCC_Optimize>
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<DCC_RemoteDebug>true</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<DCC_RemoteDebug>false</DCC_RemoteDebug>
<VerInfo_Locale>1033</VerInfo_Locale>
<Manifest_File>(None)</Manifest_File>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
<DCC_DebugInformation>0</DCC_DebugInformation>
</PropertyGroup>
<ItemGroup>
<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="PackageInfoTest.pas"/>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>Console</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality>
<Source>
<Source Name="MainSource">PackageInfoTestSuite.dpr</Source>
</Source>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k250.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp250.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="3">
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="OSX32">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libPCRE.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgsqlite3.dylib" Class="DependencyModule">
<Platform Name="OSX32">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="Win32\Debug\PackageInfoTestSuite.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>PackageInfoTestSuite.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="AdditionalDebugSymbols">
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidClassesDexFile">
<Platform Name="Android">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidGDBServer">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeArmeabiFile">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeMipsFile">
<Platform Name="Android">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashImageDef">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStyles">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_DefaultAppIcon">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon144">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage426">
<Platform Name="Android">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage470">
<Platform Name="Android">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage640">
<Platform Name="Android">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage960">
<Platform Name="Android">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DebugSymbols">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyFramework">
<Platform Name="OSX32">
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyModule">
<Platform Name="OSX32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="DependencyPackage">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="File">
<Platform Name="Android">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>0</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>0</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1024">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1536">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch768">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch320">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640x1136">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceResourceRules"/>
<DeployClass Name="ProjectiOSEntitlements"/>
<DeployClass Name="ProjectiOSInfoPList"/>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXEntitlements"/>
<DeployClass Name="ProjectOSXInfoPList"/>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
</Deployment>
<Platforms>
<Platform value="Win32">True</Platform>
<Platform value="Win64">False</Platform>
</Platforms>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
</Project>

View file

@ -0,0 +1,62 @@
[Package]
Version=7.0
ExecuteProgram=
ReadMeFile=readme.htm
GraphicFile=sideimage.bmp
[StartMenu]
Path=GFF Amharic Keyboard
Create=1
AddUninstallEntry=1
[StartMenuEntries]
Welcome="..\..\..\gff\gff_amh_7\source\welcome.htm",""
Amharic Keyboard Manual (Amharic)="AmharicTyping-Amharic.pdf",""
Amharic Keyboard Manual (English)="AmharicTyping-English.pdf",""
OFL (Abyssinica SIL Licence)="OFL.txt",""
GPL (WashRa + Free Serif Licence)="GNU-GPLv2.txt",""
[Info]
WebSite="http://keyboards.ethiopic.org","http://keyboards.ethiopic.org"
Version="8.0.0",""
Name="GFF Amharic Keyboard",""
Copyright="Creative Commons Attribution 3.0",""
Author="The Ge'ez Frontier Foundation","mailto:keyboards@ethiopic.org"
[Files]
0="File readme.htm","readme.htm",0
1="File sideimage.bmp","sideimage.bmp",0
2="File AmharicTyping-Amharic.pdf","..\..\..\gff\gff_amh_7\source\AmharicTyping-Amharic.pdf",0
3="File AmharicTyping-English.pdf","..\..\..\gff\gff_amh_7\source\AmharicTyping-English.pdf",0
4="File OFL.txt","..\..\..\shared\fonts\geez\OFL.txt",0
5="File GNU-GPLv2.txt","..\..\..\shared\fonts\geez\GNU-GPLv2.txt",0
6="File Welcome.htm","..\..\..\gff\gff_amh_7\source\welcome.htm",0
7="Font Abyssinica SIL","..\..\..\shared\fonts\geez\AbyssinicaSIL-R.ttf",0
8="Font Ethiopic Fantuwua","..\..\..\shared\fonts\geez\fantuwua.ttf",0
9="Font Free Serif","..\..\..\shared\fonts\geez\FreeSerif.otf",0
10="Font Ethiopic Yigezu Bisrat Goffer","..\..\..\shared\fonts\geez\goffer.ttf",0
11="Font Ethiopic Hiwua","..\..\..\shared\fonts\geez\hiwua.ttf",0
12="Font Ethiopia Jiret","..\..\..\shared\fonts\geez\jiret.ttf",0
13="Font Ethiopia Jiret Slant","..\..\..\shared\fonts\geez\jiretsl.ttf",0
14="Font Ethiopic Tint","..\..\..\shared\fonts\geez\tint.ttf",0
15="Font Ethiopic WashRa Bold","..\..\..\shared\fonts\geez\washrab.ttf",0
16="Font Ethiopic WashRa Bold Slant","..\..\..\shared\fonts\geez\washrabsl.ttf",0
17="Font Ethiopic WashRa SemiBold","..\..\..\shared\fonts\geez\washrasb.ttf",0
18="Font Ethiopic WashRa SemiBold Slant","..\..\..\shared\fonts\geez\washrasbsl.ttf",0
19="Font Ethiopic Wookianos","..\..\..\shared\fonts\geez\wookianos.ttf",0
20="Font Ethiopic Yebse","..\..\..\shared\fonts\geez\yebse.ttf",0
21="File gff_amh_7.kvk","..\..\..\gff\gff_amh_7\build\gff_amh_7.kvk",0
22="Keyboard Amharic","..\..\..\gff\gff_amh_7\build\gff_amh_7.kmx",0
23="File gff_ethiopic_7.kvk","..\..\..\gff\gff_ethiopic_7\build\gff_ethiopic_7.kvk",0
24="Keyboard Ethiopic - (Language Neutral)","..\..\..\gff\gff_ethiopic_7\build\gff_ethiopic_7.kmx",0
[Keyboard0]
Name=Amharic
ID=gff_amh_7
Version=8.0
OSKFont=wookianos.ttf
DisplayFont=fantuwua.ttf
Language0=amh,Amharic
Language1=gez,Ge'ez
[Keyboard1]
Name=Ethiopic Language Neutral
ID=gff_ethiopic_7
Version=8.0
Language0=gez,Ge'ez

File diff suppressed because one or more lines are too long