mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-07 01:15:33 +00:00
362 lines
9.7 KiB
ObjectPascal
362 lines
9.7 KiB
ObjectPascal
(*
|
|
Name: kmxfileutils
|
|
Copyright: Copyright (C) SIL International.
|
|
Documentation:
|
|
Description:
|
|
Create Date: 27 Mar 2008
|
|
|
|
Modified Date: 27 Aug 2012
|
|
Authors: mcdurdin
|
|
Related Files:
|
|
Dependencies:
|
|
|
|
Bugs:
|
|
Todo:
|
|
Notes:
|
|
History: 27 Mar 2008 - mcdurdin - Initial version
|
|
22 Mar 2010 - mcdurdin - I2243 - Support for nul in LHS of rule
|
|
27 Aug 2012 - mcdurdin - I3442 - V9.0 - Update xstring utils in Delphi to support v8 and v9
|
|
*)
|
|
unit kmxfileutils;
|
|
|
|
interface
|
|
|
|
uses
|
|
Winapi.Windows,
|
|
|
|
kmxfile;
|
|
|
|
// Sentinel code is similar to that found in CompileKeymanWeb.pas, but here is working
|
|
// with a compiled keyboard rather than with the intermediate obj that CompileKeymanWeb
|
|
// version works with.
|
|
//
|
|
// TODO: A refactor in the future may be worthwhile to consolidate these two sentinel
|
|
// processors. I have not done it at present because it introduces risk in the
|
|
// web compiler for minimal direct benefit.
|
|
|
|
type
|
|
TSentinelRecordAny = record
|
|
StoreIndex: Integer;
|
|
Store: PKeyboardFileStore;
|
|
end;
|
|
|
|
TSentinelRecordIndex = record
|
|
StoreIndex: Integer;
|
|
Store: PKeyboardFileStore;
|
|
Index: Integer;
|
|
end;
|
|
|
|
TSentinelRecordContextEx = record
|
|
Index: Integer;
|
|
end;
|
|
|
|
TSentinelRecordDeadkey = record
|
|
DeadKey: Integer;
|
|
end;
|
|
|
|
TSentinelRecordUse = record
|
|
GroupIndex: Integer;
|
|
Group: PKeyboardFileGroup;
|
|
end;
|
|
|
|
TSentinelRecordCall = record
|
|
StoreIndex: Integer;
|
|
Store: PKeyboardFileStore;
|
|
end;
|
|
|
|
TSentinelRecordIfOpt = record
|
|
StoreIndex1: Integer;
|
|
Store1: PKeyboardFileStore;
|
|
StoreIndex2: Integer;
|
|
Store2: PKeyboardFileStore;
|
|
IsNot: Integer;
|
|
end;
|
|
|
|
TSentinelRecordSetOpt = record
|
|
StoreIndex1: Integer;
|
|
Store1: PKeyboardFileStore;
|
|
StoreIndex2: Integer;
|
|
Store2: PKeyboardFileStore;
|
|
end;
|
|
|
|
TSentinelRecordResetOpt = record
|
|
StoreIndex: Integer;
|
|
Store: PKeyboardFileStore;
|
|
end;
|
|
|
|
TSentinelRecordSaveOpt = record
|
|
StoreIndex: Integer;
|
|
Store: PKeyboardFileStore;
|
|
end;
|
|
|
|
TSentinelRecordIfSystemStore = record
|
|
dwSystemID: DWORD;
|
|
SystemStore: PKeyboardFileStore;
|
|
StoreIndex: Integer;
|
|
Store: PKeyboardFileStore;
|
|
IsNot: Integer;
|
|
end;
|
|
|
|
TSentinelRecordSetSystemStore = record
|
|
dwSystemID: DWORD;
|
|
SystemStore: PKeyboardFileStore;
|
|
StoreIndex: Integer;
|
|
Store: PKeyboardFileStore;
|
|
end;
|
|
|
|
TSentinelRecord = record
|
|
IsSentinel: Boolean;
|
|
Code: Integer;
|
|
Any: TSentinelRecordAny;
|
|
Index: TSentinelRecordIndex;
|
|
Deadkey: TSentinelRecordDeadkey;
|
|
Use: TSentinelRecordUse;
|
|
Call: TSentinelRecordCall;
|
|
ContextEx: TSentinelRecordContextEx;
|
|
IfOpt: TSentinelRecordIfOpt;
|
|
IfSystemStore: TSentinelRecordIfSystemStore;
|
|
SetOpt: TSentinelRecordSetOpt;
|
|
SetSystemStore: TSentinelRecordSetSystemStore;
|
|
ResetOpt: TSentinelRecordResetOpt;
|
|
SaveOpt: TSentinelRecordSaveOpt;
|
|
ChrVal: DWord;
|
|
end;
|
|
|
|
function incxstr(p: PWideChar): PWideChar;
|
|
function xstrlen(p: PWideChar): Integer;
|
|
function xstrlen_printing(p: PWideChar): Integer;
|
|
function GetSuppChar(p: PWideChar): DWord;
|
|
function ExpandSentinel(
|
|
pwsz: PWideChar; fk: PKeyboardFileHeader): TSentinelRecord;
|
|
|
|
implementation
|
|
|
|
uses
|
|
kmxfileconsts,
|
|
Unicode;
|
|
|
|
function incxstr(p: PWideChar): PWideChar;
|
|
begin
|
|
Result := p;
|
|
if Result^ = #0 then Exit;
|
|
|
|
if PWord(Result)^ <> UC_SENTINEL then
|
|
begin
|
|
if (PWord(Result)^ >= $D800) and (PWord(Result)^ <= $DBFF) then
|
|
begin
|
|
Inc(Result);
|
|
if (PWord(Result)^ >= $DC00) and (PWord(Result)^ <= $DFFF) then Inc(Result);
|
|
end
|
|
else Inc(Result);
|
|
Exit;
|
|
end;
|
|
|
|
Inc(Result);
|
|
|
|
case PWord(Result)^ of
|
|
CODE_ANY: Inc(Result, 2);
|
|
CODE_INDEX: Inc(Result, 3);
|
|
CODE_USE: Inc(Result, 2);
|
|
CODE_DEADKEY: Inc(Result, 2);
|
|
CODE_EXTENDED: begin Inc(Result, 3); while (PWord(Result)^ <> UC_SENTINEL_EXTENDEDEND) and (Result^ <> #0) do Inc(Result); Inc(Result); end;
|
|
CODE_CALL: Inc(Result, 2);
|
|
CODE_CONTEXTEX: Inc(Result, 2);
|
|
CODE_NOTANY: Inc(Result, 2);
|
|
|
|
CODE_CLEARCONTEXT: Inc(Result, 2); // I3442
|
|
CODE_IFOPT: Inc(Result, 4); // I3442
|
|
CODE_IFSYSTEMSTORE: Inc(Result, 4); // I3442
|
|
CODE_SETOPT: Inc(Result, 3); // I3442
|
|
CODE_SETSYSTEMSTORE: Inc(Result, 3); // I3442
|
|
CODE_RESETOPT: Inc(Result, 2); // I3442
|
|
CODE_SAVEOPT: Inc(Result, 2); // I3442
|
|
|
|
else Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
function xstrlen(p: PWideChar): Integer;
|
|
begin
|
|
Result := 0;
|
|
while p^ <> #0 do
|
|
begin
|
|
p := incxstr(p);
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
function xstrlen_printing(p: PWideChar): Integer;
|
|
var
|
|
q: PWideChar;
|
|
begin
|
|
Result := 0;
|
|
while p^ <> #0 do
|
|
begin
|
|
if PWord(p)^ = UC_SENTINEL then
|
|
begin
|
|
q := p;
|
|
Inc(q);
|
|
case PWord(q)^ of // I3442
|
|
CODE_DEADKEY,
|
|
CODE_NUL,
|
|
CODE_IFOPT,
|
|
CODE_IFSYSTEMSTORE:
|
|
Dec(Result);
|
|
end;
|
|
end;
|
|
p := incxstr(p);
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
function GetSuppChar(p: PWideChar): DWord;
|
|
var
|
|
ch1: WideChar;
|
|
begin
|
|
Result := Ord(p^);
|
|
if Uni_IsSurrogate1(p^) then
|
|
begin
|
|
ch1 := p^;
|
|
Inc(p);
|
|
if Uni_IsSurrogate2(p^) then
|
|
Result := Uni_SurrogateToUTF32(ch1, p^);
|
|
end;
|
|
end;
|
|
|
|
function ExpandSentinel(
|
|
pwsz: PWideChar; fk: PKeyboardFileHeader): TSentinelRecord;
|
|
var
|
|
i: Integer;
|
|
Found: Boolean;
|
|
function BaseMem(dp: DWord): PByte;
|
|
begin
|
|
Result := PByte(fk);
|
|
Inc(Result, dp);
|
|
end;
|
|
function BaseStore(dp: DWord; n: DWord): PKeyboardFileStore;
|
|
begin
|
|
Result := PKeyboardFileStore(BaseMem(dp));
|
|
Inc(Result, n);
|
|
end;
|
|
function BaseGroup(dp: DWord; n: DWord): PKeyboardFileGroup;
|
|
begin
|
|
Result := PKeyboardFileGroup(BaseMem(dp));
|
|
Inc(Result, n);
|
|
end;
|
|
|
|
begin
|
|
FillChar(Result, SizeOf(Result), 0);
|
|
if Ord(pwsz^) = UC_SENTINEL then
|
|
begin
|
|
Result.IsSentinel := True;
|
|
Inc(pwsz);
|
|
Result.Code := Ord(pwsz^);
|
|
Inc(pwsz);
|
|
case Result.Code of
|
|
CODE_ANY, CODE_NOTANY: // I3981
|
|
begin
|
|
Result.Any.StoreIndex := Ord(pwsz^) - 1;
|
|
Result.Any.Store := BaseStore(fk.dpStoreArray, Result.Any.StoreIndex);
|
|
end;
|
|
CODE_INDEX:
|
|
begin
|
|
Result.Index.StoreIndex := Ord(pwsz^) - 1;
|
|
Result.Index.Store := BaseStore(fk.dpStoreArray, Result.Index.StoreIndex);
|
|
Inc(pwsz);
|
|
Result.Index.Index := Ord(pwsz^);
|
|
end;
|
|
CODE_DEADKEY:
|
|
Result.DeadKey.DeadKey := Ord(pwsz^) - 1;
|
|
CODE_USE:
|
|
begin
|
|
Result.Use.GroupIndex := Ord(pwsz^) - 1;
|
|
Result.Use.Group := BaseGroup(fk.dpGroupArray, Result.Use.GroupIndex);
|
|
end;
|
|
CODE_CALL:
|
|
begin
|
|
Result.Call.StoreIndex := Ord(pwsz^) - 1;
|
|
Result.Call.Store := BaseStore(fk.dpStoreArray, Result.Call.StoreIndex);
|
|
end;
|
|
CODE_CONTEXTEX:
|
|
Result.ContextEx.Index := Ord(pwsz^);
|
|
CODE_SETOPT: // I3429
|
|
begin
|
|
Result.SetOpt.StoreIndex1 := Ord(pwsz^) - 1;
|
|
Result.SetOpt.Store1 := BaseStore(fk.dpStoreArray, Result.SetOpt.StoreIndex1);
|
|
Inc(pwsz);
|
|
Result.SetOpt.StoreIndex2 := Ord(pwsz^) - 1;
|
|
Result.SetOpt.Store2 := BaseStore(fk.dpStoreArray, Result.SetOpt.StoreIndex2);
|
|
end;
|
|
CODE_SETSYSTEMSTORE: // I3437
|
|
begin
|
|
Result.SetSystemStore.dwSystemID := Ord(pwsz^) - 1;
|
|
Result.SetSystemStore.SystemStore := BaseStore(fk.dpStoreArray, 0);
|
|
Found := False;
|
|
|
|
for i := 0 to fk.cxStoreArray - 1 do
|
|
begin
|
|
if Result.SetSystemStore.SystemStore.dwSystemID = Result.SetSystemStore.dwSystemID then
|
|
begin
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
Inc(Result.SetSystemStore.SystemStore);
|
|
end;
|
|
|
|
if not Found then Result.SetSystemStore.SystemStore := nil;
|
|
|
|
Inc(pwsz);
|
|
Result.SetSystemStore.StoreIndex := Ord(pwsz^) - 1;
|
|
Result.SetSystemStore.Store := BaseStore(fk.dpStoreArray, Result.SetSystemStore.StoreIndex);
|
|
end;
|
|
CODE_RESETOPT: // I3429
|
|
begin
|
|
Result.ResetOpt.StoreIndex := Ord(pwsz^) - 1;
|
|
Result.ResetOpt.Store := BaseStore(fk.dpStoreArray, Result.ResetOpt.StoreIndex);
|
|
end;
|
|
CODE_SAVEOPT: // I3429
|
|
begin
|
|
Result.SaveOpt.StoreIndex := Ord(pwsz^) - 1;
|
|
Result.SaveOpt.Store := BaseStore(fk.dpStoreArray, Result.SaveOpt.StoreIndex);
|
|
end;
|
|
CODE_IFOPT: // I3429
|
|
begin
|
|
Result.IfOpt.StoreIndex1 := Ord(pwsz^) - 1;
|
|
Result.IfOpt.Store1 := BaseStore(fk.dpStoreArray, Result.IfOpt.StoreIndex1);
|
|
Inc(pwsz);
|
|
Result.IfOpt.IsNot := Ord(pwsz^) - 1; // I3429
|
|
Inc(pwsz);
|
|
Result.IfOpt.StoreIndex2 := Ord(pwsz^) - 1;
|
|
Result.IfOpt.Store2 := BaseStore(fk.dpStoreArray, Result.IfOpt.StoreIndex2);
|
|
end;
|
|
CODE_IFSYSTEMSTORE: // I3430
|
|
begin
|
|
Result.IfSystemStore.dwSystemID := Ord(pwsz^) - 1;
|
|
Result.IfSystemStore.SystemStore := BaseStore(fk.dpStoreArray, 0);
|
|
|
|
Found := False;
|
|
|
|
for i := 0 to fk.cxStoreArray - 1 do
|
|
begin
|
|
if Result.IfSystemStore.SystemStore.dwSystemID = Result.IfSystemStore.dwSystemID then
|
|
begin
|
|
Found := True;
|
|
Break;
|
|
end;
|
|
Inc(Result.IfSystemStore.SystemStore);
|
|
end;
|
|
|
|
if not Found then Result.IfSystemStore.SystemStore := nil;
|
|
Inc(pwsz);
|
|
Result.IfSystemStore.IsNot := Ord(pwsz^) - 1; // I3430
|
|
Inc(pwsz);
|
|
Result.IfSystemStore.StoreIndex := Ord(pwsz^) - 1;
|
|
Result.IfSystemStore.Store := BaseStore(fk.dpStoreArray, Result.IfSystemStore.StoreIndex);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
Result.ChrVal := GetSuppChar(pwsz);
|
|
end;
|
|
|
|
end.
|