Componentes.Terceros.DevExp.../official/x.48/ExpressSpellChecker 2/Sources/dxHunspellAffixes.pas
2010-01-18 18:33:24 +00:00

4867 lines
157 KiB
ObjectPascal

{********************************************************************}
{ }
{ Developer Express Visual Component Library }
{ ExpressSpellChecker }
{ }
{ Copyright (c) 1998-2009 Developer Express Inc. }
{ ALL RIGHTS RESERVED }
{ }
{ The entire contents of this file is protected by U.S. and }
{ International Copyright Laws. Unauthorized reproduction, }
{ reverse-engineering, and distribution of all or any portion of }
{ the code contained in this file is strictly prohibited and may }
{ result in severe civil and criminal penalties and will be }
{ prosecuted to the maximum extent possible under the law. }
{ }
{ RESTRICTIONS }
{ }
{ THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES }
{ (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE }
{ SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS }
{ LICENSED TO DISTRIBUTE THE EXPRESSSPELLCHECKER AND ALL }
{ ACCOMPANYING VCL CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY. }
{ }
{ THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED }
{ FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE }
{ COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE }
{ AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT }
{ AND PERMISSION FROM DEVELOPER EXPRESS INC. }
{ }
{ CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON }
{ ADDITIONAL RESTRICTIONS. }
{ }
{********************************************************************}
unit dxHunspellAffixes;
{$I cxVer.inc}
interface
uses
StrUtils, Math, SysUtils, Contnrs, dxHunspellUtils, dxHunspellWords,
dxHunspellTypes;
const
AffixTableSize = 256;
MaxLineLength = 8192;
DefaultCompoundPartLength = 3;
ExistentSuffixFlag = 1 shl 0;
ExistentPrefixFlag = 1 shl 1;
aoPrefixSuffixUnion = 1 shl 0;
aeUTF8 = 1 shl 1;
aoAffixFlagAliasTable = 1 shl 2;
aoAffixMorphologyTable = 1 shl 3;
aeLONGCOND = 1 shl 4;
HashSize = 256;
MaxFlagCount = 65536;
MaxConditionLength = 20;
type
TdxExistentAffixFlags = array[0..MaxFlagCount - 1] of Byte;
TdxStringData = record
Data: PAnsiChar;
Length: Integer;
end;
TdxReplaceTableItem = packed record
Initial: PAnsiChar;
Replacement: PAnsiChar;
end;
PdxReplaceArray = ^TdxReplaceArray;
TdxReplaceArray = array[0..0] of TdxReplaceTableItem;
TdxMapTableItem = packed record
CharacterSet: PAnsiChar;
Length: Integer;
end;
PdxMapArray = ^TdxMapArray;
TdxMapArray = array[0..0] of TdxMapTableItem;
TdxCompoundForbidPattern = record
Pattern: PAnsiChar;
Pattern2: PAnsiChar;
Pattern3: PAnsiChar;
Condition: Word;
Condition2: Word;
end;
PdxCompoundForbidPatternArray = ^TdxCompoundForbidPatternArray;
TdxCompoundForbidPatternArray = array[0..0] of TdxCompoundForbidPattern;
TdxHunspellAffixManager = class;
TdxAffix = class;
TdxAffixType = (atNone, atPrefix, atSuffix);
TdxCompoundWordPart = (cwpNone, cwpFirst, cwpLast, cwpOther);
TAffixTable = array [0..AffixTableSize - 1] of TdxAffix;
TWordFormArray = array [0..MAXWORDUTF8LEN + 4 - 1] of AnsiChar;
TAffixManagerFlagArray = array[0..MaxFlagCount - 1] of Boolean;
PdxAffixItem = ^TdxAffixItem;
TdxAffixItem = packed record
FStripString: PAnsiChar;
FAppendString: PAnsiChar;
FStripStringLength: Byte;
FAppendStringLength: Byte;
FConditionLength: Shortint;
FCompatibleFlags: TdxHunspellFlags;
FMorphologicalDescription: PAnsiChar;
LongCondition: Boolean;
case Integer of
1: (Condition: array [0..MaxConditionLength - 1] of AnsiChar);
2: (ConditionFirstPart: array [0..MaxConditionLength - 1] of AnsiChar;
ConditionSecondPart: PAnsiChar;)
end;
PdxAffixItemArray = ^TdxAffixItemArray;
TdxAffixItemArray = array[0..0] of TdxAffixItem;
PdxCompoundFlag = ^TdxCompoundFlag;
TdxCompoundFlag = record
Pattern: PdxAffixFlagsData;
Count: Integer;
Length: Integer;
end;
PdxCompoundFlagArray = ^TdxCompoundFlagArray;
TdxCompoundFlagArray = array[0..0] of TdxCompoundFlag;
PdxAffixCondition = ^TdxAffixCondition;
TdxAffixCondition = record
case Integer of
1: (Condition: array [0..MaxConditionLength - 1] of AnsiChar);
2: (ConditionFirstPart: array [0..MaxConditionLength - 1] of AnsiChar;
ConditionSecondPart: PAnsiChar);
end;
TdxSpellCheckerDataTable = class
private
FCurrentDataIndex: Integer;
FDataIdentifier: PAnsiChar;
FSize: Integer;
procedure FreeData;
protected
FData: Pointer;
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean; virtual;
function IsAllPiecesFound(APieceIndex: Integer): Boolean; virtual;
function CheckDataType(const APiece: PAnsiChar): Boolean;
procedure FreeDataItems; virtual; abstract;
function GetDataIdentifier: PAnsiChar; virtual; abstract;
function GetDataItemSize: Integer; virtual; abstract;
function GetPieceQuantity: Integer; virtual; abstract;
procedure InitializeItem(Index: Integer); virtual;
function ReadDataHeader(ALine: PAnsiChar): Boolean;
function ParseHeader(ALine: PAnsiChar; out ATableSize: Integer): Boolean; virtual;
function ParseData(AAffixFileManager: TdxHunspellReader): Boolean;
public
constructor Create; overload;
constructor Create(ADataIdentifier: PAnsiChar); overload;
destructor Destroy; override;
function AllocateData(ASize: Integer): Boolean;
function ReadData(ALine: PAnsiChar; AAffixFileManager: TdxHunspellReader): Boolean;
property Count: Integer read FSize;
end;
TdxSpellCheckerDataLinkedTable = class(TdxSpellCheckerDataTable)
private
FWordBaseManager: TdxHunspellWordBaseManager;
FAffixManager: TdxHunspellAffixManager;
public
constructor Create(AWordBaseManager: TdxHunspellWordBaseManager;
AAffixManager: TdxHunspellAffixManager);
property AffixManager: TdxHunspellAffixManager read FAffixManager;
property WordBaseManager: TdxHunspellWordBaseManager read FWordBaseManager;
end;
TdxAffixItemTable = class(TdxSpellCheckerDataLinkedTable)
private
FAffixesIsCreated: Boolean;
FDecodedFlag: Word;
FExistentAffixFlags: TdxExistentAffixFlags;
FFlag: PAnsiChar;
FPrefixSuffixUnion: Boolean;
procedure AddLineRemainderToMorphologicDescription(ALine: PAnsiChar; ADataIndex: Integer);
function CheckFlag(ALine: PAnsiChar): Boolean;
function ConditionLength(ALine: PAnsiChar): Integer;
function EncodeAffixCondition(ALine: PAnsiChar; ADataIndex: Integer): Boolean;
function HasAffixFlagAliases: Boolean;
function HasAffixMorphologicAliases: Boolean;
function FlagIsNil: Boolean;
function FlagIsUnique(AFlag: Word): Boolean;
procedure FreeIfZero(var AString: TdxStringData);
function GetData: PdxAffixItemArray;
function GetItem(Index: Integer): TdxAffixItem;
function GetOptions(AItem: TdxAffixItem): ShortInt;
function IsReverseWritingDirection: Boolean;
procedure ParseAppendString(const ALine: PAnsiChar; ADataIndex: Integer);
function ParseAppendStringWithAffixes(const ALine: PAnsiChar; ADataIndex: Integer): Boolean;
function ParseCompatibleFlags(const ALine: PAnsiChar; ADataIndex: Integer): Boolean;
function ParseCondition(ALine: PAnsiChar; ADataIndex: Integer): Boolean;
function ParseFlag(ALine: PAnsiChar): Boolean;
function ParseMorphologicDescription(ALine: PAnsiChar; ADataIndex: Integer): Boolean;
procedure ParsePrefixSuffixUnion(ALine: PAnsiChar);
procedure ParseStripString(const ALine: PAnsiChar; ADataIndex: Integer);
function ParseTableSize(ALine: PAnsiChar; out ATableSize: Integer): Boolean;
procedure ProcessIgnoreChars(ALine: PAnsiChar);
procedure ProcessReverseString(ALine: PAnsiChar);
procedure RegisterCompatibleFlags(ADataIndex: Integer);
procedure ReverseCondition(ACondition: PAnsiChar);
procedure SetExisting;
protected
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean; override;
function IsAllPiecesFound(APieceIndex: Integer): Boolean; override;
function IsComplexPrefixes: Boolean;
procedure BuildAffixes; virtual;
function ConditionContainsDuplicateInformation(strip: PAnsiChar; stripl: Integer;
const ACondition: PAnsiChar; out Contains: Boolean): Boolean; virtual; abstract;
function GetDataIdentifier: PAnsiChar; override;
function GetDataItemSize: Integer; override;
function GetPieceQuantity: Integer; override;
procedure FreeDataItems; override;
function IsPrefix: Boolean; virtual; abstract;
function ParseHeader(ALine: PAnsiChar; out ATableSize: Integer): Boolean; override;
property Data: PdxAffixItemArray read GetData;
property Items[Index: Integer]: TdxAffixItem read GetItem; default;
public
constructor Create(AWordBaseManager: TdxHunspellWordBaseManager;
AAffixManager: TdxHunspellAffixManager; AExistentAffixFlags: TdxExistentAffixFlags);
destructor Destroy; override;
property Flag: PAnsiChar read FFlag;
end;
TdxPrefixItemTable = class(TdxAffixItemTable)
protected
function ConditionContainsDuplicateInformation(strip: PAnsiChar; stripl: Integer;
const ACondition: PAnsiChar; out Contains: Boolean): Boolean; override;
function IsPrefix: Boolean; override;
public
procedure BuildAffixes; override;
end;
TdxSuffixItemTable = class(TdxAffixItemTable)
protected
function ConditionContainsDuplicateInformation(strip: PAnsiChar; stripl: Integer;
const ACondition: PAnsiChar; out Contains: Boolean): Boolean; override;
function IsPrefix: Boolean; override;
public
procedure BuildAffixes; override;
end;
TdxBreakTable = class(TdxSpellCheckerDataTable)
private
procedure FillDefaultData;
function GetData: PdxPAnsiCharArray;
function GetItem(Index: Integer): PAnsiChar;
protected
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean; override;
procedure FreeDataItems; override;
function GetDataIdentifier: PAnsiChar; override;
function GetDataItemSize: Integer; override;
function GetPieceQuantity: Integer; override;
public
constructor Create;
property Data: PdxPAnsiCharArray read GetData;
property Items[Index: Integer]: PAnsiChar read GetItem; default;
end;
TdxCheckCompoundPatternTable = class(TdxSpellCheckerDataLinkedTable)
private
FIsSimplified: Boolean;
procedure ExtractCondition(APattern: PAnsiChar; var ACondition: Word);
function GetData: PdxCompoundForbidPatternArray;
function GetItem(Index: Integer): TdxCompoundForbidPattern;
protected
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean; override;
procedure FreeDataItems; override;
function GetDataIdentifier: PAnsiChar; override;
function GetDataItemSize: Integer; override;
function GetPieceQuantity: Integer; override;
procedure InitializeItem(Index: Integer); override;
public
property Data: PdxCompoundForbidPatternArray read GetData;
property IsSimplified: Boolean read FIsSimplified;
property Items[Index: Integer]: TdxCompoundForbidPattern read GetItem; default;
end;
TdxCompoundRuleTable = class(TdxSpellCheckerDataLinkedTable)
private
function GetData: PdxCompoundFlagArray;
function GetItem(Index: Integer): TdxCompoundFlag;
function ParseFlags(APiece: PAnsiChar; AIndex: Integer): Boolean;
protected
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean; override;
procedure FreeDataItems; override;
function GetDataIdentifier: PAnsiChar; override;
function GetDataItemSize: Integer; override;
function GetPieceQuantity: Integer; override;
procedure InitializeItem(Index: Integer); override;
public
property Data: PdxCompoundFlagArray read GetData;
property Items[Index: Integer]: TdxCompoundFlag read GetItem; default;
end;
TdxMapTable = class(TdxSpellCheckerDataTable)
private
function GetData: PdxMapArray;
function GetItem(Index: Integer): TdxMapTableItem;
protected
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean; override;
procedure FreeDataItems; override;
function GetDataIdentifier: PAnsiChar; override;
function GetDataItemSize: Integer; override;
function GetPieceQuantity: Integer; override;
procedure InitializeItem(Index: Integer); override;
public
property Data: PdxMapArray read GetData;
property Items[Index: Integer]: TdxMapTableItem read GetItem; default;
end;
TdxReplaceTable = class(TdxSpellCheckerDataTable)
private
function GetData: PdxReplaceArray;
function GetItem(Index: Integer): TdxReplaceTableItem;
protected
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean; override;
procedure FreeDataItems; override;
function GetDataIdentifier: PAnsiChar; override;
function GetDataItemSize: Integer; override;
function GetPieceQuantity: Integer; override;
procedure InitializeItem(Index: Integer); override;
public
property Data: PdxReplaceArray read GetData;
property Items[Index: Integer]: TdxReplaceTableItem read GetItem; default;
end;
TdxSortedReplaceTable = class(TdxReplaceTable)
private
function near1(const Aword: PAnsiChar): Integer;
function match(const Aword: PAnsiChar; n: Integer): Integer;
procedure Sort(AIndex: Integer);
protected
function AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean; override;
public
function conv(const Aword: PAnsiChar; dest: PAnsiChar): Integer;
end;
TdxAffix = class
protected
FAffixManager: TdxHunspellAffixManager;
FAppendString: PAnsiChar;
FStripString: PAnsiChar;
FAppendStringLength: Byte;
FStripStringLength: Byte;
FConditionLength: ShortInt;
FOptions: ShortInt;
FFlag: Word;
FMorphologicalDescription: PAnsiChar;
FCompatibleFlags: TdxHunspellFlags;
FConditions: PdxAffixCondition;
FNext: TdxAffix;
FNextSimilar: TdxAffix;
FNextDifferent: TdxAffix;
FNextByFlag: TdxAffix;
function GetAppendString: PAnsiChar; virtual;
function GetPrefixSuffixUnion: Boolean;
protected
function CanUseInCompoundWordPart(ACompoundWordPart: TdxCompoundWordPart): Boolean; virtual; abstract;
function GetNextConditionChar(AConditionCursor: PAnsiChar): PAnsiChar;
function IsCompatibleWithFlag(AFlag: Word; CompatibleIfNull: Boolean = False): Boolean;
function IsPrefixSuffixUnion(AOptions: ShortInt): Boolean;
function IsWithoutAffixWordLengthCorrect(ALengthWithoutAffix: Integer): Boolean;
procedure SearchConditionGroupEnd(var AConditionCursor: PAnsiChar);
public
constructor Create(AAffixManager: TdxHunspellAffixManager;
AAffixItem: PdxAffixItem; AFlag: Word; AOptions: ShortInt);
destructor Destroy; override;
function CanUseInSimpleWordsOrIsFogemorpheme(ACompoundWordPart: TdxCompoundWordPart): Boolean;
function CanUseInTheMiddleOfCompoundWords(ACompoundWordPart: TdxCompoundWordPart): Boolean;
function IsCircumfix: Boolean;
property AffixManager: TdxHunspellAffixManager read FAffixManager;
property AppendString: PAnsiChar read GetAppendString;
property AppendStringLength: Byte read FAppendStringLength write FAppendStringLength;
property CompatibleFlags: TdxHunspellFlags read FCompatibleFlags write FCompatibleFlags;
property Flag: Word read FFlag;
property MorphologicalDescription: PAnsiChar read FMorphologicalDescription;
property Options: ShortInt read FOptions;
property PrefixSuffixUnion: Boolean read GetPrefixSuffixUnion;
property Next: TdxAffix read FNext write FNext;
property NextSimilar: TdxAffix read FNextSimilar write FNextSimilar;
property NextDifferent: TdxAffix read FNextDifferent write FNextDifferent;
property NextByFlag: TdxAffix read FNextByFlag write FNextByFlag;
end;
TdxSuffix = class;
TdxPrefix = class(TdxAffix)
protected
function CanUseInCompoundWordPart(ACompoundWordPart: TdxCompoundWordPart): Boolean; override;
public
function CheckWord(const AWord: PAnsiChar; AWordLength: Integer; var ATakenSuffix: TdxSuffix;
ACompoundWordPart: TdxCompoundWordPart; const ACompoundPartFlag: Word = NullFlag): TdxHunspellWordItem;
function MakeInitialWordFormAndProcessTwoSuffixCheck(const AWord: PAnsiChar; AWordLength: Integer;
var ATakenSuffix: TdxSuffix; ACompoundWordPart: TdxCompoundWordPart;
const ACompoundPartFlag: Word = NullFlag): TdxHunspellWordItem;
function IsWordSuitableToCondition(AWord: PAnsiChar): Boolean;
end;
TdxSuffix = class(TdxAffix)
private
FReverseAppendString: PAnsiChar;
l_morph: TdxSuffix; //TODO: Remove
r_morph: TdxSuffix;
eq_morph: TdxSuffix;
protected
function CanUseInCompoundWordPart(ACompoundWordPart: TdxCompoundWordPart): Boolean; override;
function GetAppendString: PAnsiChar; override;
public
constructor Create(AAffixManager: TdxHunspellAffixManager;
AAffixItem: PdxAffixItem; AFlag: Word; AOptions: ShortInt);
destructor Destroy; override;
function CheckWord(const AWord: PAnsiChar; AWordLength, AOptions: Integer;
APrefix: TdxPrefix; wlst: PPAnsiChar; maxSug: Integer; ns: PInteger;
const ACompatibleFlag: Word = NullFlag; const ACompoundPartFlag: Word = NullFlag; const AIncompatibleFlag: Word = NullFlag): TdxHunspellWordItem;
function MakeInitialWordFormAndProcessSuffixCheck(const AWord: PAnsiChar;
AWordLength, AOptions: Integer; APrefix: TdxPrefix; var ATakenSuffix: TdxSuffix;
const ACompoundPartFlag: Word = 0): TdxHunspellWordItem;
function GetWordWithAffix(const AWord: PAnsiChar; AWordLength: Integer): PAnsiChar;
function getLM: TdxSuffix;
function getRM: TdxSuffix;
function getEQM: TdxSuffix;
function IsWordSuitableToCondition(AWordEnd, AWordBegin: PAnsiChar): Boolean;
end;
TdxSuffixInfo = record
Flag: Word;
AppendString: PAnsiChar;
end;
TdxHunspellAffixManager = class
private
cpdvowels_utf16: PWideChar;
cpdvowels_utf16_len: Integer;
FAffixFilePath: string;
FBreakTable: TdxBreakTable;
FCheckCompoundCase: Boolean;
FCheckCompoundDup: Boolean;
FCheckCompoundPatternTable: TdxCheckCompoundPatternTable;
FCheckCompoundRep: Boolean;
FCheckCompoundTriple: Boolean;
FCheckSharps: Integer;
FCircumfix: Word;
FCodePage: Cardinal;
FCompatibleFlags: TAffixManagerFlagArray;
FCompatibleFlagsExist: Boolean;
FComplexPrefixes: Boolean;
FCompoundBegin: Word;
FCompoundEnd: Word;
FCompoundFlag: Word;
FCompoundForbidFlag: Word;
FCompoundMiddle: Word;
FCompoundPartMin: Integer;
FCompoundPermitFlag: Word;
FCompoundRoot: Word;
FCompoundRuleTable: TdxCompoundRuleTable;
FCompoundVowels: PAnsiChar;
FCompoundWordMax: Integer;
FExistentAffixFlags: TdxExistentAffixFlags;
FForbiddenWord: Word;
FFullStrip: Boolean;
FIgnore: PAnsiChar;
FInputReplaceTable: TdxSortedReplaceTable;
FIsExistentAffixFlagsInitialized: Boolean;
FIsUTF8: Boolean;
FKeepCase: Word;
FLanguage: Integer;
FLemmaPresent: Word;
FMapTable: TdxMapTable;
FMaxCompoundSyllable: Integer;
FMaxngramsugs: Integer;
FNeedAffix: Word;
FNoSplitSugs: Boolean;
FNoSuggest: Word;
FOnlyInCompound: Word;
FOutputReplaceTable: TdxSortedReplaceTable;
FPrefixTableArrangedByAppendString: TAffixTable;
FPrefixTableIndexedByFlag: TAffixTable;
FReplaceTable: TdxReplaceTable;
FSavedSuffixInfo: TdxSuffixInfo;
FSimplifiedTriple: Boolean;
FSubstandard: Word;
FSuffixTableArrangedByAppendString: TAffixTable;
FSuffixTableIndexedByFlag: TAffixTable;
FSugsWithDots: Boolean;
FSyllableNum: PAnsiChar;
FTryChars: PAnsiChar;
FVersion: PAnsiChar;
FWordBaseManager: TdxHunspellWordBaseManager;
ignorechars_utf16: PWord;
ignorechars_utf16_len: Integer;
FIsHungarian: Boolean;
wordchars_utf16: PWord;
wordchars_utf16_len: Integer;
function DoAffixParsing(ALine: PAnsiChar; AAffixFileManager: TdxHunspellReader; AAffixType: TdxAffixType): Boolean;
function ParseFile(const AFileName: string): Integer;
function ParseCompoundSyllable(ALine: PAnsiChar; AAffixFileManager: TdxHunspellReader): Boolean;
function ParseRep(ALine: PAnsiChar; AAffixFileManager: TdxHunspellReader): Boolean;
function ParseAffix(ALine: PAnsiChar; const IsPrefix: Boolean; AAffixFileManager: TdxHunspellReader; AExistentAffixFlags: TdxExistentAffixFlags): Boolean;
function AreAffixesBothCircumfixesOrNot(APrefix, ASuffix: TdxAffix): Boolean;
function CanBeFirstPartInCompoundWord(AWordBaseItem: TdxHunspellWordItem; AWordPartIndex: Cardinal): Boolean;
procedure CompoundRootCheck(AWordBaseItem: TdxHunspellWordItem; var AWordPartIndex: SmallInt);
function IsForbiddenOrNoSuggestWord(AWordBaseItem: TdxHunspellWordItem; ASuggest: Boolean): Boolean;
function IsWordPartSuitsCheckCompoundPatternTable(AWordBaseItem: TdxHunspellWordItem; ATableIndex: Integer; AIsFirstWordPart: Boolean): Boolean;
function IsWordPartSuitsCompoundFlags(AWordBaseItem: TdxHunspellWordItem; AWordPartIndex: SmallInt; AIsFirstWordPart: Boolean; words: PdxHunspellWordBaseTable): Boolean;
function IsTripleLettersExistAndForbid(AWord: PAnsiChar; AJoint: Cardinal): Boolean;
function UseWithAffixOnly(AWordBaseItem: TdxHunspellWordItem): Boolean;
function HungarianCheck(AWordBaseItem: TdxHunspellWordItem; hu_mov_rule: Boolean): Boolean;
function HungarianCheck2(var AWordBaseItem: TdxHunspellWordItem; AInitialWordForm: TWordFormArray;
ACompoundWordJoint: Integer; hu_mov_rule: Boolean;
var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix): Boolean;
procedure BuildAffixTree(AAffix: TdxAffix; var AAffixTableArrangedByAppendString: TAffixTable;
var AAffixTableIndexedByFlag: TAffixTable);
function ProcessSuffixOrPrefixCheck(const AWord: PAnsiChar; AWordLength: Integer;
ACompoundPartFlag: Word; ACompoundWordPart: TdxCompoundWordPart; var
AWordBaseTableItem: TdxHunspellWordItem; var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix): Boolean;
procedure LinkAffixesIntoSubsets(AAffixTableArrangedByAppendString: TAffixTable);
function OrderAffixTree(AAffix, ANextAffix: TdxAffix): TdxAffix;
procedure AffixTreeToList(var ATable: TAffixTable);
function GetIsCompoundWordsAvailable: Boolean;
function GetParseClasses: TObjectList;
procedure SetLanguage(Value: Integer);
protected
property FullStrip: Boolean read FFullStrip;
public
constructor Create(const AAffixFilePath: string;
AWordBaseManager: TdxHunspellWordBaseManager);
destructor Destroy; override;
function AffixCheck(const AWord: PAnsiChar; AWordLength: Integer; var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix;
const ACompoundPartFlag: Word = 0; ACompoundWordPart: TdxCompoundWordPart = cwpNone): TdxHunspellWordItem;
function ProcessPrefixCheck(const AWord: PAnsiChar; AWordLength: Integer;
var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix;
ACompoundWordPart: TdxCompoundWordPart; const ACompoundPartFlag: Word = NullFlag): TdxHunspellWordItem;
function IsLeadingSubset(ASubset: PAnsiChar; ASet: PAnsiChar): Boolean; {$IFDEF DELPHI9} inline; {$ENDIF}
function IsTrailingReversedSubset(AReversedSubset: PAnsiChar; AEndOfSet: PAnsiChar; ASetLength: Integer): Boolean;
function ProcessPrefixWithSuffixesCheck(const AWord: PAnsiChar; AWordLength: Integer;
var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; ACompoundWordPart: TdxCompoundWordPart;
const ACompoundPartFlag: Word = NullFlag): TdxHunspellWordItem;
function ProcessSuffixCheck(const AWord: PAnsiChar; AWordLength, AOptions: Integer;
APrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; wlst: PPAnsiChar; maxSug: Integer; ns: PInteger;
const ACompatibleFlag: Word = NullFlag; const ACompoundPartFlag: Word = NullFlag;
ACompoundWordPart: TdxCompoundWordPart = cwpNone): TdxHunspellWordItem;
function ProcessTwoSuffixCheck(const AWord: PAnsiChar; AWordLength, AOptions: Integer;
APrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; const ACompoundPartFlag: Word = NullFlag): TdxHunspellWordItem;
function GetSyllableCount(const AWord: PAnsiChar; AWordLength: Integer): SmallInt;
function IsSimpleWordWithReplacedCharacters(
const AWord: PAnsiChar; AWordLength: Integer; var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix): Boolean;
function IsForbiddenByCheckCompoundPattern(const AWord: PAnsiChar; AJoint: Integer;
AFirstPartWordBase, ASecondPartWordBase: TdxHunspellWordItem): Boolean;
function IsWordPartsSuitCompoundRule(var AWords: PdxHunspellWordBaseTable; AWordCount: SmallInt;
AWordBaseItem: TdxHunspellWordItem; ADefaultWords: PdxHunspellWordBaseTable; all: Boolean): Boolean;
function IsJointUpperCaseExistAndForbid(const AWord: PAnsiChar; AJoint: Integer): Boolean;
function CompoundWordWithReplacedCharactersExists(const AWord: PAnsiChar;
AWordLength: Integer; var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix): Boolean;
procedure GetCompoundWordJointRange(var ACompoundWordJointMin, ACompoundWordJointMax: Integer; const AWord: PAnsiChar; AWordLength: Integer);
function CompoundCheck(const AWord: PAnsiChar;
AWordPartIndex, ASyllableCount, AWordPartMaxCount, wnum: SmallInt; words: PdxHunspellWordBaseTable = nil;
hu_mov_rule: Boolean = False; ASuggest: Boolean = False): TdxHunspellWordItem;
function Lookup(const AWord: PAnsiChar): TdxHunspellWordItem;
function EncodeFlag(AFlag: Word): PAnsiChar;
procedure SetCompatibleFlags(AIndex: Integer; AValue: Boolean);
property BreakTable: TdxBreakTable read FBreakTable;
property CheckSharps: Integer read FCheckSharps;
property CodePage: Cardinal read FCodePage write FCodePage;
property CompatibleFlagsExist: Boolean read FCompatibleFlagsExist write FCompatibleFlagsExist;
property ComplexPrefixes: Boolean read FComplexPrefixes;
property CompoundFlag: Word read FCompoundFlag;
property ForbiddenWord: Word read FForbiddenWord;
property Ignore: PAnsiChar read FIgnore;
property InputReplaceTable: TdxSortedReplaceTable read FInputReplaceTable;
property IsCompoundWordsAvailable: Boolean read GetIsCompoundWordsAvailable;
property IsHungarian: Boolean read FIsHungarian;
property IsUTF8: Boolean read FIsUTF8;
property KeepCase: Word read FKeepCase;
property Language: Integer read FLanguage write SetLanguage;
property Maxngramsugs: Integer read FMaxngramsugs;
property NeedAffix: Word read FNeedAffix;
property OutputReplaceTable: TdxSortedReplaceTable read FOutputReplaceTable;
property OnlyInCompound: Word read FOnlyInCompound;
property TryChars: PAnsiChar read FTryChars;
end;
TAffixFileReader = class
protected
FAffixManager: TdxHunspellAffixManager;
function GetDataIdentifier: PAnsiChar; virtual; abstract;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; virtual; abstract;
function ParseFlag(ALine: PAnsiChar; var ADecodedFlag: Word; AReader: TdxHunspellReader): Boolean;
function ParseNumber(ALine: PAnsiChar; out ANumber: Integer): Boolean;
public
constructor Create(AAffixManager: TdxHunspellAffixManager);
end;
TTryReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TSetReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TComplexPrefixesReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCompoundFlagReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCompoundBeginReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCompoundEndReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCompoundMiddleReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCompoundWordMaxReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCompoundRootReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCompoundPermitFlagReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCompoundForbidFlagReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCheckCompoundDupReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCheckCompoundRepReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCheckCompoundTripleReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TSimplifiedTripleReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCheckCompoundCaseReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TNoSuggestReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TForbiddenWordReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TLemmaPresentReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCircumfixReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TOnlyInCompoundReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TPseudoRootReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TNeedAffixReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCompoundMinReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCompoundSyllableReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TSyllableNumReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TWordCharsReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TIgnoreReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TRepReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TIConvReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TOConvReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCheckCompoundPatternReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCompoundRuleReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TMapReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TBreakReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TLangReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TVersionReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TNoSplitSugsReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TFullStripReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TSugsWithDotsReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TKeepCaseReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TSubStandardReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TCheckSharpsReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TPrefixReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
TSuffixReader = class(TAffixFileReader)
protected
function GetDataIdentifier: PAnsiChar; override;
function Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean; override;
end;
implementation
uses
dxSpellCheckerUtils;
constructor TdxHunspellAffixManager.Create(const AAffixFilePath: string;
AWordBaseManager: TdxHunspellWordBaseManager);
var
I: Integer;
begin
FWordBaseManager := AWordBaseManager;
FForbiddenWord := ForbiddenWordFlag;
FCompoundWordMax := -1;
FCompoundPartMin := -1;
FMaxngramsugs := -1;
FBreakTable := TdxBreakTable.Create;
FCheckCompoundPatternTable := TdxCheckCompoundPatternTable.Create(FWordBaseManager, Self);
FCompoundRuleTable := TdxCompoundRuleTable.Create(FWordBaseManager, Self);
FInputReplaceTable := TdxSortedReplaceTable.Create('ICONV');
FOutputReplaceTable := TdxSortedReplaceTable.Create('OCONV');
FMapTable := TdxMapTable.Create;
FReplaceTable := TdxReplaceTable.Create;
for I := 0 to AffixTableSize - 1 do
begin
FPrefixTableArrangedByAppendString[I] := nil;
FSuffixTableArrangedByAppendString[I] := nil;
FPrefixTableIndexedByFlag[I] := nil;
FSuffixTableIndexedByFlag[I] := nil;
end;
for I := 0 to MaxFlagCount - 1 do
FCompatibleFlags[I] := False;
FAffixFilePath := AAffixFilePath;
ParseFile(AAffixFilePath);
if FCompoundPartMin = -1 then
FCompoundPartMin := DefaultCompoundPartLength;
end;
destructor TdxHunspellAffixManager.Destroy;
var
I: Integer;
AAffix, ANextAffix: TdxAffix;
begin
for I := 0 to AffixTableSize - 1 do
begin
FPrefixTableIndexedByFlag[I] := nil;
FSuffixTableIndexedByFlag[I] := nil;
AAffix := TdxPrefix(FPrefixTableArrangedByAppendString[I]);
while AAffix <> nil do
begin
ANextAffix := AAffix.Next;
AAffix.Free;
AAffix := ANextAffix;
end;
AAffix := TdxSuffix(FSuffixTableArrangedByAppendString[I]);
while AAffix <> nil do
begin
ANextAffix := AAffix.Next;
AAffix.Free;
AAffix := ANextAffix;
end;
FSuffixTableArrangedByAppendString[I] := nil;
end;
if FTryChars <> nil then
StrDispose(FTryChars);
FTryChars := nil;
FreeAndNil(FMapTable);
FreeAndNil(FBreakTable);
FreeAndNil(FReplaceTable);
FreeAndNil(FInputReplaceTable);
FreeAndNil(FOutputReplaceTable);
FreeAndNil(FCompoundRuleTable);
FreeAndNil(FCheckCompoundPatternTable);
FWordBaseManager := nil;
if FCompoundVowels <> nil then
StrDispose(FCompoundVowels);
if cpdvowels_utf16 <> nil then
FreeMem(cpdvowels_utf16, cpdvowels_utf16_len * SizeOf(WideChar));
StrDispose(FSyllableNum);
if wordchars_utf16 <> nil then
FreeMem(wordchars_utf16, wordchars_utf16_len * SizeOf(Word));
StrDispose(FIgnore);
if ignorechars_utf16 <> nil then
FreeMem(ignorechars_utf16, ignorechars_utf16_len * SizeOf(Word));
StrDispose(FVersion);
inherited Destroy;
end;
function TdxHunspellAffixManager.DoAffixParsing(ALine: PAnsiChar; AAffixFileManager: TdxHunspellReader; AAffixType: TdxAffixType): Boolean;
var
I: Integer;
begin
Result := True;
if AAffixType <> atNone then
begin
if not FIsExistentAffixFlagsInitialized then
begin
for I := 0 to MaxFlagCount - 1 do
FExistentAffixFlags[I] := 0;
FIsExistentAffixFlagsInitialized := True;
end;
if ParseAffix(ALine, AAffixType = atPrefix, AAffixFileManager, FExistentAffixFlags) then
begin
AffixTreeToList(FPrefixTableArrangedByAppendString);
AffixTreeToList(FSuffixTableArrangedByAppendString);
Result := False;
end;
end;
end;
function TdxHunspellAffixManager.ParseFile(const AFileName: string): Integer;
var
ALineCursor, ADataIdentifier: PAnsiChar;
AIsFirstLine: Boolean;
AAffixReader: TdxHunspellReader;
AParseClasses: TObjectList;
I: Integer;
begin
Result := 0;
FIsExistentAffixFlagsInitialized := False;
AIsFirstLine := True;
AAffixReader := nil;
ALineCursor := nil;
AParseClasses := GetParseClasses;
try
AAffixReader := TdxHunspellReader.Create(AFileName);
if AAffixReader = nil then
begin
Result := 1;
Exit;
end;
ALineCursor := AAffixReader.getline;
while ALineCursor <> nil do
begin
RemoveCRLF(ALineCursor);
if AIsFirstLine then
begin
AIsFirstLine := False;
RemoveMark(ALineCursor);
end;
for I := 0 to AParseClasses.Count - 1 do
begin
ADataIdentifier := TAffixFileReader(AParseClasses.Items[I]).GetDataIdentifier;
if StrLComp(ALineCursor, ADataIdentifier, StrLen(ADataIdentifier)) = 0 then
TAffixFileReader(AParseClasses.Items[I]).Process(ALineCursor, AAffixReader);
end;
StrDispose(ALineCursor);
ALineCursor := AAffixReader.getline;
end;
finally
StrDispose(ALineCursor);
AAffixReader.Free;
AParseClasses.Free;
end;
AffixTreeToList(FPrefixTableArrangedByAppendString);
AffixTreeToList(FSuffixTableArrangedByAppendString);
LinkAffixesIntoSubsets(FPrefixTableArrangedByAppendString);
LinkAffixesIntoSubsets(FSuffixTableArrangedByAppendString);
end;
procedure TdxHunspellAffixManager.BuildAffixTree(AAffix: TdxAffix;
var AAffixTableArrangedByAppendString: TAffixTable; var AAffixTableIndexedByFlag: TAffixTable);
var
ACurrentItem, APreviousAffix: TdxAffix;
AAppendString: PAnsiChar;
AFlag, AFirstChar: Byte;
begin
AAppendString := AAffix.AppendString;
AFlag := AAffix.Flag;
ACurrentItem := AAffixTableIndexedByFlag[AFlag];
AAffix.NextByFlag := ACurrentItem;
AAffixTableIndexedByFlag[AFlag] := AAffix;
if StrLen(AAppendString) = 0 then
begin
ACurrentItem := AAffixTableArrangedByAppendString[0];
AAffix.Next := ACurrentItem;
AAffixTableArrangedByAppendString[0] := AAffix;
Exit;
end;
AAffix.NextSimilar := nil;
AAffix.NextDifferent := nil;
AFirstChar := Ord(AAppendString^);
ACurrentItem := AAffixTableArrangedByAppendString[AFirstChar];
if ACurrentItem = nil then
begin
AAffixTableArrangedByAppendString[AFirstChar] := AAffix;
Exit;
end;
while True do
begin
APreviousAffix := ACurrentItem;
if StrComp(AAffix.AppendString, ACurrentItem.AppendString) <= 0 then
begin
ACurrentItem := ACurrentItem.NextSimilar;
if ACurrentItem = nil then
begin
APreviousAffix.NextSimilar := AAffix;
Break;
end;
end
else
begin
ACurrentItem := ACurrentItem.NextDifferent;
if ACurrentItem = nil then
begin
APreviousAffix.NextDifferent := AAffix;
Break;
end;
end;
end;
end;
function TdxHunspellAffixManager.ProcessSuffixOrPrefixCheck(const AWord: PAnsiChar; AWordLength: Integer;
ACompoundPartFlag: Word; ACompoundWordPart: TdxCompoundWordPart;
var AWordBaseTableItem: TdxHunspellWordItem; var ATakenPrefix: TdxPrefix;
var ATakenSuffix: TdxSuffix): Boolean;
begin
AWordBaseTableItem := ProcessSuffixCheck(AWord, AWordLength, 0, nil, ATakenSuffix,
nil, 0, nil, NullFlag, ACompoundPartFlag, ACompoundWordPart);
Result := AWordBaseTableItem <> nil;
if not Result then
begin
AWordBaseTableItem := ProcessPrefixCheck(AWord, AWordLength, ATakenPrefix,
ATakenSuffix, ACompoundWordPart, ACompoundPartFlag);
Result := AWordBaseTableItem <> nil;
end;
end;
procedure TdxHunspellAffixManager.AffixTreeToList(var ATable: TAffixTable);
var
I: Integer;
begin
for I := 1 to AffixTableSize - 1 do
ATable[I] := OrderAffixTree(ATable[I], nil);
end;
function TdxHunspellAffixManager.OrderAffixTree(AAffix, ANextAffix: TdxAffix): TdxAffix;
begin
if AAffix <> nil then
begin
ANextAffix := OrderAffixTree(AAffix.NextDifferent, ANextAffix);
AAffix.Next := ANextAffix;
ANextAffix := OrderAffixTree(AAffix.NextSimilar, AAffix);
end;
Result := ANextAffix;
end;
procedure TdxHunspellAffixManager.LinkAffixesIntoSubsets(AAffixTableArrangedByAppendString: TAffixTable);
var
AAffix, ANextAffix, ALastAffixInChain: TdxAffix;
I: Integer;
begin
for I := 1 to AffixTableSize - 1 do
begin
AAffix := AAffixTableArrangedByAppendString[I];
while AAffix <> nil do
begin
ANextAffix := AAffix.Next;
while ANextAffix <> nil do
begin
if not IsLeadingSubset(AAffix.AppendString, ANextAffix.AppendString) then
Break;
ANextAffix := ANextAffix.Next;
end;
AAffix.NextDifferent := ANextAffix;
AAffix.NextSimilar := nil;
if (AAffix.Next <> nil) and IsLeadingSubset(AAffix.AppendString, AAffix.Next.AppendString) then
AAffix.NextSimilar := AAffix.Next;
AAffix := AAffix.Next;
end;
AAffix := AAffixTableArrangedByAppendString[I];
while AAffix <> nil do
begin
ANextAffix := AAffix.Next;
ALastAffixInChain := nil;
while ANextAffix <> nil do
begin
if not IsLeadingSubset(AAffix.AppendString, ANextAffix.AppendString) then
Break;
ALastAffixInChain := ANextAffix;
ANextAffix := ANextAffix.Next;
end;
if ALastAffixInChain <> nil then
ALastAffixInChain.NextDifferent := nil;
AAffix := AAffix.Next;
end;
end;
end;
function TdxHunspellAffixManager.IsLeadingSubset(ASubset: PAnsiChar; ASet: PAnsiChar): Boolean;
begin
while (ASubset^ in [ASet^, '.']) and (ASubset^ <> #0) do
begin
Inc(ASubset);
Inc(ASet);
end;
Result := ASubset^ = #0;
end;
function TdxHunspellAffixManager.IsTrailingReversedSubset(AReversedSubset: PAnsiChar;
AEndOfSet: PAnsiChar; ASetLength: Integer): Boolean;
begin
while (ASetLength > 0) and (AReversedSubset^ <> #0) and
((AReversedSubset^ = AEndOfSet^) or (AReversedSubset^ = '.')) do
begin
Inc(AReversedSubset);
Dec(AEndOfSet);
Dec(ASetLength);
end;
Result := AReversedSubset^ = #0;
end;
function TdxHunspellAffixManager.ProcessPrefixCheck(const AWord: PAnsiChar; AWordLength: Integer;
var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; ACompoundWordPart: TdxCompoundWordPart;
const ACompoundPartFlag: Word): TdxHunspellWordItem;
var
APrefix: TdxPrefix;
begin
Result := nil;
ATakenPrefix := nil;
FSavedSuffixInfo.AppendString := nil;
APrefix := TdxPrefix(FPrefixTableArrangedByAppendString[0]);
while (APrefix <> nil) and (Result = nil) do
begin
if APrefix.CanUseInSimpleWordsOrIsFogemorpheme(ACompoundWordPart) and
APrefix.CanUseInTheMiddleOfCompoundWords(ACompoundWordPart) then
begin
Result := APrefix.CheckWord(AWord, AWordLength, ATakenSuffix, ACompoundWordPart, ACompoundPartFlag); //TODO: Extract block
if Result <> nil then
ATakenPrefix := APrefix;
end;
APrefix := TdxPrefix(APrefix.Next);
end;
if Result = nil then
begin
APrefix := TdxPrefix(FPrefixTableArrangedByAppendString[PByte(AWord)^]);
while (APrefix <> nil) and (Result = nil) do
begin
if IsLeadingSubset(APrefix.AppendString, AWord) then
begin
if APrefix.CanUseInSimpleWordsOrIsFogemorpheme(ACompoundWordPart) and
APrefix.CanUseInTheMiddleOfCompoundWords(ACompoundWordPart) then
begin
Result := APrefix.CheckWord(AWord, AWordLength, ATakenSuffix, ACompoundWordPart, ACompoundPartFlag); //TODO: Extract block
if Result <> nil then
ATakenPrefix := APrefix;
end;
APrefix := TdxPrefix(APrefix.NextSimilar);
end
else
APrefix := TdxPrefix(APrefix.NextDifferent);
end;
end;
end;
function TdxHunspellAffixManager.ProcessPrefixWithSuffixesCheck(const AWord: PAnsiChar;
AWordLength: Integer; var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix;
ACompoundWordPart: TdxCompoundWordPart; const ACompoundPartFlag: Word): TdxHunspellWordItem;
var
APrefix: TdxPrefix;
begin
Result := nil;
ATakenPrefix := nil;
FSavedSuffixInfo.AppendString := nil;
APrefix := TdxPrefix(FPrefixTableArrangedByAppendString[0]);
while (APrefix <> nil) and (Result = nil) do
begin
Result := APrefix.MakeInitialWordFormAndProcessTwoSuffixCheck(AWord,
AWordLength, ATakenSuffix, ACompoundWordPart, ACompoundPartFlag);
APrefix := TdxPrefix(APrefix.Next);
end;
if Result = nil then
begin
APrefix := TdxPrefix(FPrefixTableArrangedByAppendString[PByte(AWord)^]);
while (APrefix <> nil) and (Result = nil) do
begin
if IsLeadingSubset(APrefix.AppendString, AWord) then
begin
Result := APrefix.MakeInitialWordFormAndProcessTwoSuffixCheck(AWord,
AWordLength, ATakenSuffix, ACompoundWordPart, ACompoundPartFlag);
if Result <> nil then
ATakenPrefix := APrefix;
APrefix := TdxPrefix(APrefix.NextSimilar);
end
else
APrefix := TdxPrefix(APrefix.NextDifferent);
end;
end;
end;
function TdxHunspellAffixManager.IsSimpleWordWithReplacedCharacters(
const AWord: PAnsiChar; AWordLength: Integer; var ATakenPrefix: TdxPrefix;
var ATakenSuffix: TdxSuffix): Boolean;
var
AChangedWord: array [0..MaxLineLength - 1] of AnsiChar;
AWordCursor: PAnsiChar;
AReplaceLength, AInitialLength, I: Integer;
begin
Result := False;
if (AWordLength < 2) or (FReplaceTable.Count = 0) or not FCheckCompoundRep then
Exit;
for I := 0 to FReplaceTable.Count - 1 do
begin
AWordCursor := AWord;
AReplaceLength := StrLen(FReplaceTable[I].Replacement);
AInitialLength := StrLen(FReplaceTable[I].Initial);
AWordCursor := StrPos(AWordCursor, FReplaceTable[I].Initial);
while AWordCursor <> nil do
begin
StrCopy(AChangedWord, AWord);
if AWordCursor - AWord + AReplaceLength +
Integer(StrLen(AWordCursor + AInitialLength)) > MaxLineLength then
Break;
StrCopy(AChangedWord + (AWordCursor - AWord), FReplaceTable[I].Replacement);
StrCopy(AChangedWord + (AWordCursor - AWord) + AReplaceLength,
AWordCursor + AInitialLength);
if CompoundWordWithReplacedCharactersExists(AChangedWord,
strlen(AChangedWord), ATakenPrefix, ATakenSuffix) then
begin
Result := True;
Exit;
end;
Inc(AWordCursor);
AWordCursor := StrPos(AWordCursor, FReplaceTable[I].Initial);
end;
end;
end;
function TdxHunspellAffixManager.IsForbiddenByCheckCompoundPattern(const AWord: PAnsiChar;
AJoint: Integer; AFirstPartWordBase, ASecondPartWordBase: TdxHunspellWordItem): Boolean;
var
ALength, I: Integer;
begin
Result := False;
for I := 0 to FCheckCompoundPatternTable.Count - 1 do
begin
ALength := StrLen(FCheckCompoundPatternTable[I].Pattern);
if IsLeadingSubset(FCheckCompoundPatternTable[I].Pattern2, AWord + AJoint) and
((AFirstPartWordBase = nil) or (FCheckCompoundPatternTable[I].Condition = 0) or
AFirstPartWordBase.IsCompatibleWithFlag(FCheckCompoundPatternTable[I].Condition)) and
((ASecondPartWordBase = nil) or (FCheckCompoundPatternTable[I].Condition2 = 0) or
ASecondPartWordBase.IsCompatibleWithFlag(FCheckCompoundPatternTable[I].Condition2)) and
(ALength <> 0) and (AJoint > ALength) and
(StrLComp(AWord + AJoint - ALength, FCheckCompoundPatternTable[I].Pattern, ALength) = 0) then
begin
Result := True;
Break;
end;
end;
end;
function TdxHunspellAffixManager.IsJointUpperCaseExistAndForbid(const AWord: PAnsiChar; AJoint: Integer): Boolean;
var
A, B: AnsiChar;
begin
Result := False;
begin
A := (AWord + AJoint - 1)^;
B := (AWord + AJoint)^;
if (IsUpCase(A) or IsUpCase(B)) and (A <> '-') and (B <> '-') then
Result := FCheckCompoundCase;
end;
end;
function TdxHunspellAffixManager.IsWordPartsSuitCompoundRule(var AWords: PdxHunspellWordBaseTable;
AWordCount: SmallInt; AWordBaseItem: TdxHunspellWordItem;
ADefaultWords: PdxHunspellWordBaseTable; all: Boolean): Boolean;
type
TBackTrackingItem = record
MetacharacterPosition: SmallInt;
WordsIndex: SmallInt;
MatchedCharactersCount: Integer;
end;
var
ABackTrackingTable: array [0..MaxWordLength - 1] of TBackTrackingItem;
ABackTrackingIndex, AOldBackTrackingIndex, AFlagCursor, AFlagCursor2,
AMetacharacterPointer, AWordIndex: SmallInt;
I, J, AWordIndexMax: Integer;
AIsWordBaseItemCompatibleWithCompoundRule, AIsAllWordsCompatibleWithCompoundRule,
AIsWordsInitialized: Boolean;
AFlag: Word;
begin
Result := False;
if (AWordBaseItem.AffixFlags.Length = 0) or
(AWords = nil) and (ADefaultWords = nil) then
Exit;
AIsWordBaseItemCompatibleWithCompoundRule := False;
for I := 0 to FCompoundRuleTable.Count - 1 do
for J := 0 to FCompoundRuleTable[I].Length - 1 do
begin
AFlag := FCompoundRuleTable[I].Pattern[J];
if (AFlag <> Ord('*')) and (AFlag <> Ord('?')) and
AWordBaseItem.IsCompatibleWithFlag(AFlag) then
AIsWordBaseItemCompatibleWithCompoundRule := True;
end;
if AIsWordBaseItemCompatibleWithCompoundRule then
begin
AIsWordsInitialized := False;
if AWords = nil then
begin
AIsWordsInitialized := True;
AWords := ADefaultWords;
end;
AWords[AWordCount] := AWordBaseItem;
ABackTrackingIndex := 0;
I := 0;
while (I < FCompoundRuleTable.Count) and not Result do
begin
AFlagCursor := 0;
AWordIndex := 0;
AIsWordBaseItemCompatibleWithCompoundRule := True;
AIsAllWordsCompatibleWithCompoundRule := True;
repeat
while (AFlagCursor < FCompoundRuleTable[I].Length) and (AWordIndex <= AWordCount) do
begin
AMetacharacterPointer := AFlagCursor + 1;
AFlag := 0;
if AMetacharacterPointer < FCompoundRuleTable[I].Length then
AFlag := FCompoundRuleTable[I].Pattern[AMetacharacterPointer];
if (AMetacharacterPointer < FCompoundRuleTable[I].Length) and
((AFlag = Ord('*')) or (AFlag = Ord('?'))) then
begin
AWordIndexMax := IfThen(AFlag = Ord('?'), AWordIndex, AWordCount);
AIsAllWordsCompatibleWithCompoundRule := True;
Inc(AFlagCursor, 2);
ABackTrackingTable[ABackTrackingIndex].MetacharacterPosition := AFlagCursor;
ABackTrackingTable[ABackTrackingIndex].WordsIndex := AWordIndex;
while AWordIndex <= AWordIndexMax do
begin
if not AWords[AWordIndex].IsCompatibleWithFlag(FCompoundRuleTable[I].Pattern[AFlagCursor - 2]) then
begin
AIsAllWordsCompatibleWithCompoundRule := False;
Break;
end;
Inc(AWordIndex);
end;
if AWordIndex <= AWordCount then
AIsAllWordsCompatibleWithCompoundRule := False;
ABackTrackingTable[ABackTrackingIndex].MatchedCharactersCount :=
AWordIndex - ABackTrackingTable[ABackTrackingIndex].WordsIndex;
if ABackTrackingTable[ABackTrackingIndex].MatchedCharactersCount > 0 then
Inc(ABackTrackingIndex);
if AIsAllWordsCompatibleWithCompoundRule then
Break;
end
else
begin
AIsAllWordsCompatibleWithCompoundRule := True;
if (AWords[AWordIndex] = nil) or
not AWords[AWordIndex].IsCompatibleWithFlag(FCompoundRuleTable[I].Pattern[AFlagCursor]) then
begin
AIsWordBaseItemCompatibleWithCompoundRule := False;
Break;
end;
Inc(AFlagCursor);
Inc(AWordIndex);
if (FCompoundRuleTable[I].Length = AFlagCursor) and not(AWordIndex > AWordCount) then
AIsWordBaseItemCompatibleWithCompoundRule := False;
end;
end;
if AIsWordBaseItemCompatibleWithCompoundRule and AIsAllWordsCompatibleWithCompoundRule then
begin
AFlagCursor2 := AFlagCursor;
while (AFlagCursor2 + 1 < FCompoundRuleTable[I].Length) and
((FCompoundRuleTable[I].Pattern[AFlagCursor2 + 1] = Ord('*')) or
(FCompoundRuleTable[I].Pattern[AFlagCursor2 + 1] = Ord('?'))) do
Inc(AFlagCursor2, 2);
if FCompoundRuleTable[I].Length <= AFlagCursor2 then
begin
Result := True;
Break;
end;
end;
if ABackTrackingIndex > 0 then
begin
repeat
AIsWordBaseItemCompatibleWithCompoundRule := True;
Dec(ABackTrackingTable[ABackTrackingIndex - 1].MatchedCharactersCount);
AFlagCursor := ABackTrackingTable[ABackTrackingIndex - 1].MetacharacterPosition;
AWordIndex := ABackTrackingTable[ABackTrackingIndex - 1].WordsIndex +
ABackTrackingTable[ABackTrackingIndex - 1].MatchedCharactersCount;
AOldBackTrackingIndex := ABackTrackingIndex;
Dec(ABackTrackingIndex);
until not((ABackTrackingTable[AOldBackTrackingIndex - 1].MatchedCharactersCount < 0) and
(ABackTrackingIndex > 0));
if not(ABackTrackingTable[AOldBackTrackingIndex - 1].MatchedCharactersCount < 0) then
ABackTrackingIndex := AOldBackTrackingIndex;
end;
until ABackTrackingIndex = 0;
if AIsWordBaseItemCompatibleWithCompoundRule and AIsAllWordsCompatibleWithCompoundRule and (not all or (FCompoundRuleTable[I].Length <= AFlagCursor)) then
Result := True;
while AIsWordBaseItemCompatibleWithCompoundRule and AIsAllWordsCompatibleWithCompoundRule and
(AFlagCursor + 1 < FCompoundRuleTable[I].Length) and
((FCompoundRuleTable[I].Pattern[AFlagCursor + 1] = Ord('*')) or (FCompoundRuleTable[I].Pattern[AFlagCursor + 1] = Ord('?'))) do
Inc(AFlagCursor, 2);
if AIsWordBaseItemCompatibleWithCompoundRule and AIsAllWordsCompatibleWithCompoundRule and
(FCompoundRuleTable[I].Length <= AFlagCursor) then
Result := True;
Inc(I);
end;
if not Result then
begin
AWords[AWordCount] := nil;
if AIsWordsInitialized then
AWords := nil;
end;
end;
end;
function TdxHunspellAffixManager.CompoundWordWithReplacedCharactersExists(
const AWord: PAnsiChar; AWordLength: Integer; var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix): Boolean;
begin
Result := True;
if Lookup(AWord) = nil then
if AffixCheck(AWord, AWordLength, ATakenPrefix, ATakenSuffix) = nil then
Result := False;
end;
function TdxHunspellAffixManager.GetSyllableCount(const AWord: PAnsiChar; AWordLength: Integer): SmallInt;
var
I: Integer;
begin
Result := 0;
if FMaxCompoundSyllable = 0 then
Exit;
if not FIsUTF8 then
begin
for I := 0 to AWordLength - 1 do
if StrScan(FCompoundVowels, (AWord + I)^) <> nil then
Inc(Result);
end
else
//TODO:
;
end;
procedure TdxHunspellAffixManager.GetCompoundWordJointRange(var ACompoundWordJointMin,
ACompoundWordJointMax: Integer; const AWord: PAnsiChar; AWordLength: Integer);
var
I: Integer;
begin
if FIsUTF8 then
begin
ACompoundWordJointMin := 0;
I := 0;
while (I < FCompoundPartMin) and ((AWord + ACompoundWordJointMin) <> nil) do
begin
Inc(ACompoundWordJointMin);
while Ord((AWord + ACompoundWordJointMin)^) and $c0 = $80 do
Inc(ACompoundWordJointMin);
Inc(I);
end;
ACompoundWordJointMax := AWordLength;
I := 0;
while (I < FCompoundPartMin - 1) and (ACompoundWordJointMax <> 0) do
begin
Dec(ACompoundWordJointMax);
while Ord((AWord + ACompoundWordJointMax)^) and $c0 = $80 do
Dec(ACompoundWordJointMax);
Inc(I);
end;
end
else
begin
ACompoundWordJointMin := FCompoundPartMin;
ACompoundWordJointMax := AWordLength - FCompoundPartMin + 1;
end;
end;
function TdxHunspellAffixManager.CompoundCheck(const AWord: PAnsiChar;
AWordPartIndex, ASyllableCount, AWordPartMaxCount, wnum: SmallInt; words: PdxHunspellWordBaseTable = nil;
hu_mov_rule: Boolean = False; ASuggest: Boolean = False): TdxHunspellWordItem;
var
ACompoundWordJoint, AWordLength, ACompoundWordJointMin, ACompoundWordJointMax,
ATableIndex, AInitialWordJoint: Integer;
ACheckedPrefix: Boolean;
ADoubleCharacter, ACheckWordWithoutTripleRemoving: Boolean;
ASyllableCountStore, ASyllableCountStore2, AWordPartIndexStore, AWordPartIndexStore2: SmallInt;
AWordBaseItem, AFirstPartWordBaseItem: TdxHunspellWordItem;
ACompoundRuleWords: array[0..MaxWordLength] of TdxHunspellWordItem;
AInitialWordForm: TWordFormArray;
AJointCharacter: AnsiChar;
ACompoundWordPart: TdxCompoundWordPart;
ATakenPrefix: TdxPrefix;
ATakenSuffix: TdxSuffix;
function CheckSimpleWordWithReplacedCharacters: TdxHunspellWordItem;
begin
if IsSimpleWordWithReplacedCharacters(AWord, AWordLength, ATakenPrefix, ATakenSuffix) then
Result := nil
else
Result := AFirstPartWordBaseItem;
end;
procedure HungarianSyllableProcess;
begin
if IsHungarian then
begin
Inc(ASyllableCount, GetSyllableCount(AInitialWordForm, AInitialWordJoint));
if (ATakenPrefix <> nil) and (GetSyllableCount(ATakenPrefix.AppendString, StrLen(ATakenPrefix.AppendString)) > 1) then
Inc(AWordPartIndex);
end;
end;
procedure HungarianDecreaseSyllableCount;
begin
if (AWordBaseItem <> nil) and IsHungarian and
AWordBaseItem.IsCompatibleWithFlag(Ord('I')) and
not AWordBaseItem.IsCompatibleWithFlag(Ord('J')) then
Dec(ASyllableCount);
end;
begin
Result := nil;
AWordLength := StrLen(AWord);
if IsSimpleWordWithReplacedCharacters(AWord, AWordLength, ATakenPrefix, ATakenSuffix) then
Exit;
AWordBaseItem := nil;
ADoubleCharacter := False;
ACheckWordWithoutTripleRemoving := False;
ATableIndex := 0;
GetCompoundWordJointRange(ACompoundWordJointMin, ACompoundWordJointMax, AWord, AWordLength);
StrCopy(AInitialWordForm, AWord);
ACompoundWordJoint := ACompoundWordJointMin;
while ACompoundWordJoint < ACompoundWordJointMax do
begin
AWordLength := StrLen(AWord);
GetCompoundWordJointRange(ACompoundWordJointMin, ACompoundWordJointMax, AWord, AWordLength);
StrCopy(AInitialWordForm, AWord);
ASyllableCountStore := ASyllableCount;
AWordPartIndexStore := AWordPartIndex;
ACheckedPrefix := False;
if IsUTF8 then
begin
//TODO:
end;
repeat
AInitialWordJoint := ACompoundWordJoint;
if ATableIndex > 0 then
begin
while (ATableIndex <= FCheckCompoundPatternTable.Count) and
((FCheckCompoundPatternTable[ATableIndex - 1].Pattern3 = nil) or
(StrLComp(AWord + ACompoundWordJoint, FCheckCompoundPatternTable[ATableIndex - 1].Pattern3,
StrLen(FCheckCompoundPatternTable[ATableIndex - 1].Pattern3)) <> 0)) do
Inc(ATableIndex);
if ATableIndex > FCheckCompoundPatternTable.Count then
Break;
StrCopy(AInitialWordForm + ACompoundWordJoint, FCheckCompoundPatternTable[ATableIndex - 1].Pattern);
AInitialWordJoint := ACompoundWordJoint;
Inc(AInitialWordJoint, StrLen(FCheckCompoundPatternTable[ATableIndex - 1].Pattern));
StrCopy(AInitialWordForm + AInitialWordJoint, FCheckCompoundPatternTable[ATableIndex - 1].Pattern2);
StrCopy(AInitialWordForm + AInitialWordJoint + StrLen(FCheckCompoundPatternTable[ATableIndex - 1].Pattern2),
AWord + ACompoundWordJoint + StrLen(FCheckCompoundPatternTable[ATableIndex - 1].Pattern3));
Inc(AWordLength, StrLen(FCheckCompoundPatternTable[ATableIndex - 1].Pattern) +
StrLen(FCheckCompoundPatternTable[ATableIndex - 1].Pattern2) -
StrLen(FCheckCompoundPatternTable[ATableIndex - 1].Pattern3));
GetCompoundWordJointRange(ACompoundWordJointMin, ACompoundWordJointMax,
AInitialWordForm, AWordLength);
ACompoundWordJointMax := AWordLength - FCompoundPartMin + 1; //TODO: Remove after UTF8 removing, because GetCompoundWordJointRange hes this line
end;
AJointCharacter := AInitialWordForm[AInitialWordJoint];
AInitialWordForm[AInitialWordJoint] := #0;
ATakenSuffix := nil;
ATakenPrefix := nil;
AWordBaseItem := Lookup(AInitialWordForm);
while (AWordBaseItem <> nil) and not hu_mov_rule and
(UseWithAffixOnly(AWordBaseItem) or
not ((IsWordPartSuitsCompoundFlags(AWordBaseItem, AWordPartIndex, True, words) or
((words <> nil) or (AWordPartIndex = 0)) and
IsWordPartsSuitCompoundRule(words, wnum, AWordBaseItem, @ACompoundRuleWords, False)) and
IsWordPartSuitsCheckCompoundPatternTable(AWordBaseItem, ATableIndex, True))) do
AWordBaseItem := AWordBaseItem.NextHomonym;
if AWordBaseItem = nil then
begin
ACompoundWordPart := cwpFirst;
if hu_mov_rule then
ACompoundWordPart := cwpOther;
if (FCompoundFlag <> 0) then
begin
AWordBaseItem := ProcessPrefixCheck(AInitialWordForm, AInitialWordJoint,
ATakenPrefix, ATakenSuffix, ACompoundWordPart, FCompoundFlag);
if AWordBaseItem = nil then
begin
AWordBaseItem := ProcessSuffixCheck(AInitialWordForm, AInitialWordJoint,
0, nil, ATakenSuffix, nil, 0, nil, NullFlag, FCompoundFlag, ACompoundWordPart);
if (AWordBaseItem <> nil) and not hu_mov_rule and
(((FCompoundForbidFlag <> 0) and ATakenSuffix.IsCompatibleWithFlag(FCompoundForbidFlag)) or
((FCompoundEnd <> 0) and ATakenSuffix.IsCompatibleWithFlag(FCompoundEnd))) then
AWordBaseItem := nil;
end;
end;
if (AWordBaseItem <> nil) or
(((AWordPartIndex = 0) and (FCompoundBegin <> 0) and
ProcessSuffixOrPrefixCheck(AInitialWordForm, AInitialWordJoint,
FCompoundBegin, ACompoundWordPart, AWordBaseItem, ATakenPrefix, ATakenSuffix)) or
((AWordPartIndex > 0) and (FCompoundMiddle <> 0) and
ProcessSuffixOrPrefixCheck(AInitialWordForm, AInitialWordJoint,
FCompoundMiddle, ACompoundWordPart, AWordBaseItem, ATakenPrefix, ATakenSuffix))) then
ACheckedPrefix := True;
end
else
if UseWithAffixOnly(AWordBaseItem) or
IsForbiddenOrNoSuggestWord(AWordBaseItem, ASuggest) then
begin
AInitialWordForm[AInitialWordJoint] := AJointCharacter;
Continue;
end;
if (AWordBaseItem <> nil) and not hu_mov_rule and
(((ATakenPrefix <> nil) and ATakenPrefix.IsCompatibleWithFlag(FCompoundForbidFlag)) or
((ATakenSuffix <> nil) and ATakenSuffix.IsCompatibleWithFlag(FCompoundForbidFlag))) then
AWordBaseItem := nil;
if (AWordBaseItem <> nil) and not ACheckedPrefix and (FCompoundEnd <> 0) and not hu_mov_rule and
(((ATakenPrefix <> nil) and ATakenPrefix.IsCompatibleWithFlag(FCompoundEnd)) or
((ATakenSuffix <> nil) and ATakenSuffix.IsCompatibleWithFlag(FCompoundEnd))) then
AWordBaseItem := nil;
if (AWordBaseItem <> nil) and not ACheckedPrefix and (AWordPartIndex = 0) and
(FCompoundMiddle <> 0) and not hu_mov_rule and
(((ATakenPrefix <> nil) and ATakenPrefix.IsCompatibleWithFlag(FCompoundMiddle)) or
((ATakenSuffix <> nil) and ATakenSuffix.IsCompatibleWithFlag(FCompoundMiddle))) then
AWordBaseItem := nil;
if IsForbiddenOrNoSuggestWord(AWordBaseItem, ASuggest) then
begin
Result := nil;
Exit;
end;
CompoundRootCheck(AWordBaseItem, AWordPartIndex);
if ((AWordBaseItem <> nil) and
(ACheckedPrefix or ((words <> nil) and (words[wnum] <> nil)) or
CanBeFirstPartInCompoundWord(AWordBaseItem, AWordPartIndexStore) or
HungarianCheck(AWordBaseItem, hu_mov_rule)) and
IsWordPartSuitsCheckCompoundPatternTable(AWordBaseItem, ATableIndex, True) and
not ((ATableIndex = 0) and (words = nil) and
(IsTripleLettersExistAndForbid(AWord, AInitialWordJoint) or
IsJointUpperCaseExistAndForbid(AWord, AInitialWordJoint)))) or
HungarianCheck2(AWordBaseItem, AInitialWordForm, ACompoundWordJoint, hu_mov_rule, ATakenPrefix, ATakenSuffix) then
begin
HungarianSyllableProcess;
// Second part of word
AFirstPartWordBaseItem := AWordBaseItem;
AInitialWordForm[AInitialWordJoint] := AJointCharacter;
repeat
if FSimplifiedTriple then
begin
if ADoubleCharacter then
begin
ACheckWordWithoutTripleRemoving := True;
Dec(AInitialWordJoint);
end
else
if (AInitialWordJoint > 2) and ((AWord + AInitialWordJoint - 1)^ = (AWord + AInitialWordJoint - 2)^) then
ADoubleCharacter := True;
end;
AWordBaseItem := Lookup(AInitialWordForm + AInitialWordJoint);
while (AWordBaseItem <> nil) and
(UseWithAffixOnly(AWordBaseItem) or
not ((IsWordPartSuitsCompoundFlags(AWordBaseItem, 0, False, words) or
IsWordPartsSuitCompoundRule(words, wnum + 1, AWordBaseItem, nil, True)) and
IsWordPartSuitsCheckCompoundPatternTable(AWordBaseItem, ATableIndex, False))) do
AWordBaseItem := AWordBaseItem.NextHomonym;
if (AWordBaseItem <> nil) and (words <> nil) and (words[wnum + 1] <> nil) then
begin
Result := AFirstPartWordBaseItem;
Exit;
end;
if IsForbiddenOrNoSuggestWord(AWordBaseItem, ASuggest) then
begin
Result := nil;
Exit;
end;
ASyllableCountStore2 := ASyllableCount;
AWordPartIndexStore2 := AWordPartIndex;
HungarianDecreaseSyllableCount;
CompoundRootCheck(AWordBaseItem, AWordPartIndex);
if (AWordBaseItem <> nil) and
(AWordBaseItem.IsCompatibleWithFlag(FCompoundFlag) or
AWordBaseItem.IsCompatibleWithFlag(FCompoundEnd)) and
(((FCompoundWordMax = -1) or (AWordPartIndex + 1 < FCompoundWordMax)) or
((FMaxCompoundSyllable <> 0) and
(ASyllableCount + GetSyllableCount(AWordBaseItem.WordBase, AWordBaseItem.clen) <= FMaxCompoundSyllable))) and
((ATableIndex <> 0) or
not IsForbiddenByCheckCompoundPattern(AWord, ACompoundWordJoint, AFirstPartWordBaseItem, AWordBaseItem)) and
(not FCheckCompoundDup or (AWordBaseItem <> AFirstPartWordBaseItem)) and
IsWordPartSuitsCheckCompoundPatternTable(AWordBaseItem, ATableIndex, False) then
begin
Result := AFirstPartWordBaseItem;
Exit;
end;
ASyllableCount := ASyllableCountStore2;
AWordPartIndex := AWordPartIndexStore2;
ATakenSuffix := nil;
FSavedSuffixInfo.Flag := NullFlag;
if FCompoundFlag <> 0 then
AWordBaseItem := AffixCheck(AWord + AInitialWordJoint, StrLen(AWord + AInitialWordJoint),
ATakenPrefix, ATakenSuffix, FCompoundFlag, cwpLast)
else
AWordBaseItem := nil;
if (AWordBaseItem = nil) and (FCompoundEnd <> 0) then
begin
ATakenSuffix := nil;
ATakenPrefix := nil;
AWordBaseItem := AffixCheck(AWord + AInitialWordJoint, StrLen(AWord + AInitialWordJoint),
ATakenPrefix, ATakenSuffix, FCompoundEnd, cwpLast);
end;
if (AWordBaseItem = nil) and (FCompoundRuleTable.Count <> 0) and (words <> nil) then
begin
AWordBaseItem := AffixCheck(AWord + AInitialWordJoint, StrLen(AWord + AInitialWordJoint),
ATakenPrefix, ATakenSuffix, 0, cwpLast);
if (AWordBaseItem <> nil) and IsWordPartsSuitCompoundRule(words, wnum + 1, AWordBaseItem, nil, True) then
begin
Result := AFirstPartWordBaseItem;
Exit;
end;
AWordBaseItem := nil;
end;
if (AWordBaseItem <> nil) and not ((ATableIndex = 0) or (FCheckCompoundPatternTable[ATableIndex - 1].Condition2 = NullFlag) or
AWordBaseItem.IsCompatibleWithFlag(FCheckCompoundPatternTable[ATableIndex - 1].Condition2)) then
AWordBaseItem := nil;
if (AWordBaseItem <> nil) and (ATableIndex = 0) and
IsForbiddenByCheckCompoundPattern(AWord, AInitialWordJoint, AFirstPartWordBaseItem, AWordBaseItem) then
AWordBaseItem := nil;
if (AWordBaseItem <> nil) and
(((ATakenPrefix <> nil) and
ATakenPrefix.IsCompatibleWithFlag(FCompoundForbidFlag)) or
((ATakenSuffix <> nil) and
ATakenSuffix.IsCompatibleWithFlag(FCompoundForbidFlag))) then
AWordBaseItem := nil;
if IsForbiddenOrNoSuggestWord(AWordBaseItem, ASuggest) then
begin
Result := nil;
Exit;
end;
if IsHungarian then
begin
Inc(ASyllableCount, GetSyllableCount(AWord + AInitialWordJoint, StrLen(AWord + AInitialWordJoint)));
if FSavedSuffixInfo.AppendString <> nil then
Dec(ASyllableCount, GetSyllableCount(FSavedSuffixInfo.AppendString, StrLen(FSavedSuffixInfo.AppendString)));
if (ATakenPrefix <> nil) and (GetSyllableCount(ATakenPrefix.AppendString, StrLen(ATakenPrefix.AppendString)) > 1) then
Inc(AWordPartIndex);
if FSyllableNum <> nil then
case Chr(FSavedSuffixInfo.Flag) of
'c': Inc(ASyllableCount, 2);
'J': Inc(ASyllableCount, 1);
'I': if AWordBaseItem.IsCompatibleWithFlag(Ord('J')) then Inc(ASyllableCount, 1);
end;
end;
CompoundRootCheck(AWordBaseItem, AWordPartIndex);
if (AWordBaseItem <> nil) and
(((FCompoundWordMax = -1) or (AWordPartIndex + 1 < FCompoundWordMax)) or
((FMaxCompoundSyllable <> 0) and (ASyllableCount <= FMaxCompoundSyllable))) and
(not FCheckCompoundDup or (AWordBaseItem <> AFirstPartWordBaseItem)) then
begin
Result := AFirstPartWordBaseItem;
Exit;
end;
ASyllableCount := ASyllableCountStore2;
AWordPartIndex := AWordPartIndexStore2;
if AWordPartIndex < AWordPartMaxCount then
begin
AWordBaseItem := CompoundCheck(AInitialWordForm + AInitialWordJoint, AWordPartIndex + 1,
ASyllableCount, AWordPartMaxCount, wnum + 1, words, False, ASuggest);
if (AWordBaseItem <> nil) and (
not ((ATableIndex = 0) xor IsForbiddenByCheckCompoundPattern(AWord,
AInitialWordJoint, AFirstPartWordBaseItem, AWordBaseItem))) then
AWordBaseItem := nil;
end
else
AWordBaseItem := nil;
if AWordBaseItem <> nil then
begin
Result := AFirstPartWordBaseItem;
Exit;
end;
until not ADoubleCharacter or ACheckWordWithoutTripleRemoving;
if ACheckWordWithoutTripleRemoving then
begin
Inc(ACompoundWordJoint);
ACheckWordWithoutTripleRemoving := False;
ADoubleCharacter := False;
end;
end;
Inc(ATableIndex);
until not (FCheckCompoundPatternTable.IsSimplified and (ATableIndex <= FCheckCompoundPatternTable.Count));
ATableIndex := 0;
AWordPartIndex := AWordPartIndexStore;
ASyllableCount := ASyllableCountStore;
Inc(ACompoundWordJoint);
end;
end;
function TdxHunspellAffixManager.ProcessSuffixCheck(const AWord: PAnsiChar; AWordLength, AOptions: Integer;
APrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; wlst: PPAnsiChar; maxSug: Integer; ns: PInteger;
const ACompatibleFlag, ACompoundPartFlag: Word; ACompoundWordPart: TdxCompoundWordPart): TdxHunspellWordItem;
var
ASuffix: TdxSuffix;
AIncompatibleFlag: Word;
begin
Result := nil;
AIncompatibleFlag := IfThen(ACompoundWordPart <> cwpNone, NullFlag, FOnlyInCompound);
ASuffix := TdxSuffix(FSuffixTableArrangedByAppendString[0]);
while (ASuffix <> nil) and (Result = nil) do
begin
if (ACompatibleFlag = 0) or (ASuffix.CompatibleFlags <> nil) then
begin
if ASuffix.CanUseInTheMiddleOfCompoundWords(ACompoundWordPart) and
AreAffixesBothCircumfixesOrNot(APrefix, ASuffix) and
ASuffix.CanUseInSimpleWordsOrIsFogemorpheme(ACompoundWordPart) and
((ACompatibleFlag <> NullFlag) or not ASuffix.IsCompatibleWithFlag(FNeedAffix) or
(APrefix <> nil) and not APrefix.IsCompatibleWithFlag(FNeedAffix)) then
begin
Result := ASuffix.CheckWord(AWord, AWordLength, AOptions, APrefix, wlst, maxSug, ns,
ACompatibleFlag, ACompoundPartFlag, AIncompatibleFlag);
if Result <> nil then
ATakenSuffix := ASuffix;
end;
end;
ASuffix := TdxSuffix(ASuffix.Next);
end;
if Result = nil then
begin
ASuffix := TdxSuffix(FSuffixTableArrangedByAppendString[Ord((AWord + AWordLength - 1)^)]);
while (ASuffix <> nil) and (Result = nil) do
begin
if IsTrailingReversedSubset(ASuffix.AppendString, AWord + AWordLength - 1, AWordLength) then
begin
if ASuffix.CanUseInTheMiddleOfCompoundWords(ACompoundWordPart) and
AreAffixesBothCircumfixesOrNot(APrefix, ASuffix) and
ASuffix.CanUseInSimpleWordsOrIsFogemorpheme(ACompoundWordPart) and
((ACompatibleFlag <> 0) or not ASuffix.IsCompatibleWithFlag(FNeedAffix) or
(APrefix <> nil) and not APrefix.IsCompatibleWithFlag(FNeedAffix)) then
begin
Result := ASuffix.CheckWord(AWord, AWordLength, AOptions, APrefix, wlst, maxSug, ns,
ACompatibleFlag, ACompoundPartFlag, AIncompatibleFlag);
if Result <> nil then
begin
ATakenSuffix := ASuffix;
FSavedSuffixInfo.Flag := ASuffix.Flag;
if ASuffix.CompatibleFlags = nil then
FSavedSuffixInfo.AppendString := ASuffix.AppendString;
end;
end;
ASuffix := TdxSuffix(ASuffix.NextSimilar);
end
else
ASuffix := TdxSuffix(ASuffix.NextDifferent);
end;
end;
end;
function TdxHunspellAffixManager.ProcessTwoSuffixCheck(const AWord: PAnsiChar; AWordLength, AOptions: Integer;
APrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; const ACompoundPartFlag: Word): TdxHunspellWordItem;
var
ASuffix: TdxSuffix;
begin
Result := nil;
ASuffix := TdxSuffix(FSuffixTableArrangedByAppendString[0]);
while (ASuffix <> nil) and (Result = nil) do
begin
if FCompatibleFlags[ASuffix.Flag] then
Result := ASuffix.MakeInitialWordFormAndProcessSuffixCheck(AWord,
AWordLength, AOptions, APrefix, ATakenSuffix, ACompoundPartFlag);
ASuffix := TdxSuffix(ASuffix.Next);
end;
if Result = nil then
begin
ASuffix := TdxSuffix(FSuffixTableArrangedByAppendString[Ord((AWord + AWordLength - 1)^)]);
while (ASuffix <> nil) and (Result = nil) do
begin
if IsTrailingReversedSubset(ASuffix.AppendString, AWord + AWordLength - 1, AWordLength) then
begin
if FCompatibleFlags[ASuffix.Flag] then
begin
Result := ASuffix.MakeInitialWordFormAndProcessSuffixCheck(AWord,
AWordLength, AOptions, APrefix, ATakenSuffix, ACompoundPartFlag);
if Result <> nil then
begin
FSavedSuffixInfo.Flag := ASuffix.Flag;
if ASuffix.CompatibleFlags = nil then
FSavedSuffixInfo.AppendString := ASuffix.AppendString;
end;
end;
ASuffix := TdxSuffix(ASuffix.NextSimilar);
end
else
ASuffix := TdxSuffix(ASuffix.NextDifferent);
end;
end;
end;
function TdxHunspellAffixManager.AffixCheck(const AWord: PAnsiChar; AWordLength: Integer;
var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; const ACompoundPartFlag: Word;
ACompoundWordPart: TdxCompoundWordPart): TdxHunspellWordItem;
begin
Result := ProcessPrefixCheck(AWord, AWordLength, ATakenPrefix, ATakenSuffix,
ACompoundWordPart, ACompoundPartFlag);
if Result = nil then
begin
Result := ProcessSuffixCheck(AWord, AWordLength, 0, nil, ATakenSuffix, nil,
0, nil, NullFlag, ACompoundPartFlag, ACompoundWordPart);
if FCompatibleFlagsExist then
begin
ATakenSuffix := nil;
ATakenPrefix := nil;
if Result = nil then
begin
Result := ProcessTwoSuffixCheck(AWord, AWordLength, 0, nil, ATakenSuffix, ACompoundPartFlag);
if Result = nil then
Result := ProcessPrefixWithSuffixesCheck(AWord, AWordLength,
ATakenPrefix, ATakenSuffix, cwpNone, ACompoundPartFlag);
end;
end;
end;
end;
function TdxHunspellAffixManager.EncodeFlag(AFlag: Word): PAnsiChar;
begin
Result := FWordBaseManager.EncodeFlag(AFlag);
end;
procedure TdxHunspellAffixManager.SetCompatibleFlags(AIndex: Integer; AValue: Boolean);
begin
FCompatibleFlags[AIndex] := AValue;
end;
function TdxHunspellAffixManager.Lookup(const AWord: PAnsiChar): TdxHunspellWordItem;
begin
Result := FWordBaseManager.Lookup(AWord);
end;
function TdxHunspellAffixManager.ParseCompoundSyllable(ALine: PAnsiChar;
AAffixFileManager: TdxHunspellReader): Boolean;
var
ALineCursor, APiece: PAnsiChar;
I, APartCount: Integer;
begin
Result := False;
ALineCursor := ALine;
APiece := StrSeparate(@ALineCursor, #0);
APartCount := 0;
I := 0;
while APiece <> nil do
begin
if APiece^ <> #0 then
begin
case I of
0: Inc(APartCount);
1: begin
FMaxCompoundSyllable := StrInt(APiece);
Inc(APartCount);
end;
2: begin
if not IsUTF8 then
FCompoundVowels := StrNew(APiece)
else
begin
//TODO:
end;
Inc(APartCount);
end;
end;
Inc(I);
end;
APiece := StrSeparate(@ALineCursor, #0);
end;
if APartCount < 2 then
begin
Result := True;
Exit;
end;
if APartCount = 2 then
FCompoundVowels := StrNew(PAnsiChar('aeiouAEIOU'));
end;
function TdxHunspellAffixManager.ParseRep(ALine: PAnsiChar; AAffixFileManager: TdxHunspellReader): Boolean;
begin
Result := not FReplaceTable.ReadData(ALine, AAffixFileManager);
end;
function TdxHunspellAffixManager.AreAffixesBothCircumfixesOrNot(APrefix, ASuffix: TdxAffix): Boolean;
begin
Result := (FCircumfix = NullFlag) or
not (((APrefix <> nil) and APrefix.IsCircumfix) xor ASuffix.IsCircumfix);
end;
function TdxHunspellAffixManager.CanBeFirstPartInCompoundWord(
AWordBaseItem: TdxHunspellWordItem; AWordPartIndex: Cardinal): Boolean;
begin
Result := ((FCompoundFlag <> 0) and
AWordBaseItem.IsCompatibleWithFlag(FCompoundFlag)) or
((AWordPartIndex = 0) and (FCompoundBegin <> 0) and
AWordBaseItem.IsCompatibleWithFlag(FCompoundBegin)) or
((AWordPartIndex > 0) and (FCompoundMiddle <> 0) and
AWordBaseItem.IsCompatibleWithFlag(FCompoundMiddle));
end;
procedure TdxHunspellAffixManager.CompoundRootCheck(
AWordBaseItem: TdxHunspellWordItem; var AWordPartIndex: SmallInt);
begin
if (AWordBaseItem <> nil) and (FCompoundRoot <> 0) and
AWordBaseItem.IsCompatibleWithFlag(FCompoundRoot) then
Inc(AWordPartIndex);
end;
function TdxHunspellAffixManager.IsForbiddenOrNoSuggestWord(
AWordBaseItem: TdxHunspellWordItem; ASuggest: Boolean): Boolean;
begin
Result := (AWordBaseItem <> nil) and
(AWordBaseItem.IsCompatibleWithFlag(FForbiddenWord) or
(ASuggest and (FNoSuggest <> 0) and AWordBaseItem.IsCompatibleWithFlag(FNoSuggest)));
end;
function TdxHunspellAffixManager.IsWordPartSuitsCheckCompoundPatternTable(
AWordBaseItem: TdxHunspellWordItem; ATableIndex: Integer; AIsFirstWordPart: Boolean): Boolean;
var
AFlag: Word;
begin
Result := ATableIndex = 0;
if not Result then
begin
if AIsFirstWordPart then
AFlag := FCheckCompoundPatternTable[ATableIndex - 1].Condition
else
AFlag := FCheckCompoundPatternTable[ATableIndex - 1].Condition2;
Result := (AFlag = NullFlag) or AWordBaseItem.IsCompatibleWithFlag(AFlag);
end;
end;
function TdxHunspellAffixManager.IsWordPartSuitsCompoundFlags(AWordBaseItem: TdxHunspellWordItem;
AWordPartIndex: SmallInt; AIsFirstWordPart: Boolean; words: PdxHunspellWordBaseTable): Boolean;
begin
Result := (words = nil) and AWordBaseItem.IsCompatibleWithFlag(FCompoundFlag);
if not Result then
begin
if AIsFirstWordPart then
Result := ((AWordPartIndex = 0) and
AWordBaseItem.IsCompatibleWithFlag(FCompoundBegin)) or
((AWordPartIndex <> 0) and (words = nil) and
AWordBaseItem.IsCompatibleWithFlag(FCompoundMiddle))
else
Result := (words = nil) and AWordBaseItem.IsCompatibleWithFlag(FCompoundEnd);
end;
end;
function TdxHunspellAffixManager.IsTripleLettersExistAndForbid(AWord: PAnsiChar; AJoint: Cardinal): Boolean;
begin
Result := FCheckCompoundTriple and
(AWord[AJoint - 1] = AWord[AJoint]) and (
((AJoint > 1) and (AWord[AJoint - 1] = AWord[AJoint - 2])) or
((AJoint + 1 < StrLen(AWord)) and (AWord[AJoint - 1] = AWord[AJoint + 1])));
end;
function TdxHunspellAffixManager.UseWithAffixOnly(AWordBaseItem: TdxHunspellWordItem): Boolean;
begin
Result := (FNeedAffix <> 0) and AWordBaseItem.IsCompatibleWithFlag(FNeedAffix);
end;
function TdxHunspellAffixManager.HungarianCheck(AWordBaseItem: TdxHunspellWordItem;
hu_mov_rule: Boolean): Boolean;
begin
Result := IsHungarian and hu_mov_rule and (
AWordBaseItem.IsCompatibleWithFlag(Ord('F')) or
AWordBaseItem.IsCompatibleWithFlag(Ord('G')) or
AWordBaseItem.IsCompatibleWithFlag(Ord('H')));
end;
function TdxHunspellAffixManager.HungarianCheck2(var AWordBaseItem: TdxHunspellWordItem;
AInitialWordForm: TWordFormArray; ACompoundWordJoint: Integer;
hu_mov_rule: Boolean; var ATakenPrefix: TdxPrefix; var ATakenSuffix: TdxSuffix): Boolean;
function DoAffixCheck: Boolean;
begin
AWordBaseItem := AffixCheck(AInitialWordForm, ACompoundWordJoint, ATakenPrefix, ATakenSuffix);
Result := AWordBaseItem <> nil;
end;
begin
Result := (AWordBaseItem = nil) and IsHungarian and hu_mov_rule and DoAffixCheck and
((ATakenSuffix <> nil) and (ATakenSuffix.IsCompatibleWithFlag(Ord('x')) or ATakenSuffix.IsCompatibleWithFlag(Ord('%'))));
end;
function TdxHunspellAffixManager.ParseAffix(ALine: PAnsiChar; const IsPrefix: Boolean;
AAffixFileManager: TdxHunspellReader; AExistentAffixFlags: TdxExistentAffixFlags): Boolean;
var
AAffixItem: TdxAffixItemTable;
begin
if IsPrefix then
AAffixItem := TdxPrefixItemTable.Create(FWordBaseManager, Self, AExistentAffixFlags)
else
AAffixItem := TdxSuffixItemTable.Create(FWordBaseManager, Self, AExistentAffixFlags);
try
Result := not AAffixItem.ReadData(ALine, AAffixFileManager);
if not Result then
AAffixItem.BuildAffixes
else
dxHunspellError(AAffixItem.Flag + ' affix is invalid in file ' + FAffixFilePath);
finally
AAffixItem.Free;
end;
end;
function TdxHunspellAffixManager.GetIsCompoundWordsAvailable: Boolean;
begin
Result := (FCompoundFlag <> NullFlag) or (FCompoundBegin <> NullFlag) or
(FCompoundRuleTable.Count > 0);
end;
function TdxHunspellAffixManager.GetParseClasses: TObjectList;
begin
Result := TObjectList.Create;
Result.Add(TTryReader.Create(Self));
Result.Add(TSetReader.Create(Self));
Result.Add(TComplexPrefixesReader.Create(Self));
Result.Add(TCompoundFlagReader.Create(Self));
Result.Add(TCompoundBeginReader.Create(Self));
Result.Add(TCompoundEndReader.Create(Self));
Result.Add(TCompoundMiddleReader.Create(Self));
Result.Add(TCompoundWordMaxReader.Create(Self));
Result.Add(TCompoundRootReader.Create(Self));
Result.Add(TCompoundPermitFlagReader.Create(Self));
Result.Add(TCompoundForbidFlagReader.Create(Self));
Result.Add(TCheckCompoundDupReader.Create(Self));
Result.Add(TCheckCompoundRepReader.Create(Self));
Result.Add(TCheckCompoundTripleReader.Create(Self));
Result.Add(TSimplifiedTripleReader.Create(Self));
Result.Add(TCheckCompoundCaseReader.Create(Self));
Result.Add(TNoSuggestReader.Create(Self));
Result.Add(TForbiddenWordReader.Create(Self));
Result.Add(TLemmaPresentReader.Create(Self));
Result.Add(TCircumfixReader.Create(Self));
Result.Add(TOnlyInCompoundReader.Create(Self));
Result.Add(TPseudoRootReader.Create(Self));
Result.Add(TNeedAffixReader.Create(Self));
Result.Add(TCompoundMinReader.Create(Self));
Result.Add(TCompoundSyllableReader.Create(Self));
Result.Add(TSyllableNumReader.Create(Self));
Result.Add(TWordCharsReader.Create(Self));
Result.Add(TIgnoreReader.Create(Self));
Result.Add(TRepReader.Create(Self));
Result.Add(TIConvReader.Create(Self));
Result.Add(TOConvReader.Create(Self));
Result.Add(TCheckCompoundPatternReader.Create(Self));
Result.Add(TCompoundRuleReader.Create(Self));
Result.Add(TMapReader.Create(Self));
Result.Add(TBreakReader.Create(Self));
Result.Add(TLangReader.Create(Self));
Result.Add(TVersionReader.Create(Self));
Result.Add(TNoSplitSugsReader.Create(Self));
Result.Add(TFullStripReader.Create(Self));
Result.Add(TSugsWithDotsReader.Create(Self));
Result.Add(TKeepCaseReader.Create(Self));
Result.Add(TSubStandardReader.Create(Self));
Result.Add(TCheckSharpsReader.Create(Self));
Result.Add(TPrefixReader.Create(Self));
Result.Add(TSuffixReader.Create(Self));
end;
procedure TdxHunspellAffixManager.SetLanguage(Value: Integer);
begin
FLanguage := Value;
FIsHungarian := Language = LanguageHu; //TODO:
end;
{ TdxAffix }
constructor TdxAffix.Create(AAffixManager: TdxHunspellAffixManager;
AAffixItem: PdxAffixItem; AFlag: Word; AOptions: ShortInt);
begin
FAffixManager := AAffixManager;
FFlag := AFlag;
FStripString := AAffixItem.FStripString;
FAppendString := AAffixItem.FAppendString;
FStripStringLength := AAffixItem.FStripStringLength;
FAppendStringLength := AAffixItem.FAppendStringLength;
FConditionLength := AAffixItem.FConditionLength;
FOptions := AOptions;
FConditions := AllocMem(SizeOf(TdxAffixCondition));
if FOptions and aeLONGCOND <> 0 then
begin
Move(AAffixItem.ConditionFirstPart, FConditions.Condition, MaxConditionLength);
FConditions.ConditionSecondPart := AAffixItem.ConditionSecondPart;
end
else
Move(AAffixItem.Condition, FConditions.Condition, MaxConditionLength);
FMorphologicalDescription := AAffixItem.FMorphologicalDescription;
FCompatibleFlags := AAffixItem.FCompatibleFlags;
end;
destructor TdxAffix.Destroy;
begin
FFlag := 0;
StrDispose(FAppendString);
StrDispose(FStripString);
FAppendString := nil;
FStripString := nil;
if FOptions and aeLONGCOND <> 0 then
StrDispose(FConditions.ConditionSecondPart);
FreeMem(FConditions, SizeOf(TdxAffixCondition));
if (FMorphologicalDescription <> nil) and (FOptions and aoAffixMorphologyTable = 0) then
StrDispose(FMorphologicalDescription);
FreeAndNil(FCompatibleFlags);
inherited Destroy;
end;
function TdxAffix.CanUseInSimpleWordsOrIsFogemorpheme(ACompoundWordPart: TdxCompoundWordPart): Boolean;
begin
Result := (ACompoundWordPart <> cwpNone) or
not IsCompatibleWithFlag(AffixManager.OnlyInCompound);
end;
function TdxAffix.CanUseInTheMiddleOfCompoundWords(ACompoundWordPart: TdxCompoundWordPart): Boolean;
begin
Result := CanUseInCompoundWordPart(ACompoundWordPart) or
IsCompatibleWithFlag(AffixManager.FCompoundPermitFlag);
end;
function TdxAffix.GetNextConditionChar(AConditionCursor: PAnsiChar): PAnsiChar;
begin
Result := nil;
if AConditionCursor <> nil then
begin
Inc(AConditionCursor);
if FOptions and aeLONGCOND <> 0 then
begin
if AConditionCursor = FConditions.Condition + MaxConditionLength then
AConditionCursor := FConditions.ConditionSecondPart;
end
else
if AConditionCursor = FConditions.Condition + MaxConditionLength then
Exit;
if AConditionCursor^ <> #0 then
Result := AConditionCursor;
end;
end;
function TdxAffix.IsCompatibleWithFlag(AFlag: Word; CompatibleIfNull: Boolean = False): Boolean;
begin
Result := (CompatibleFlags <> nil) and
CompatibleFlags.ContainsFlag(AFlag);
if CompatibleIfNull then
Result := Result or (AFlag = NullFlag);
end;
function TdxAffix.IsPrefixSuffixUnion(AOptions: ShortInt): Boolean;
begin
Result := AOptions and aoPrefixSuffixUnion <> 0
end;
function TdxAffix.IsWithoutAffixWordLengthCorrect(ALengthWithoutAffix: Integer): Boolean;
begin
Result := ((ALengthWithoutAffix > 0) or
(ALengthWithoutAffix = 0) and AffixManager.FullStrip) and
(ALengthWithoutAffix + FStripStringLength >= FConditionLength);
end;
procedure TdxAffix.SearchConditionGroupEnd(var AConditionCursor: PAnsiChar);
var
ANextConditionChar: PAnsiChar;
begin
ANextConditionChar := GetNextConditionChar(AConditionCursor);
while (AConditionCursor <> nil) and (AConditionCursor^ <> ']') and
(ANextConditionChar <> nil) do
begin
AConditionCursor := ANextConditionChar;
ANextConditionChar := GetNextConditionChar(AConditionCursor);
end;
end;
function TdxAffix.IsCircumfix: Boolean;
begin
Result := IsCompatibleWithFlag(AffixManager.FCircumfix);
end;
function TdxAffix.GetAppendString: PAnsiChar;
begin
Result := FAppendString;
end;
function TdxAffix.GetPrefixSuffixUnion: Boolean;
begin
Result := IsPrefixSuffixUnion(FOptions);
end;
{ TdxPrefix }
function TdxPrefix.CanUseInCompoundWordPart(ACompoundWordPart: TdxCompoundWordPart): Boolean;
begin
Result := ACompoundWordPart <> cwpLast;
end;
function TdxPrefix.CheckWord(const AWord: PAnsiChar; AWordLength: Integer; var ATakenSuffix: TdxSuffix;
ACompoundWordPart: TdxCompoundWordPart; const ACompoundPartFlag: Word = NullFlag): TdxHunspellWordItem;
var
AInitialWordFormLength: Integer;
AWordBaseTableItem: TdxHunspellWordItem;
AInitialWordForm: array[0..MAXWORDUTF8LEN + 3] of AnsiChar;
begin
Result := nil;
AInitialWordFormLength := AWordLength - AppendStringLength;
if IsWithoutAffixWordLengthCorrect(AInitialWordFormLength) then
begin
if FStripStringLength <> 0 then
StrCopy(AInitialWordForm, FStripString);
StrCopy(AInitialWordForm + FStripStringLength, AWord + AppendStringLength);
if IsWordSuitableToCondition(AInitialWordForm) then
begin
Inc(AInitialWordFormLength, FStripStringLength);
AWordBaseTableItem := AffixManager.Lookup(AInitialWordForm);
if AWordBaseTableItem <> nil then
repeat
if AWordBaseTableItem.IsCompatibleWithFlag(FFlag) and
not IsCompatibleWithFlag(AffixManager.FNeedAffix) and
(AWordBaseTableItem.IsCompatibleWithFlag(ACompoundPartFlag, True) or
IsCompatibleWithFlag(ACompoundPartFlag)) then
Result := AWordBaseTableItem;
AWordBaseTableItem := AWordBaseTableItem.NextHomonym;
until (AWordBaseTableItem = nil) or (Result <> nil);
if Result = nil then
begin
if PrefixSuffixUnion then
Result := AffixManager.ProcessSuffixCheck(AInitialWordForm,
AInitialWordFormLength, aoPrefixSuffixUnion, Self, ATakenSuffix, nil,
0, nil, NullFlag, ACompoundPartFlag, ACompoundWordPart);
end;
end;
end;
end;
function TdxPrefix.MakeInitialWordFormAndProcessTwoSuffixCheck(const AWord: PAnsiChar;
AWordLength: Integer; var ATakenSuffix: TdxSuffix;
ACompoundWordPart: TdxCompoundWordPart;
const ACompoundPartFlag: Word = NullFlag): TdxHunspellWordItem;
var
AInitialWordFormLength: Integer;
AInitialWordForm: array[0..MAXWORDUTF8LEN + 3] of AnsiChar;
begin
Result := nil;
AInitialWordFormLength := AWordLength - AppendStringLength;
if IsWithoutAffixWordLengthCorrect(AInitialWordFormLength) then
begin
if FStripStringLength <> 0 then
StrCopy(AInitialWordForm, FStripString);
StrCopy(AInitialWordForm + FStripStringLength, AWord + AppendStringLength);
if IsWordSuitableToCondition(AInitialWordForm) then
begin
Inc(AInitialWordFormLength, FStripStringLength);
if PrefixSuffixUnion and (ACompoundWordPart <> cwpFirst) then
Result := AffixManager.ProcessTwoSuffixCheck(AInitialWordForm,
AInitialWordFormLength, aoPrefixSuffixUnion, Self, ATakenSuffix,
ACompoundPartFlag);
end;
end;
end;
function TdxPrefix.IsWordSuitableToCondition(AWord: PAnsiChar): Boolean;
procedure GoForward;
begin
Inc(AWord);
while (FOptions and aeUTF8 <> 0) and (Ord(AWord^) and $C0 = $80) do
Inc(AWord);
end;
var
AWordCursor: PAnsiChar;
ANegative: Boolean;
AIsGroup: Boolean;
AConditionCursor: PAnsiChar;
begin
Result := False;
AWordCursor := nil;
ANegative := False;
AIsGroup := False;
if FConditionLength = 0 then
begin
Result := True;
Exit;
end;
AConditionCursor := FConditions.Condition;
while True do
begin
case AConditionCursor^ of
#0:
begin
Result := True;
Exit;
end;
'[':
begin
ANegative := False;
AIsGroup := False;
AConditionCursor := GetNextConditionChar(AConditionCursor);
AWordCursor := AWord;
end;
'^':
begin
AConditionCursor := GetNextConditionChar(AConditionCursor);
ANegative := True;
end;
']':
begin
if ANegative and AIsGroup or not ANegative and not AIsGroup then
Exit;
AWordCursor := nil;
AConditionCursor := GetNextConditionChar(AConditionCursor);
if not AIsGroup then
GoForward;
if (AWord^ = #0) and (AConditionCursor <> nil) then
Exit;
end;
'.':
if AWordCursor = nil then
begin
AConditionCursor := GetNextConditionChar(AConditionCursor);
GoForward;
if (AWord^ = #0) and (AConditionCursor <> nil) then
Exit;
end;
else
if AWord^ = AConditionCursor^ then
begin
Inc(AWord);
AConditionCursor := GetNextConditionChar(AConditionCursor);
if (FOptions and aeUTF8 <> 0) and (Ord((AWord - 1)^) and $80 <> 0) then
begin
while (AConditionCursor <> nil) and (Ord(AConditionCursor^) and $C0 = $80) do
begin
if (AConditionCursor^ <> AWord^) then
begin
if AWordCursor = nil then
Exit;
AWord := AWordCursor;
Break;
end;
AConditionCursor := GetNextConditionChar(AConditionCursor);
Inc(AWord);
end;
if (AWordCursor <> nil) and (AWord <> AWordCursor) then
begin
AIsGroup := True;
SearchConditionGroupEnd(AConditionCursor);
end;
end
else
if AWordCursor <> nil then
begin
AIsGroup := True;
SearchConditionGroupEnd(AConditionCursor);
end;
end
else
if AWordCursor <> nil then
AConditionCursor := GetNextConditionChar(AConditionCursor)
else
Exit;
end;
if AConditionCursor = nil then
begin
Result := True;
Exit;
end;
end;
end;
{ TdxSuffix }
constructor TdxSuffix.Create(AAffixManager: TdxHunspellAffixManager;
AAffixItem: PdxAffixItem; AFlag: Word; AOptions: ShortInt);
begin
inherited Create(AAffixManager, AAffixItem, AFlag, AOptions);
FReverseAppendString := StrCopyReverse(FAppendString);
end;
destructor TdxSuffix.Destroy;
begin
StrDispose(FReverseAppendString);
inherited Destroy;
end;
function TdxSuffix.CanUseInCompoundWordPart(ACompoundWordPart: TdxCompoundWordPart): Boolean;
begin
Result := ACompoundWordPart <> cwpFirst;
end;
function TdxSuffix.GetWordWithAffix(const AWord: PAnsiChar; AWordLength: Integer): PAnsiChar;
var
ATempWord: array[0..MAXWORDUTF8LEN + 3] of AnsiChar;
begin
Result := nil;
if ((AWordLength > FStripStringLength) or (AWordLength = 0) and (AffixManager.FullStrip)) and
(AWordLength >= FConditionLength) and IsWordSuitableToCondition(AWord + AWordLength, AWord) and
((FStripStringLength = 0) or (StrComp(AWord + AWordLength - FStripStringLength, FStripString) = 0)) and
(MAXWORDUTF8LEN + 4 > AWordLength + AppendStringLength - FStripStringLength) then
begin
StrCopy(ATempWord, AWord);
if AppendStringLength <> 0 then
StrCopy(ATempWord + AWordLength - FStripStringLength, FAppendString)
else
(ATempWord + AWordLength - FStripStringLength)^ := #0;
Result := StrNew(ATempWord);
end;
end;
function TdxSuffix.CheckWord(const AWord: PAnsiChar; AWordLength, AOptions: Integer;
APrefix: TdxPrefix; wlst: PPAnsiChar; maxSug: Integer; ns: PInteger;
const ACompatibleFlag: Word = NullFlag; const ACompoundPartFlag: Word = NullFlag;
const AIncompatibleFlag: Word = NullFlag): TdxHunspellWordItem;
function IsIncompatibleWithFlag(AWordBaseTableItem: TdxHunspellWordItem; AFlag: Word): Boolean;
begin
Result := (AFlag = 0) or not AWordBaseTableItem.IsCompatibleWithFlag(AFlag);
end;
var
AInitialWordFormLength: Integer;
AWordBaseTableItem: TdxHunspellWordItem;
AInitialWordFormEndPointer: PAnsiChar;
AInitialWordForm: array[0..MAXWORDUTF8LEN + 3] of AnsiChar;
cwrd: Boolean;
K: Integer;
AElement: PPAnsiChar;
begin
Result := nil;
if IsPrefixSuffixUnion(AOptions) and not PrefixSuffixUnion then
Exit;
AInitialWordFormLength := AWordLength - AppendStringLength;
if IsWithoutAffixWordLengthCorrect(AInitialWordFormLength) then
begin
StrCopy(AInitialWordForm, AWord);
AInitialWordFormEndPointer := AInitialWordForm + AInitialWordFormLength;
if FStripStringLength <> 0 then
begin
StrCopy(AInitialWordFormEndPointer, FStripString);
Inc(AInitialWordFormLength, FStripStringLength);
AInitialWordFormEndPointer := AInitialWordForm + AInitialWordFormLength;
end
else
AInitialWordFormEndPointer^ := #0;
if IsWordSuitableToCondition(AInitialWordFormEndPointer, AInitialWordForm) then
begin
AWordBaseTableItem := AffixManager.Lookup(AInitialWordForm);
if AWordBaseTableItem <> nil then
begin
repeat
if (AWordBaseTableItem.IsCompatibleWithFlag(FFlag) or
(APrefix <> nil) and APrefix.IsCompatibleWithFlag(FFlag)) and
(not IsPrefixSuffixUnion(AOptions) or
AWordBaseTableItem.IsCompatibleWithFlag(APrefix.Flag) or
IsCompatibleWithFlag(APrefix.Flag)) and
IsCompatibleWithFlag(ACompatibleFlag, True) and
IsIncompatibleWithFlag(AWordBaseTableItem, AIncompatibleFlag) and
((ACompoundPartFlag = 0) or
(AWordBaseTableItem.IsCompatibleWithFlag(ACompoundPartFlag, True) or
IsCompatibleWithFlag(ACompoundPartFlag))) then
Result := AWordBaseTableItem;
AWordBaseTableItem := AWordBaseTableItem.NextHomonym;
until (AWordBaseTableItem = nil) or (Result <> nil);
end
else
if (wlst <> nil) and (ns^ < maxSug) then
begin
cwrd := True;
for K := 0 to ns^ - 1 do
if StrComp(AInitialWordForm, GetElementPointer(wlst, K)^) = 0 then
cwrd := False;
if cwrd then
begin
AElement := GetElementPointer(wlst, ns^);
AElement^ := StrNew(AInitialWordForm);
if AElement^ = nil then
begin
for K := 0 to ns^ - 1 do
StrDispose(GetElementPointer(wlst, K)^);
ns^ := -1;
Exit;
end;
Inc(ns^);
end;
end;
end;
end;
end;
function TdxSuffix.MakeInitialWordFormAndProcessSuffixCheck(const AWord: PAnsiChar; AWordLength, AOptions: Integer;
APrefix: TdxPrefix; var ATakenSuffix: TdxSuffix; const ACompoundPartFlag: Word = 0): TdxHunspellWordItem;
var
AInitialWordFormLength: Integer;
AInitialWordFormEndPointer: PAnsiChar;
AInitialWordForm: array[0..MAXWORDUTF8LEN + 3] of AnsiChar;
begin
Result := nil;
if IsPrefixSuffixUnion(AOptions) and not PrefixSuffixUnion then
Exit;
AInitialWordFormLength := AWordLength - AppendStringLength;
if IsWithoutAffixWordLengthCorrect(AInitialWordFormLength) then
begin
StrCopy(AInitialWordForm, AWord);
AInitialWordFormEndPointer := AInitialWordForm + AInitialWordFormLength;
if FStripStringLength <> 0 then
begin
StrCopy(AInitialWordFormEndPointer, FStripString);
Inc(AInitialWordFormLength, FStripStringLength);
AInitialWordFormEndPointer := AInitialWordForm + AInitialWordFormLength;
end
else
AInitialWordFormEndPointer^ := #0;
if IsWordSuitableToCondition(AInitialWordFormEndPointer, AInitialWordForm) then
begin
if APrefix <> nil then
begin
if IsCompatibleWithFlag(APrefix.Flag) then
Result := AffixManager.ProcessSuffixCheck(AInitialWordForm,
AInitialWordFormLength, 0, nil, ATakenSuffix, nil, 0, nil, FFlag,
ACompoundPartFlag)
else
Result := AffixManager.ProcessSuffixCheck(AInitialWordForm,
AInitialWordFormLength, AOptions, APrefix, ATakenSuffix, nil, 0, nil,
FFlag, ACompoundPartFlag);
end
else
Result := AffixManager.ProcessSuffixCheck(AInitialWordForm,
AInitialWordFormLength, 0, nil, ATakenSuffix, nil, 0, nil, FFlag,
ACompoundPartFlag);
end;
end;
end;
function TdxSuffix.GetAppendString: PAnsiChar;
begin
Result := FReverseAppendString;
end;
function TdxSuffix.getLM: TdxSuffix;
begin
Result := l_morph;
end;
function TdxSuffix.getRM: TdxSuffix;
begin
Result := r_morph;
end;
function TdxSuffix.getEQM: TdxSuffix;
begin
Result := eq_morph;
end;
function TdxSuffix.IsWordSuitableToCondition(AWordEnd, AWordBegin: PAnsiChar): Boolean;
procedure GoForward;
begin
while (FOptions and aeUTF8 <> 0) and (AWordEnd >= AWordBegin) and (Ord(AWordEnd^) and $C0 = $80) do
Dec(AWordEnd);
end;
var
AWordCursor: PAnsiChar;
ANegative: Boolean;
AIsGroup: Boolean;
AConditionCursor: PAnsiChar;
I: Integer;
begin
Result := False;
AWordCursor := nil;
ANegative := False;
AIsGroup := False;
if FConditionLength = 0 then
begin
Result := True;
Exit;
end;
AConditionCursor := FConditions.Condition;
Dec(AWordEnd);
I := 1;
while True do
begin
case AConditionCursor^ of
#0:
begin
Result := True;
Exit;
end;
'[':
begin
AConditionCursor := GetNextConditionChar(AConditionCursor);
AWordCursor := AWordEnd;
end;
'^':
begin
AConditionCursor := GetNextConditionChar(AConditionCursor);
ANegative := True;
end;
']':
begin
if not ANegative and not AIsGroup then
Exit;
Inc(I);
if not AIsGroup then
begin
GoForward;
Dec(AWordEnd);
end;
AWordCursor := nil;
ANegative := False;
AIsGroup := False;
AConditionCursor := GetNextConditionChar(AConditionCursor);
if (AWordEnd < AWordBegin) and (AConditionCursor <> nil) then
Exit;
end;
'.':
if AWordCursor = nil then
begin
AConditionCursor := GetNextConditionChar(AConditionCursor);
Dec(AWordEnd);
GoForward;
if AWordEnd < AWordBegin then
begin
if AConditionCursor = nil then
Result := True;
Exit;
end;
if (FOptions and aeUTF8 <> 0) and (Ord(AWordEnd^) and $80 <> 0) then
begin
Dec(AWordEnd);
if AWordEnd < AWordBegin then
begin
if AConditionCursor = nil then
Result := True;
Exit;
end;
end;
end;
else
if AWordEnd^ = AConditionCursor^ then
begin
AConditionCursor := GetNextConditionChar(AConditionCursor);
if (FOptions and aeUTF8 <> 0) and (Ord(AWordEnd^) and $80 <> 0) then
begin
Dec(AWordEnd);
while (AConditionCursor <> nil) and (AWordEnd >= AWordBegin) do
begin
if AConditionCursor^ <> AWordEnd^ then
begin
if AWordCursor = nil then
Exit;
AWordEnd := AWordCursor;
Break;
end;
if Ord(AConditionCursor^) and $C0 <> $80 then
Break;
AConditionCursor := GetNextConditionChar(AConditionCursor);
Dec(AWordEnd);
end;
if (AWordCursor <> nil) and (AWordEnd <> AWordCursor) then
begin
if ANegative then
Exit
else
if I = FConditionLength then
begin
Result := True;
Exit;
end;
AIsGroup := True;
SearchConditionGroupEnd(AConditionCursor);
Dec(AWordEnd);
end;
if (AConditionCursor <> nil) and (AConditionCursor^ <> ']') then
AConditionCursor := GetNextConditionChar(AConditionCursor);
end
else
if AWordCursor <> nil then
begin
if ANegative then
Exit
else
if I = FConditionLength then
begin
Result := True;
Exit;
end;
AIsGroup := True;
SearchConditionGroupEnd(AConditionCursor);
Dec(AWordEnd);
end;
if AWordCursor = nil then
begin
Inc(I);
Dec(AWordEnd);
end;
if (AWordEnd < AWordBegin) and (AConditionCursor <> nil) and
(AConditionCursor^ <> ']') then
Exit;
end
else
if AWordCursor <> nil then
AConditionCursor := GetNextConditionChar(AConditionCursor)
else
Exit;
end;
if AConditionCursor = nil then
begin
Result := True;
Exit;
end;
end;
end;
{ TdxAffixDataTable }
constructor TdxSpellCheckerDataTable.Create;
begin
// do nothing
end;
constructor TdxSpellCheckerDataTable.Create(ADataIdentifier: PAnsiChar);
begin
inherited Create;
FDataIdentifier := ADataIdentifier;
end;
destructor TdxSpellCheckerDataTable.Destroy;
begin
FreeData;
inherited Destroy;
end;
function TdxSpellCheckerDataTable.AllocateData(ASize: Integer): Boolean;
begin
Result := True;
FreeData;
FSize := ASize;
try
FData := AllocMem(GetDataItemSize * ASize);
except
on EOutOfMemory do
begin
FSize := 0;
Result := False;
end;
end;
end;
function TdxSpellCheckerDataTable.ReadData(ALine: PAnsiChar; AAffixFileManager: TdxHunspellReader): Boolean;
begin
Result := ReadDataHeader(ALine);
if Result then
Result := ParseData(AAffixFileManager);
if not Result then
FreeData;
end;
function TdxSpellCheckerDataTable.AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean;
begin
Result := True;
if APieceIndex = 0 then
begin
Result := CheckDataType(APiece);
if Result then
begin
FCurrentDataIndex := ADataIndex;
InitializeItem(ADataIndex);
end;
end
else
if FCurrentDataIndex <> ADataIndex then
Result := False;
end;
function TdxSpellCheckerDataTable.IsAllPiecesFound(APieceIndex: Integer): Boolean;
begin
Result := APieceIndex >= GetPieceQuantity;
end;
function TdxSpellCheckerDataTable.CheckDataType(const APiece: PAnsiChar): Boolean;
var
ADataIdentifier: PAnsiChar;
begin
ADataIdentifier := FDataIdentifier;
if ADataIdentifier = nil then
ADataIdentifier := GetDataIdentifier;
Result := StrLComp(APiece, ADataIdentifier, StrLen(ADataIdentifier)) = 0;
end;
procedure TdxSpellCheckerDataTable.InitializeItem(Index: Integer);
begin
// do nothing
end;
function TdxSpellCheckerDataTable.ReadDataHeader(ALine: PAnsiChar): Boolean;
var
ATableSize: Integer;
begin
Result := ParseHeader(ALine, ATableSize);
if Result then
AllocateData(ATableSize);
end;
function TdxSpellCheckerDataTable.ParseHeader(ALine: PAnsiChar; out ATableSize: Integer): Boolean;
var
APiece: PAnsiChar;
begin
ATableSize := 0;
APiece := nil;
Result := GetSecondPartOfString(ALine, APiece);
if Result then
begin
ATableSize := StrInt(APiece);
StrDispose(APiece);
end;
end;
function TdxSpellCheckerDataTable.ParseData(AAffixFileManager: TdxHunspellReader): Boolean;
var
ADataIndex, APieceIndex: Integer;
ALineStart, ALineCursor, APiece: PAnsiChar;
begin
Result := True;
for ADataIndex := 0 to Count - 1 do
begin
ALineStart := AAffixFileManager.getline;
try
RemoveCRLF(ALineStart);
ALineCursor := ALineStart;
APieceIndex := 0;
repeat
APiece := StrSeparate(@ALineCursor, #0);
if (APiece <> nil) and (APiece^ <> #0) then
begin
Result := AddDataPiece(APiece, ADataIndex, APieceIndex);
Inc(APieceIndex);
end;
until (APiece = nil) or not Result;
if not IsAllPiecesFound(APieceIndex) then
begin
Result := False;
Break;
end;
finally
StrDispose(ALineStart);
end;
end;
end;
procedure TdxSpellCheckerDataTable.FreeData;
begin
if FData <> nil then
begin
FreeDataItems;
FreeMem(FData, GetDataItemSize * FSize);
FData := nil;
end;
FSize := 0;
end;
{ TdxAffixDataLinkedTable }
constructor TdxSpellCheckerDataLinkedTable.Create(AWordBaseManager: TdxHunspellWordBaseManager;
AAffixManager: TdxHunspellAffixManager);
begin
inherited Create;
FWordBaseManager := AWordBaseManager;
FAffixManager := AAffixManager;
end;
{ TdxAffixItemTable }
constructor TdxAffixItemTable.Create(AWordBaseManager: TdxHunspellWordBaseManager;
AAffixManager: TdxHunspellAffixManager; AExistentAffixFlags: TdxExistentAffixFlags);
begin
inherited Create(AWordBaseManager, AAffixManager);
FExistentAffixFlags := AExistentAffixFlags;
end;
destructor TdxAffixItemTable.Destroy;
begin
StrDispose(FFlag);
inherited Destroy;
end;
function TdxAffixItemTable.AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean;
begin
Result := inherited AddDataPiece(APiece, ADataIndex, APieceIndex);
if Result then
case APieceIndex of
1: Result := CheckFlag(APiece);
2: ParseStripString(APiece, ADataIndex);
3: Result := ParseAppendStringWithAffixes(APiece, ADataIndex);
4: Result := ParseCondition(APiece, ADataIndex);
5: Result := ParseMorphologicDescription(APiece, ADataIndex);
6: AddLineRemainderToMorphologicDescription(APiece, ADataIndex);
end;
end;
function TdxAffixItemTable.IsAllPiecesFound(APieceIndex: Integer): Boolean;
begin
Result := True;
end;
function TdxAffixItemTable.IsComplexPrefixes: Boolean;
begin
Result := FAffixManager.ComplexPrefixes;
end;
procedure TdxAffixItemTable.BuildAffixes;
begin
FAffixesIsCreated := True;
end;
function TdxAffixItemTable.GetDataItemSize: Integer;
begin
Result := SizeOf(TdxAffixItem);
end;
function TdxAffixItemTable.GetDataIdentifier: PAnsiChar;
begin
if IsPrefix then
Result := 'PFX'
else
Result := 'SFX';
end;
function TdxAffixItemTable.GetPieceQuantity: Integer;
begin
Result := 7;
end;
procedure TdxAffixItemTable.FreeDataItems;
var
I: Integer;
begin
if not FAffixesIsCreated then
for I := 0 to Count - 1 do
begin
StrDispose(Data[I].FStripString);
StrDispose(Data[I].FAppendString);
if not HasAffixMorphologicAliases then
StrDispose(Data[I].FMorphologicalDescription);
if Data[I].LongCondition then
StrDispose(Data[I].ConditionSecondPart);
FreeAndNil(Data[I].FCompatibleFlags);
end;
end;
function TdxAffixItemTable.ParseHeader(ALine: PAnsiChar; out ATableSize: Integer): Boolean;
var
I: Integer;
APiece: PAnsiChar;
begin
Result := True;
APiece := StrSeparate(@ALine, #0);
I := 0;
while (APiece <> nil) and Result and (I < 4) do
begin
if APiece^ <> #0 then
begin
case I of
1: Result := ParseFlag(APiece);
2: ParsePrefixSuffixUnion(APiece);
3: Result := ParseTableSize(APiece, ATableSize);
end;
Inc(I);
end;
APiece := StrSeparate(@ALine, #0);
end;
end;
function TdxAffixItemTable.GetData: PdxAffixItemArray;
begin
Result := PdxAffixItemArray(FData);
end;
function TdxAffixItemTable.GetItem(Index: Integer): TdxAffixItem;
begin
Result := Data[Index];
end;
procedure TdxAffixItemTable.AddLineRemainderToMorphologicDescription(
ALine: PAnsiChar; ADataIndex: Integer);
var
ANewDescription: PAnsiChar;
ALength: Integer;
begin
if not HasAffixMorphologicAliases then
begin
ALength := StrLen(Data[ADataIndex].FMorphologicalDescription) + StrLen(ALine) + 2;
{$IFDEF DELPHI12}
ANewDescription := AnsiStrAlloc(ALength);
{$ELSE}
ANewDescription := StrAlloc(ALength);
{$ENDIF}
StrCopy(ANewDescription, Data[ADataIndex].FMorphologicalDescription);
ALength := StrLen(ANewDescription);
StrCopy(ANewDescription + ALength, ' ');
StrCopy(ANewDescription + ALength + 1, ALine);
StrDispose(Data[ADataIndex].FMorphologicalDescription);
Data[ADataIndex].FMorphologicalDescription := ANewDescription;
end;
end;
function TdxAffixItemTable.CheckFlag(ALine: PAnsiChar): Boolean;
begin
Result := (WordBaseManager.DecodeFlag(ALine) = FDecodedFlag) or FlagIsNil;
end;
procedure TdxSuffixItemTable.BuildAffixes;
var
I: Integer;
begin
inherited BuildAffixes;
for I := 0 to Count - 1 do
AffixManager.BuildAffixTree(TdxSuffix.Create(AffixManager, @Data[I],
FDecodedFlag, GetOptions(Data[I])),
AffixManager.FSuffixTableArrangedByAppendString, AffixManager.FSuffixTableIndexedByFlag);
end;
function TdxSuffixItemTable.ConditionContainsDuplicateInformation(
strip: PAnsiChar; stripl: Integer; const ACondition: PAnsiChar; out Contains: Boolean): Boolean;
var
AConditionLength, I, J: Integer;
ANegative, AIsCharactersAgreed: Boolean;
begin
Result := True;
Contains := False;
AConditionLength := StrLen(ACondition);
if (stripl >= AConditionLength) and (StrComp(strip + stripl - AConditionLength, ACondition) = 0) then
Contains := True;
if not Contains then
begin
I := stripl - 1;
J := AConditionLength - 1;
while (I >= 0) and (J >= 0) and Result do
begin
if (ACondition + J)^ <> ']' then
begin
Result := (ACondition + J)^ = (strip + I)^;
end
else
begin
AIsCharactersAgreed := False;
repeat
Dec(J);
if (strip + I)^ = (ACondition + J)^ then
AIsCharactersAgreed := True;
until not((J > 0) and ((ACondition + J)^ <> '['));
Result := not((J = 0) and ((ACondition + J)^ <> '['));
if Result then
begin
ANegative := (ACondition + J + 1)^ = '^';
Result := ANegative xor AIsCharactersAgreed;
end;
end;
Dec(I);
Dec(J);
end;
if Result and (J < 0) then
Contains := True;
end;
end;
function TdxAffixItemTable.ConditionLength(ALine: PAnsiChar): Integer;
var
AInGroup: Boolean;
begin
Result := 0;
AInGroup := False;
while ALine^ <> #0 do
begin
if ALine^ = '[' then
begin
AInGroup := True;
Inc(Result);
end
else
if ALine^ = ']' then
AInGroup := False
else
if not AInGroup then
Inc(Result);
Inc(ALine);
end;
end;
function TdxAffixItemTable.EncodeAffixCondition(ALine: PAnsiChar; ADataIndex: Integer): Boolean;
begin
Result := True;
if StrComp(ALine, '.') <> 0 then
begin
Data[ADataIndex].FConditionLength := ConditionLength(ALine);
StrLCopy(Data[ADataIndex].Condition, ALine, MaxConditionLength);
if (Data[ADataIndex].Condition[MaxConditionLength - 1] <> #0) and
((ALine + MaxConditionLength)^ <> #0) then
begin
Data[ADataIndex].LongCondition := True;
Data[ADataIndex].ConditionSecondPart := StrNew(ALine + MaxConditionLength);
Result := Data[ADataIndex].ConditionSecondPart <> nil;
end;
end
else
begin
Data[ADataIndex].FConditionLength := 0;
Data[ADataIndex].Condition[0] := #0;
end;
end;
function TdxAffixItemTable.HasAffixFlagAliases: Boolean;
begin
Result := WordBaseManager.HasAffixFlagAliases;
end;
function TdxAffixItemTable.HasAffixMorphologicAliases: Boolean;
begin
Result := WordBaseManager.HasAffixMorphologicAliases;
end;
function TdxAffixItemTable.FlagIsNil: Boolean;
var
AEncodedFlag: PAnsiChar;
begin
AEncodedFlag := WordBaseManager.EncodeFlag(FDecodedFlag);
try
Result := AEncodedFlag = nil;
finally
StrDispose(AEncodedFlag);
end;
end;
function TdxAffixItemTable.FlagIsUnique(AFlag: Word): Boolean;
begin
Result := IsPrefix and (FExistentAffixFlags[FDecodedFlag] and ExistentPrefixFlag = 0) or
(FExistentAffixFlags[FDecodedFlag] and ExistentSuffixFlag = 0);
end;
procedure TdxAffixItemTable.FreeIfZero(var AString: TdxStringData);
begin
if StrComp(AString.Data, '0') = 0 then
begin
StrDispose(AString.Data);
AString.Data := StrNew(PAnsiChar(''));
AString.Length := 0;
end;
end;
function TdxAffixItemTable.GetOptions(AItem: TdxAffixItem): ShortInt;
begin
Result := 0;
if FPrefixSuffixUnion then
Result := Result + aoPrefixSuffixUnion;
if HasAffixFlagAliases then
Result := Result + aoAffixFlagAliasTable;
if WordBaseManager.HasAffixMorphologicAliases then
Result := Result + aoAffixMorphologyTable;
if AItem.LongCondition then
Result := Result + aeLONGCOND;
end;
function TdxAffixItemTable.IsReverseWritingDirection: Boolean;
begin
Result := AffixManager.ComplexPrefixes;
end;
procedure TdxAffixItemTable.ParseAppendString(const ALine: PAnsiChar; ADataIndex: Integer);
begin
ProcessIgnoreChars(ALine);
ProcessReverseString(ALine);
Data[ADataIndex].FAppendString := StrNew(ALine);
end;
function TdxAffixItemTable.ParseAppendStringWithAffixes(const ALine: PAnsiChar; ADataIndex: Integer): Boolean;
var
ACompatibleFlagCursor: PAnsiChar;
ATempStringData: TdxStringData;
begin
Result := True;
ACompatibleFlagCursor := StrScan(ALine, '/');
if ACompatibleFlagCursor <> nil then
begin
ACompatibleFlagCursor^ := #0;
ParseAppendString(ALine, ADataIndex);
Result := ParseCompatibleFlags(ACompatibleFlagCursor + 1, ADataIndex);
ACompatibleFlagCursor^ := '/';
if Result then
RegisterCompatibleFlags(ADataIndex);
end
else
ParseAppendString(ALine, ADataIndex);
Data[ADataIndex].FAppendStringLength := StrLen(Data[ADataIndex].FAppendString);
if Result then
begin
ATempStringData.Data := Data[ADataIndex].FAppendString;
ATempStringData.Length := Data[ADataIndex].FAppendStringLength;
FreeIfZero(ATempStringData);
Data[ADataIndex].FAppendString := ATempStringData.Data;
Data[ADataIndex].FAppendStringLength := ATempStringData.Length;
end;
end;
function TdxAffixItemTable.ParseCompatibleFlags(const ALine: PAnsiChar; ADataIndex: Integer): Boolean;
begin
Result := True;
Data[ADataIndex].FCompatibleFlags := TdxHunspellFlags.Create(FWordBaseManager);
if HasAffixFlagAliases then
Result := Data[ADataIndex].FCompatibleFlags.InitializeByAlias(ALine)
else
begin
Data[ADataIndex].FCompatibleFlags.Decode(ALine);
Data[ADataIndex].FCompatibleFlags.Sort;
end;
end;
function TdxAffixItemTable.ParseCondition(ALine: PAnsiChar; ADataIndex: Integer): Boolean;
var
Contains: Boolean;
begin
Result := True;
ProcessReverseString(ALine);
if IsReverseWritingDirection then
ReverseCondition(ALine);
if (Data[ADataIndex].FStripStringLength <> 0) and (StrComp(ALine, '.') <> 0) then
begin
Result := ConditionContainsDuplicateInformation(Data[ADataIndex].FStripString,
Data[ADataIndex].FStripStringLength, ALine, Contains);
if Result and Contains then
StrPCopy(ALine, '.');
end;
if Result then
begin
if not IsPrefix then
begin
StrReverse(ALine);
ReverseCondition(ALine);
end;
Result := EncodeAffixCondition(ALine, ADataIndex);
end;
end;
function TdxAffixItemTable.ParseFlag(ALine: PAnsiChar): Boolean;
begin
FDecodedFlag := WordBaseManager.DecodeFlag(ALine);
Result := FlagIsUnique(FDecodedFlag);
if Result then
begin
SetExisting;
FFlag := StrNew(ALine);
end;
end;
function TdxAffixItemTable.ParseMorphologicDescription(ALine: PAnsiChar; ADataIndex: Integer): Boolean;
begin
Result := True;
if HasAffixMorphologicAliases then
Data[ADataIndex].FMorphologicalDescription := WordBaseManager.GetAffixMorphologyByAlias(StrInt(ALine))
else
begin
ProcessReverseString(ALine);
Data[ADataIndex].FMorphologicalDescription := StrNew(ALine);
Result := Data[ADataIndex].FMorphologicalDescription <> nil;
end;
end;
procedure TdxAffixItemTable.ParsePrefixSuffixUnion(ALine: PAnsiChar);
begin
FPrefixSuffixUnion := ALine^ = 'Y';
end;
procedure TdxAffixItemTable.ParseStripString(const ALine: PAnsiChar; ADataIndex: Integer);
var
ATempStringData: TdxStringData;
begin
ProcessReverseString(ALine);
ATempStringData.Data := StrNew(ALine);
ATempStringData.Length := StrLen(ATempStringData.Data);
FreeIfZero(ATempStringData);
Data[ADataIndex].FStripString := ATempStringData.Data;
Data[ADataIndex].FStripStringLength := ATempStringData.Length;
end;
function TdxAffixItemTable.ParseTableSize(ALine: PAnsiChar; out ATableSize: Integer): Boolean;
begin
ATableSize := StrInt(ALine);
Result := (ATableSize <> 0) or FlagIsNil;
end;
procedure TdxAffixItemTable.ProcessIgnoreChars(ALine: PAnsiChar);
begin
if AffixManager.Ignore <> nil then
RemoveIgnoredChars(ALine, AffixManager.Ignore);
end;
procedure TdxAffixItemTable.ProcessReverseString(ALine: PAnsiChar);
begin
if IsReverseWritingDirection then
StrReverse(ALine);
end;
procedure TdxAffixItemTable.RegisterCompatibleFlags(ADataIndex: Integer);
var
I: Integer;
begin
AffixManager.CompatibleFlagsExist := True;
for I := 0 to Data[ADataIndex].FCompatibleFlags.Length - 1 do
AffixManager.SetCompatibleFlags(Data[ADataIndex].FCompatibleFlags[I], True);
end;
procedure TdxAffixItemTable.ReverseCondition(ACondition: PAnsiChar);
var
ANegative: Boolean;
AConditionCursor: PAnsiChar;
begin
ANegative := False;
AConditionCursor := ACondition + StrLen(ACondition) - 1;
while AConditionCursor >= ACondition do
begin
case AConditionCursor^ of
'[': begin
if ANegative then
(AConditionCursor + 1)^ := '['
else
AConditionCursor^ := ']';
end;
']': begin
AConditionCursor^ := '[';
if ANegative then
(AConditionCursor + 1)^ := '^';
ANegative := False;
end;
'^': begin
if (AConditionCursor + 1)^ = ']' then
ANegative := True
else
(AConditionCursor + 1)^ := AConditionCursor^;
end;
else
if ANegative then
(AConditionCursor + 1)^ := AConditionCursor^;
end;
Dec(AConditionCursor);
end;
end;
procedure TdxAffixItemTable.SetExisting;
begin
if IsPrefix then
FExistentAffixFlags[FDecodedFlag] := FExistentAffixFlags[FDecodedFlag] or ExistentPrefixFlag
else
FExistentAffixFlags[FDecodedFlag] := FExistentAffixFlags[FDecodedFlag] or ExistentSuffixFlag;
end;
{ TdxPrefixItemTable }
procedure TdxPrefixItemTable.BuildAffixes;
var
I: Integer;
begin
inherited BuildAffixes;
for I := 0 to Count - 1 do
AffixManager.BuildAffixTree(TdxPrefix.Create(AffixManager, @Data[I],
FDecodedFlag, GetOptions(Data[I])),
AffixManager.FPrefixTableArrangedByAppendString, AffixManager.FPrefixTableIndexedByFlag);
end;
function TdxPrefixItemTable.ConditionContainsDuplicateInformation(
strip: PAnsiChar; stripl: Integer; const ACondition: PAnsiChar; out Contains: Boolean): Boolean;
var
AConditionLength, I, J: Integer;
ANegative, AIsCharactersAgreed: Boolean;
begin
Result := True;
Contains := False;
AConditionLength := StrLen(ACondition);
if StrComp(strip, ACondition) = 0 then
Contains := True;
if not Contains then
begin
I := 0;
J := 0;
while (I < stripl) and (J < AConditionLength) and Result do
begin
if (ACondition + J)^ <> '[' then
begin
Result := (ACondition + J)^ = (strip + I)^;
end
else
begin
ANegative := (ACondition + J + 1)^ = '^';
AIsCharactersAgreed := False;
repeat
Inc(J);
if (strip + I)^ = (ACondition + J)^ then
AIsCharactersAgreed := True;
until not((J < AConditionLength - 1) and ((ACondition + J)^ <> ']'));
Result := not((J = AConditionLength - 1) and ((ACondition + J)^ <> ']'));
if Result then
Result := ANegative xor AIsCharactersAgreed;
end;
Inc(I);
Inc(J);
end;
if Result and (J >= AConditionLength) then
Contains := True;
end;
end;
function TdxPrefixItemTable.IsPrefix: Boolean;
begin
Result := not IsComplexPrefixes;
end;
{ TdxSuffixItemTable }
function TdxSuffixItemTable.IsPrefix: Boolean;
begin
Result := IsComplexPrefixes;
end;
{ TdxBreakTable }
constructor TdxBreakTable.Create;
begin
inherited Create;
FillDefaultData;
end;
procedure TdxBreakTable.FillDefaultData;
var
I: Integer;
begin
I := 3;
AllocateData(I);
Data[I - 3] := StrNew('-');
Data[I - 2] := StrNew('^-');
Data[I - 1] := StrNew('-$');
end;
function TdxBreakTable.AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean;
begin
Result := inherited AddDataPiece(APiece, ADataIndex, APieceIndex);
if Result and (APieceIndex = 1) then
Data[ADataIndex] := StrNew(APiece);
end;
procedure TdxBreakTable.FreeDataItems;
var
I: Integer;
begin
for I := 0 to Count - 1 do
begin
StrDispose(Data[I]);
Data[I] := nil;
end;
end;
function TdxBreakTable.GetDataIdentifier: PAnsiChar;
begin
Result := 'BREAK';
end;
function TdxBreakTable.GetDataItemSize: Integer;
begin
Result := SizeOf(PAnsiChar);
end;
function TdxBreakTable.GetPieceQuantity: Integer;
begin
Result := 2;
end;
function TdxBreakTable.GetData: PdxPAnsiCharArray;
begin
Result := PdxPAnsiCharArray(FData);
end;
function TdxBreakTable.GetItem(Index: Integer): PAnsiChar;
begin
Result := Data[Index];
end;
{ TdxCheckCompoundPatternTable }
function TdxCheckCompoundPatternTable.AddDataPiece(const APiece: PAnsiChar;
ADataIndex, APieceIndex: Integer): Boolean;
begin
Result := inherited AddDataPiece(APiece, ADataIndex, APieceIndex);
if Result then
case APieceIndex of
1: begin
Data[ADataIndex].Pattern := StrNew(APiece);
ExtractCondition(Data[ADataIndex].Pattern, Data[ADataIndex].Condition);
end;
2: begin
Data[ADataIndex].Pattern2 := StrNew(APiece);
ExtractCondition(Data[ADataIndex].Pattern2, Data[ADataIndex].Condition2);
end;
3: begin
Data[ADataIndex].Pattern3 := StrNew(APiece);
FIsSimplified := True;
end;
end;
end;
procedure TdxCheckCompoundPatternTable.FreeDataItems;
var
I: Integer;
begin
for I := 0 to Count - 1 do
begin
StrDispose(Data[I].Pattern);
StrDispose(Data[I].Pattern2);
StrDispose(Data[I].Pattern3);
end;
end;
function TdxCheckCompoundPatternTable.GetDataIdentifier: PAnsiChar;
begin
Result := diCheckCompoundPattern;
end;
function TdxCheckCompoundPatternTable.GetDataItemSize: Integer;
begin
Result := SizeOf(TdxCompoundForbidPattern);
end;
function TdxCheckCompoundPatternTable.GetPieceQuantity: Integer;
begin
Result := 3;
end;
procedure TdxCheckCompoundPatternTable.InitializeItem(Index: Integer);
begin
Data[Index].Pattern := nil;
Data[Index].Pattern2 := nil;
Data[Index].Pattern3 := nil;
Data[Index].Condition := NullFlag;
Data[Index].Condition2 := NullFlag;
end;
procedure TdxCheckCompoundPatternTable.ExtractCondition(APattern: PAnsiChar;
var ACondition: Word);
var
ADelimiter: PAnsiChar;
begin
ADelimiter := StrScan(APattern, '/');
if ADelimiter <> nil then
begin
ADelimiter^ := #0;
ACondition := WordBaseManager.DecodeFlag(ADelimiter + 1);
end;
end;
function TdxCheckCompoundPatternTable.GetData: PdxCompoundForbidPatternArray;
begin
Result := PdxCompoundForbidPatternArray(FData);
end;
function TdxCheckCompoundPatternTable.GetItem(Index: Integer): TdxCompoundForbidPattern;
begin
Result := Data[Index];
end;
{ TdxCompoundRuleTable }
function TdxCompoundRuleTable.AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean;
begin
Result := inherited AddDataPiece(APiece, ADataIndex, APieceIndex);
if Result and (APieceIndex = 1) then
Result := ParseFlags(APiece, ADataIndex);
end;
procedure TdxCompoundRuleTable.FreeDataItems;
var
I: Integer;
begin
for I := 0 to Count - 1 do
FreeMem(Data[I].Pattern, Data[I].Count * SizeOf(Word));
end;
function TdxCompoundRuleTable.GetDataIdentifier: PAnsiChar;
begin
Result := diCompoundRule;
end;
function TdxCompoundRuleTable.GetDataItemSize: Integer;
begin
Result := SizeOf(TdxCompoundFlag);
end;
function TdxCompoundRuleTable.GetPieceQuantity: Integer;
begin
Result := 2;
end;
procedure TdxCompoundRuleTable.InitializeItem(Index: Integer);
begin
Data[Index].Pattern := nil;
end;
function TdxCompoundRuleTable.GetData: PdxCompoundFlagArray;
begin
Result := PdxCompoundFlagArray(FData);
end;
function TdxCompoundRuleTable.GetItem(Index: Integer): TdxCompoundFlag;
begin
Result := Data[Index];
end;
function TdxCompoundRuleTable.ParseFlags(APiece: PAnsiChar; AIndex: Integer): Boolean;
var
ABracketPosition: PAnsiChar;
AIsEndOfLine: Boolean;
AItem: PdxCompoundFlag;
procedure AllocPattern(AItem: PdxCompoundFlag; ASize: Integer);
begin
AItem^.Count := ASize;
AItem^.Pattern := AllocMem(AItem^.Count * SizeOf(Word));
end;
procedure ReadFlags(APiece: PAnsiChar; AItem: PdxCompoundFlag);
var
AFlags: TdxHunspellFlags;
I: Integer;
begin
AFlags := TdxHunspellFlags.Create(FWordBaseManager);
try
AFlags.Decode(APiece);
for I := 0 to AFlags.Length - 1 do
begin
AItem^.Pattern[AItem^.Length] := AFlags[I];
Inc(AItem^.Length);
end;
finally
AFlags.Free;
end;
end;
begin
AItem := @Data[AIndex];
AllocPattern(AItem, StrLen(APiece));
if StrScan(APiece, '(') <> nil then
begin
AIsEndOfLine := False;
repeat
ABracketPosition := APiece + 1;
while (ABracketPosition^ <> '(') and (ABracketPosition^ <> ')') and (ABracketPosition^ <> #0) do
Inc(ABracketPosition);
if ABracketPosition^ = #0 then
AIsEndOfLine := True
else
ABracketPosition^ := #0;
if APiece^ = '(' then
Inc(APiece);
if (APiece^ = '*') or (APiece^ = '?') then
begin
AItem^.Pattern[AItem^.Length] := Ord(APiece^);
Inc(AItem^.Length);
end
else
if APiece^ <> #0 then
ReadFlags(APiece, AItem);
APiece := ABracketPosition + 1;
until AIsEndOfLine;
end
else
ReadFlags(APiece, AItem);
Result := AItem^.Length <> 0;
end;
{ TdxMapTable }
function TdxMapTable.AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean;
begin
Result := inherited AddDataPiece(APiece, ADataIndex, APieceIndex);
if Result and (APieceIndex = 1) then
begin
Data[ADataIndex].CharacterSet := StrNew(APiece);
Data[ADataIndex].Length := StrLen(Data[ADataIndex].CharacterSet);
end;
end;
procedure TdxMapTable.FreeDataItems;
var
I: Integer;
begin
for I := 0 to Count - 1 do
StrDispose(Data[I].CharacterSet);
end;
function TdxMapTable.GetDataIdentifier: PAnsiChar;
begin
Result := diMap;
end;
function TdxMapTable.GetDataItemSize: Integer;
begin
Result := SizeOf(TdxMapTableItem);
end;
function TdxMapTable.GetPieceQuantity: Integer;
begin
Result := 2;
end;
procedure TdxMapTable.InitializeItem(Index: Integer);
begin
Data[Index].CharacterSet := nil;
Data[Index].Length := 0;
end;
function TdxMapTable.GetData: PdxMapArray;
begin
Result := PdxMapArray(FData);
end;
function TdxMapTable.GetItem(Index: Integer): TdxMapTableItem;
begin
Result := Data[Index];
end;
{ TdxReplaceTable }
function TdxReplaceTable.AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean;
begin
Result := inherited AddDataPiece(APiece, ADataIndex, APieceIndex);
if Result then
case APieceIndex of
1: Data[ADataIndex].Initial := StrReplace(StrNew(APiece), '_', ' ');
2: Data[ADataIndex].Replacement := StrReplace(StrNew(APiece), '_', ' ');
end;
end;
procedure TdxReplaceTable.FreeDataItems;
var
I: Integer;
begin
for I := 0 to Count - 1 do
begin
StrDispose(Data[I].Initial);
StrDispose(Data[I].Replacement);
end;
end;
function TdxReplaceTable.GetDataIdentifier: PAnsiChar;
begin
Result := diRep;
end;
function TdxReplaceTable.GetDataItemSize: Integer;
begin
Result := SizeOf(TdxReplaceTableItem);
end;
function TdxReplaceTable.GetPieceQuantity: Integer;
begin
Result := 3;
end;
procedure TdxReplaceTable.InitializeItem(Index: Integer);
begin
Data[Index].Initial := nil;
Data[Index].Replacement := nil;
end;
function TdxReplaceTable.GetData: PdxReplaceArray;
begin
Result := PdxReplaceArray(FData);
end;
function TdxReplaceTable.GetItem(Index: Integer): TdxReplaceTableItem;
begin
Result := Data[Index];
end;
{ TdxSortedReplaceTable }
function TdxSortedReplaceTable.conv(const Aword: PAnsiChar; dest: PAnsiChar): Integer;
var
stl, I, n, l: Integer;
pc: PAnsiChar;
begin
Result := 0;
if Data = nil then
Exit;
stl := 0;
I := 0;
while I < Length(AWord) do
begin
n := near1(Aword + I);
l := match(Aword + I, n);
if l <> 0 then
begin
pc := Data[n].Replacement;
StrCopy(dest + stl, pc);
Inc(stl, Length(pc));
Inc(I, l - 1);
Result := 1;
end
else
begin
(dest + stl)^ := (Aword + I)^;
Inc(stl);
end;
Inc(I);
end;
(dest + stl)^ := #0;
end;
function TdxSortedReplaceTable.AddDataPiece(const APiece: PAnsiChar; ADataIndex,
APieceIndex: Integer): Boolean;
begin
Result := inherited AddDataPiece(APiece, ADataIndex, APieceIndex);
if Result and (APieceIndex = 2) then
Sort(ADataIndex);
end;
function TdxSortedReplaceTable.match(const Aword: PAnsiChar; n: Integer): Integer;
var
P: TdxReplaceTableItem;
begin
Result := 0;
P := Data[n];
if StrLComp(Aword, P.Initial, Length(P.Initial)) = 0 then
Result := Length(P.Initial);
end;
function TdxSortedReplaceTable.near1(const Aword: PAnsiChar): Integer;
var
p1, p2, m, c: Integer;
begin
p1 := 0;
p2 := Count;
while p2 - p1 > 1 do
begin
m := Round((p1 + p2) / 2);
c := StrComp(Aword, Data[m].Initial);
if c <= 0 then
begin
p2 := m;
if c = 0 then
p1 := m;
end
else
p1 := m;
end;
Result := p1;
end;
procedure TdxSortedReplaceTable.Sort(AIndex: Integer);
var
I: Integer;
AItem: TdxReplaceTableItem;
begin
for I := AIndex downto 1 do
begin
AItem := Data[I];
if StrComp(AItem.Initial, Data[I - 1].Initial) < 0 then
begin
Data[I] := Data[I - 1];
Data[I - 1] := AItem;
end
else
Break;
end;
end;
{ TAffixFileReader }
constructor TAffixFileReader.Create(AAffixManager: TdxHunspellAffixManager);
begin
FAffixManager := AAffixManager;
end;
function TAffixFileReader.ParseFlag(ALine: PAnsiChar; var ADecodedFlag: Word;
AReader: TdxHunspellReader): Boolean;
var
AFlag: PAnsiChar;
begin
Result := True;
AFlag := nil;
if (ADecodedFlag <> NullFlag) and not(ADecodedFlag >= DEFAULTFLAGS) then
begin
Result := False;
Exit;
end;
if not GetSecondPartOfString(ALine, AFlag) then
begin
Result := False;
Exit;
end;
ADecodedFlag := FAffixManager.FWordBaseManager.DecodeFlag(AFlag);
StrDispose(AFlag);
end;
function TAffixFileReader.ParseNumber(ALine: PAnsiChar; out ANumber: Integer): Boolean;
var
ASecondPart: PAnsiChar;
begin
Result := True;
if ANumber <> - 1 then
begin
Result := False;
Exit;
end;
ASecondPart := nil;
try
if GetSecondPartOfString(ALine, ASecondPart) then
ANumber := StrInt(ASecondPart)
else
Result := False;
finally
StrDispose(ASecondPart);
end;
end;
{ TTryReader }
function TTryReader.GetDataIdentifier: PAnsiChar;
begin
Result := diTry;
end;
function TTryReader.Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean;
begin
Result := GetSecondPartOfString(ALine, FAffixManager.FTryChars);
end;
{ TSetReader }
function TSetReader.GetDataIdentifier: PAnsiChar;
begin
Result := diSet;
end;
function TSetReader.Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean;
var
AEncoding: PAnsiChar;
begin
AEncoding := nil;
try
Result := GetSecondPartOfString(ALine, AEncoding);
FAffixManager.CodePage := GetCodePageByName(AEncoding);
if Result and (StrComp(AEncoding, 'UTF-8') = 0) then //TODO:
//TODO:
// FAffixManager.FIsUTF8 := 1;
raise Exception.Create('UTF-8 doesn''t supported');
finally
StrDispose(AEncoding);
end;
end;
{ TComplexPrefixesReader }
function TComplexPrefixesReader.GetDataIdentifier: PAnsiChar;
begin
Result := diComplexPrefixes;
end;
function TComplexPrefixesReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := True;
FAffixManager.FComplexPrefixes := True;
end;
{ TCompoundFlagReader }
function TCompoundFlagReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCompoundFlag;
end;
function TCompoundFlagReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseFlag(ALine, FAffixManager.FCompoundFlag, AReader);
end;
{ TCompoundBeginReader }
function TCompoundBeginReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCompoundBegin;
end;
function TCompoundBeginReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
if FAffixManager.FComplexPrefixes then
Result := ParseFlag(ALine, FAffixManager.FCompoundEnd, AReader)
else
Result := ParseFlag(ALine, FAffixManager.FCompoundBegin, AReader);
end;
{ TCompoundEndReader }
function TCompoundEndReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCompoundEnd;
end;
function TCompoundEndReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
if FAffixManager.FComplexPrefixes then
Result := ParseFlag(ALine, FAffixManager.FCompoundBegin, AReader)
else
Result := ParseFlag(ALine, FAffixManager.FCompoundEnd, AReader);
end;
{ TCompoundMiddleReader }
function TCompoundMiddleReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCompoundMiddle;
end;
function TCompoundMiddleReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseFlag(ALine, FAffixManager.FCompoundMiddle, AReader);
end;
{ TCompoundWordMaxReader }
function TCompoundWordMaxReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCompoundWordMax;
end;
function TCompoundWordMaxReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseNumber(ALine, FAffixManager.FCompoundWordMax);
end;
{ TCompoundRootReader }
function TCompoundRootReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCompoundRoot;
end;
function TCompoundRootReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseFlag(ALine, FAffixManager.FCompoundRoot, AReader);
end;
{ TCompoundPermitFlagReader }
function TCompoundPermitFlagReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCompoundPermitFlag;
end;
function TCompoundPermitFlagReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseFlag(ALine, FAffixManager.FCompoundPermitFlag, AReader);
end;
{ TCompoundForbidFlagReader }
function TCompoundForbidFlagReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCompoundForbidFlag;
end;
function TCompoundForbidFlagReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseFlag(ALine, FAffixManager.FCompoundForbidFlag, AReader);
end;
{ TCheckCompoundDupReader }
function TCheckCompoundDupReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCheckCompoundDup;
end;
function TCheckCompoundDupReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := True;
FAffixManager.FCheckCompoundDup := True;
end;
{ TCheckCompoundRepReader }
function TCheckCompoundRepReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCheckCompoundRep;
end;
function TCheckCompoundRepReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := True;
FAffixManager.FCheckCompoundRep := True;
end;
{ TCheckCompoundTripleReader }
function TCheckCompoundTripleReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCheckCompoundTriple;
end;
function TCheckCompoundTripleReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := True;
FAffixManager.FCheckCompoundTriple := True;
end;
{ TSimplifiedTripleReader }
function TSimplifiedTripleReader.GetDataIdentifier: PAnsiChar;
begin
Result := diSimplifiedTriple;
end;
function TSimplifiedTripleReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := True;
FAffixManager.FSimplifiedTriple := True;
end;
{ TCheckCompoundCaseReader }
function TCheckCompoundCaseReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCheckCompoundCase;
end;
function TCheckCompoundCaseReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := True;
FAffixManager.FCheckCompoundCase := True;
end;
{ TNoSuggestReader }
function TNoSuggestReader.GetDataIdentifier: PAnsiChar;
begin
Result := diNoSuggest;
end;
function TNoSuggestReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseFlag(ALine, FAffixManager.FNoSuggest, AReader);
end;
{ TForbiddenWordReader }
function TForbiddenWordReader.GetDataIdentifier: PAnsiChar;
begin
Result := diForbiddenWord;
end;
function TForbiddenWordReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseFlag(ALine, FAffixManager.FForbiddenWord, AReader);
end;
{ TLemmaPresentReader }
function TLemmaPresentReader.GetDataIdentifier: PAnsiChar;
begin
Result := diLemmaPresent;
end;
function TLemmaPresentReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseFlag(ALine, FAffixManager.FLemmaPresent, AReader);
end;
{ TCircumfixReader }
function TCircumfixReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCircumfix;
end;
function TCircumfixReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseFlag(ALine, FAffixManager.FCircumfix, AReader);
end;
{ TOnlyInCompoundReader }
function TOnlyInCompoundReader.GetDataIdentifier: PAnsiChar;
begin
Result := diOnlyInCompound;
end;
function TOnlyInCompoundReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseFlag(ALine, FAffixManager.FOnlyInCompound, AReader);
end;
{ TPseudoRootReader }
function TPseudoRootReader.GetDataIdentifier: PAnsiChar;
begin
Result := diPseudoRoot;
end;
function TPseudoRootReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseFlag(ALine, FAffixManager.FNeedAffix, AReader)
end;
{ TNeedAffixReader }
function TNeedAffixReader.GetDataIdentifier: PAnsiChar;
begin
Result := diNeedAffix;
end;
function TNeedAffixReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseFlag(ALine, FAffixManager.FNeedAffix, AReader);
end;
{ TCompoundMinReader }
function TCompoundMinReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCompoundMin;
end;
function TCompoundMinReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseNumber(ALine, FAffixManager.FCompoundPartMin);
if FAffixManager.FCompoundPartMin < 1 then
FAffixManager.FCompoundPartMin := 1;
end;
{ TCompoundSyllableReader }
function TCompoundSyllableReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCompoundSyllable;
end;
function TCompoundSyllableReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := FAffixManager.ParseCompoundSyllable(ALine, AReader);
end;
{ TSyllableNumReader }
function TSyllableNumReader.GetDataIdentifier: PAnsiChar;
begin
Result := diSyllableNum;
end;
function TSyllableNumReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := GetSecondPartOfString(ALine, FAffixManager.FSyllableNum);
end;
{ TWordCharsReader }
function TWordCharsReader.GetDataIdentifier: PAnsiChar;
begin
Result := diWordChars;
end;
function TWordCharsReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := False; //TODO:
end;
{ TIgnoreReader }
function TIgnoreReader.GetDataIdentifier: PAnsiChar;
begin
Result := diIgnore;
end;
function TIgnoreReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseArray(ALine, FAffixManager.FIgnore, FAffixManager.IsUTF8);
end;
{ TRepReader }
function TRepReader.GetDataIdentifier: PAnsiChar;
begin
Result := diRep;
end;
function TRepReader.Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean;
begin
Result := FAffixManager.ParseRep(ALine, AReader);
end;
{ TIConvReader }
function TIConvReader.GetDataIdentifier: PAnsiChar;
begin
Result := diIConv;
end;
function TIConvReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := FAffixManager.FInputReplaceTable.ReadData(ALine, AReader);
end;
{ TOConvReader }
function TOConvReader.GetDataIdentifier: PAnsiChar;
begin
Result := diOConv;
end;
function TOConvReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := FAffixManager.FOutputReplaceTable.ReadData(ALine, AReader);
end;
{ TCheckCompoundPatternReader }
function TCheckCompoundPatternReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCheckCompoundPattern;
end;
function TCheckCompoundPatternReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := FAffixManager.FCheckCompoundPatternTable.ReadData(ALine, AReader);
end;
{ TCompoundRuleReader }
function TCompoundRuleReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCompoundRule;
end;
function TCompoundRuleReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := FAffixManager.FCompoundRuleTable.ReadData(ALine, AReader);
end;
{ TMapReader }
function TMapReader.GetDataIdentifier: PAnsiChar;
begin
Result := diMap;
end;
function TMapReader.Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean;
begin
Result := FAffixManager.FMapTable.ReadData(ALine, AReader);
end;
{ TBreakReader }
function TBreakReader.GetDataIdentifier: PAnsiChar;
begin
Result := diBreak;
end;
function TBreakReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := FAffixManager.FBreakTable.ReadData(ALine, AReader);
end;
{ TLangReader }
function TLangReader.GetDataIdentifier: PAnsiChar;
begin
Result := diLang;
end;
function TLangReader.Process(ALine: PAnsiChar; AReader: TdxHunspellReader): Boolean;
var
ALanguage: PAnsiChar;
begin
ALanguage := nil;
try
Result := GetSecondPartOfString(ALine, ALanguage);
if Result then
FAffixManager.FLanguage := GetLanguageID(ALanguage);
finally
StrDispose(ALanguage);
end;
end;
{ TVersionReader }
function TVersionReader.GetDataIdentifier: PAnsiChar;
begin
Result := diVersion;
end;
function TVersionReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := True;
ALine := ALine + 7;
while (ALine^ = ' ') or (ALine^ = #9) do
Inc(ALine);
if ALine^ <> #0 then
FAffixManager.FVersion := StrNew(ALine)
else
FAffixManager.FVersion := nil;
end;
{ TNoSplitSugsReader }
function TNoSplitSugsReader.GetDataIdentifier: PAnsiChar;
begin
Result := diNoSplitSugs;
end;
function TNoSplitSugsReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := True;
FAffixManager.FNoSplitSugs := True;
end;
{ TFullStripReader }
function TFullStripReader.GetDataIdentifier: PAnsiChar;
begin
Result := diFullStrip;
end;
function TFullStripReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := True;
FAffixManager.FFullStrip := True;
end;
{ TSugsWithDotsReader }
function TSugsWithDotsReader.GetDataIdentifier: PAnsiChar;
begin
Result := diSugsWithDots;
end;
function TSugsWithDotsReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := True;
FAffixManager.FSugsWithDots := True;
end;
{ TKeepCaseReader }
function TKeepCaseReader.GetDataIdentifier: PAnsiChar;
begin
Result := diKeepCase;
end;
function TKeepCaseReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseFlag(ALine, FAffixManager.FKeepcase, AReader);
end;
{ TSubStandardReader }
function TSubStandardReader.GetDataIdentifier: PAnsiChar;
begin
Result := diSubStandard;
end;
function TSubStandardReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := ParseFlag(ALine, FAffixManager.FSubstandard, AReader);
end;
{ TCheckSharpsReader }
function TCheckSharpsReader.GetDataIdentifier: PAnsiChar;
begin
Result := diCheckSharps;
end;
function TCheckSharpsReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
begin
Result := True;
FAffixManager.FCheckSharps := 1;
end;
{ TPrefixReader }
function TPrefixReader.GetDataIdentifier: PAnsiChar;
begin
Result := diPrefix;
end;
function TPrefixReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
var
AAffixType: TdxAffixType;
begin
AAffixType := atPrefix;
if FAffixManager.FComplexPrefixes then
AAffixType := atSuffix;
Result := FAffixManager.DoAffixParsing(ALine, AReader, AAffixType);
end;
{ TSuffixReader }
function TSuffixReader.GetDataIdentifier: PAnsiChar;
begin
Result := diSuffix;
end;
function TSuffixReader.Process(ALine: PAnsiChar;
AReader: TdxHunspellReader): Boolean;
var
AAffixType: TdxAffixType;
begin
AAffixType := atSuffix;
if FAffixManager.FComplexPrefixes then
AAffixType := atPrefix;
Result := FAffixManager.DoAffixParsing(ALine, AReader, AAffixType);
end;
end.