123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870 |
- { Parser of the CLDR collation tailoring files.
- This parser handle the textual syntax for CLDR version > 23
- Copyright (c) 2014,2015 by Inoussa OUEDRAOGO
- The source code is distributed under the Library GNU
- General Public License with the following modification:
- - object files and libraries linked into an application may be
- distributed without source code.
- If you didn't receive a copy of the file COPYING, contact:
- Free Software Foundation
- 675 Mass Ave
- Cambridge, MA 02139
- USA
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- }
- unit cldrtxt;
- {$mode delphi}
- {$H+}
- {$SCOPEDENUMS ON}
- {$TypedAddress on}
- interface
- uses
- Classes, SysUtils,
- cldrhelper, helper;
- procedure ParseInitialDocument(
- ASequence : POrderedCharacters;
- ADoc : TCustomMemoryStream;
- ASettings : TSettingRecArray
- );overload;
- procedure ParseInitialDocument(
- ASequence : POrderedCharacters;
- AFileName : string;
- ASettings : TSettingRecArray
- );overload;
- const
- SETTING_WITH_UNICODESET = [
- TSettingOption.SuppressContractions, TSettingOption.Optimize
- ];
- SETTING_OPTION_STRINGS : // Lower case !
- array[Succ(TSettingOption.Unknown)..High(TSettingOption)] of UTF8String = (
- 'strength', 'alternate', 'backwards', 'normalization', 'caselevel', 'casefirst',
- 'hiraganaq', 'numericordering', 'reorder', 'maxvariable', 'import',
- 'suppresscontractions', 'optimize'
- );
- type
- TStatementKind = (Sequence, Setting);
- TParsedStatement = record
- Kind : TStatementKind;
- ReorderSequence : TReorderSequence;
- Setting : TSettingRec;
- end;
- PParsedStatement = ^TParsedStatement;
- function ParseStatement(
- AData : PAnsiChar;
- AStartPosition,
- AMaxLen : Integer;
- AStatement : PParsedStatement;
- var ANextPos,
- ALineCount : Integer
- ) : Boolean;
- procedure Clear(var AItem : TParsedStatement);
- procedure AddItem(var AList : TSettingRecArray; const AItem : PSettingRec);
- implementation
- uses
- unicodedata;
- const
- s_BEFORE = 'before';
- function String2UnicodeCodePointArray(const AValue : UTF8String): TUnicodeCodePointArray;
- var
- u4str : UCS4String;
- k : Integer;
- begin
- if (Length(AValue) = 0) then
- exit(nil);
- if (Length(AValue) = 1) then begin
- SetLength(Result,1);
- Result[0] := Ord(AValue[1])
- end else begin
- u4str := UnicodeStringToUCS4String(UTF8Decode(AValue));
- k := Length(u4str) - 1; // remove the last #0
- SetLength(Result,k);
- for k := 0 to k - 1 do
- Result[k] := u4str[k];
- end;
- end;
- function TryStringToReorderWeigthKind(
- const AStr : UTF8String;
- out AResult : TReorderWeigthKind
- ) : Boolean;
- begin
- Result := True;
- if (AStr = '=') then
- AResult := TReorderWeigthKind.Identity
- else if (AStr = '<') or (AStr = '>') then
- AResult := TReorderWeigthKind.Primary
- else if (AStr = '<<') or (AStr = '>>') then
- AResult := TReorderWeigthKind.Secondary
- else if (AStr = '<<<') or (AStr = '>>>') then
- AResult := TReorderWeigthKind.Tertiary
- else if (AStr = '<<<<') or (AStr = '>>>>') then
- {Quaternary level is treated as Identity !}
- AResult := TReorderWeigthKind.Identity
- else begin
- AResult := TReorderWeigthKind.Identity;
- Result := False;
- end;
- end;
- function StringToSettingOption(const AStr : UTF8String) : TSettingOption;
- var
- e : TSettingOption;
- s : UTF8String;
- begin
- s := LowerCase(AStr);
- for e := Succ(TSettingOption.Unknown) to High(TSettingOption) do begin
- if (s = SETTING_OPTION_STRINGS[e]) then
- exit(e);
- end;
- Result := TSettingOption.Unknown;
- end;
- procedure Clear(var AItem : TParsedStatement);
- begin
- AItem.Setting.Clear();
- AItem.ReorderSequence.Clear();
- AItem.Kind := TStatementKind(0);
- end;
- procedure AddItem(var AList : TSettingRecArray; const AItem : PSettingRec);
- var
- c : Integer;
- begin
- c := Length(AList);
- SetLength(AList,(c+1));
- AList[c].Assign(AItem);
- end;
- procedure FromUCS4(const AValue : UCS4Char; var AHighS, ALowS : UnicodeChar);
- begin
- AHighS := UnicodeChar((AValue - $10000) shr 10 + $d800);
- ALowS := UnicodeChar((AValue - $10000) and $3ff + $dc00);
- end;
- function ParseStatement(
- AData : PAnsiChar;
- AStartPosition,
- AMaxLen : Integer;
- AStatement : PParsedStatement;
- var ANextPos,
- ALineCount : Integer
- ) : Boolean;
- const
- LINE_LENGTH = 1024;
- var
- p : PAnsiChar;
- bufferLength, bufferPos, lineLength, linePos, lineIndex : Integer;
- line : UTF8String;
- statement : PReorderSequence;
- elementActualCount : Integer;
- specialChararter : Boolean;
- historyItemIndex : Integer;
- historyItems : array[0..31] of record
- p : PAnsiChar;
- bufferLength,
- bufferPos,
- lineLength,
- linePos,
- lineIndex : Integer;
- line : UTF8String;
- end;
- procedure SaveState();
- begin
- if (historyItemIndex >= High(historyItems)) then
- raise Exception.Create('History buffer is full.');
- historyItemIndex := historyItemIndex+1;
- historyItems[historyItemIndex].p := p;
- historyItems[historyItemIndex].bufferLength := bufferLength;
- historyItems[historyItemIndex].bufferPos := bufferPos;
- historyItems[historyItemIndex].lineLength := lineLength;
- historyItems[historyItemIndex].linePos := linePos;
- historyItems[historyItemIndex].lineIndex := lineIndex;
- historyItems[historyItemIndex].line := line;
- end;
- procedure RestoreState();
- begin
- if (historyItemIndex < 0) then
- raise Exception.Create('History buffer is empty.');
- p := historyItems[historyItemIndex].p;
- bufferLength := historyItems[historyItemIndex].bufferLength;
- bufferPos := historyItems[historyItemIndex].bufferPos;
- lineLength := historyItems[historyItemIndex].lineLength;
- linePos := historyItems[historyItemIndex].linePos;
- lineIndex := historyItems[historyItemIndex].lineIndex;
- line := historyItems[historyItemIndex].line;
- historyItemIndex := historyItemIndex-1;
- end;
- procedure DiscardState();
- begin
- if (historyItemIndex < 0) then
- raise Exception.Create('History buffer is empty.');
- historyItemIndex := historyItemIndex-1;
- end;
- function CurrentLine() : UTF8String; inline;
- begin
- Result := Copy(line,1,lineLength);
- end;
- function NextLine() : Boolean;
- var
- locOldPos : Integer;
- locOldPointer : PAnsiChar;
- begin
- Result := False;
- if (p^ = #10) then begin
- Inc(p);
- Inc(bufferPos);
- end;
- locOldPos := bufferPos;
- locOldPointer := p;
- while (bufferPos < bufferLength) and (p^ <> #10) do begin
- Inc(p);
- Inc(bufferPos);
- end;
- if (locOldPos = bufferPos) and (p^ = #10) then begin
- lineLength := 0;
- Inc(p);
- Inc(bufferPos);
- linePos := 1;
- Result := True;
- end else if (locOldPos < bufferPos) then begin
- lineLength := (bufferPos - locOldPos);
- if (lineLength >= Length(line)) then
- SetLength(line,(2*lineLength));
- Move(locOldPointer^,line[1],lineLength);
- {if (p^ = #10) then begin
- //Dec(lineLength);
- Inc(p);
- Inc(bufferPos);
- end;}
- linePos := 1;
- Result := True;
- end;
- if Result and (locOldPos < bufferPos) then
- lineIndex := lineIndex+1;
- end;
- procedure CheckLineLength(const ALength : Integer);
- begin
- if (ALength > lineLength) then
- raise Exception.CreateFmt('Unexpected end of line : "%s".',[CurrentLine()]);
- end;
- function ReadChar(out AResult : UTF8String) : Boolean;
- var
- k : Integer;
- us : UnicodeString;
- begin
- AResult := '';
- Result := False;
- if (linePos > lineLength) then
- exit;
- {if CharInSet(line[linePos],['#','=','&','[',']']) then begin
- AResult := line[linePos];
- Inc(linePos);
- exit(True);
- end;}
- if (line[linePos] <> '\') then begin
- AResult := line[linePos];
- Inc(linePos);
- exit(True);
- end;
- CheckLineLength(linePos+1);
- Inc(linePos);
- case line[linePos] of
- '''': begin
- AResult := '\';
- exit(True);
- end;
- '\' : begin
- AResult := '\';
- Inc(linePos);
- exit(True);
- end;
- 'u' : begin
- CheckLineLength(linePos+4);
- AResult := '$'+Copy(line,(linePos+1),4);
- if not TryStrToInt(AResult,k) then
- raise Exception.CreateFmt('Hexadecimal Integer expected but found "%s", line = "%s".',[AResult,CurrentLine()]);
- SetLength(us,1);
- us[1] := UnicodeChar(k);
- AResult := UTF8Encode(us);
- Inc(linePos,5);
- exit(True);
- end;
- 'U' : begin
- CheckLineLength(linePos+8);
- AResult := '$'+Copy(line,(linePos+1),8);
- if not TryStrToInt(AResult,k) then
- raise Exception.CreateFmt('Hexadecimal Integer expected but found "%s".',[AResult]);
- if (k > High(Word)) then begin
- SetLength(us,2);
- FromUCS4(k,us[1],us[2]);
- if (Ord(us[2]) = 0) then
- SetLength(us,1);
- end else begin
- SetLength(us,1);
- us[1] := UnicodeChar(k);
- end;
- AResult := UTF8Encode(us);
- Inc(linePos,9);
- exit(True);
- end;
- else
- raise Exception.CreateFmt('Invalide escaped string "%s", at %d position.',[CurrentLine(),linePos]);
- end;
- end;
- function ReadQuotedString() : UTF8String;
- var
- ks : UTF8String;
- begin
- if (line[linePos] <> '''') then
- raise Exception.CreateFmt('Unexpected character found "%s", a quote expected: "%s".',[line[linePos],CurrentLine()]);
- Inc(linePos);
- if (linePos > lineLength) then
- raise Exception.CreateFmt('Unexpected end of line, a quote expected: "%s".',[CurrentLine()]);
- if (line[linePos] = '''') then begin
- Inc(linePos);
- Result := '''';
- exit;
- end;
- Result := '';
- while (linePos <= lineLength) and ReadChar(ks) do begin
- Result := Result + ks;
- if (line[linePos] = '''') then
- break;
- end;
- if (line[linePos] = '''') then begin
- Inc(linePos);
- exit;
- end;
- raise Exception.CreateFmt('Unexpected end of line, a quote expected: "%s".',[line]);
- end;
- function ReadUnQuotedString() : UTF8String;
- var
- k : Integer;
- begin
- k := linePos;
- while (linePos <= lineLength) and
- not(CharInSet(line[linePos],[' ',#9,'#', '=','&','[',']','<','>','''','/','|']))
- do begin
- Inc(linePos);
- end;
- if (linePos > k) then begin
- if (line[linePos] in [' ',#9,'#', '=','&','[',']','<','>','''','/','|']) then
- Result := Copy(line,k,(linePos-k))
- else
- Result := Copy(line,k,(linePos-k)); //Result := Copy(line,k,(linePos-k+1));
- end else begin
- Result := '';
- end;
- end;
- function NextToken() : UTF8String; overload;
- var
- k : Integer;
- ks : UTF8String;
- begin
- specialChararter := False;
- while True do begin
- while (linePos <= lineLength) and CharInSet(line[linePos],[' ', #9, #13]) do begin
- Inc(linePos);
- end;
- if (linePos > lineLength) or (line[linePos] = '#') then begin
- if not NextLine() then begin
- if (line[linePos] = '#') then
- linePos := lineLength+1; // A comment terminates a line !
- exit('');
- end;
- Continue;
- end ;
- Break;
- end;
- if (linePos > lineLength) then
- exit('');
- if (line[linePos] = '*') then begin
- linePos := linePos+1;
- specialChararter := True;
- exit('*');
- end;
- k := linePos;
- if (linePos <= lineLength) and CharInSet(line[linePos],['<','>']) then begin
- ks := line[linePos];
- while (linePos <= lineLength) and (line[linePos] = ks) do begin
- Inc(linePos);
- end;
- Result := Copy(line,k,(linePos-k));
- exit;
- end;
- if (linePos <= lineLength) and
- CharInSet(line[linePos],['=','&','[',']','<','>','/','|'])
- then begin
- Inc(linePos);
- Result := Copy(line,k,(linePos-k));
- specialChararter := True;
- exit;
- end;
- {if (line[linePos] = '''') then
- exit(ReadQuotedString()); }
- Result := '';
- while (linePos <= lineLength) do begin
- if CharInSet(line[linePos],[' ',#9,#13,'#', '=','&','[',']','<','>','/','|']) then
- Break;
- if (line[linePos] <> '''') then
- ks := ReadUnQuotedString()
- else
- ks := ReadQuotedString();
- if (ks = '') then
- Break;
- Result := Result + ks;
- end;
- end;
- function NextToken(const AMustSucceed : Boolean) : UTF8String; overload;
- begin
- Result := NextToken();
- if (Result = '') and AMustSucceed then
- raise Exception.CreateFmt('Unexpected end of line(%d) : "%s".',[lineIndex,CurrentLine()]);
- end;
- procedure CheckToken(const AActual, AExpectedToken : UTF8String);
- begin
- if (AActual <> AExpectedToken) then
- raise Exception.CreateFmt(
- '"%s" expected but "%s" found at position %d, BufferPosition(%d), line(%d) = "%s".',
- [AExpectedToken,AActual,linePos,bufferPos,lineIndex,CurrentLine()]
- );
- end;
- function parse_reset() : Boolean;
- var
- s, s1 : UTF8String;
- logicalPos : TReorderLogicalReset;
- k : Integer;
- begin
- s := NextToken(True);
- if (s = '[') and specialChararter then begin
- s := NextToken();
- if (s = s_BEFORE) then begin
- s := NextToken();
- if not(TryStrToInt(s,k)) or (k < 1) or (k > 3) then
- CheckToken(s,'"1" or "2" or "3"');
- CheckToken(NextToken(True),']');
- statement^.Reset := String2UnicodeCodePointArray(NextToken(True));
- statement^.Before := True;
- end else begin
- while True do begin
- s1 := NextToken();
- if (s1 = '') or (s1 = ']') then
- break;
- s := s + Trim(s1)
- end;
- CheckToken(s1,']');
- if (s = '') then
- raise Exception.CreateFmt('Unexpected end of line : "%s".',[CurrentLine()]);
- if not TryStrToLogicalReorder(s,logicalPos) then
- raise Exception.CreateFmt(sUnknownResetLogicalPosition,[s]);
- statement^.LogicalPosition := logicalPos;
- end;
- end else begin
- statement^.Reset := String2UnicodeCodePointArray(s);
- end;
- if (statement^.LogicalPosition = TReorderLogicalReset.None) and
- (Length(statement^.Reset) = 0)
- then
- raise Exception.Create(sInvalidResetClause);
- Result := True;
- end;
- procedure EnsureElementLength(const ALength : Integer);
- var
- k, d : Integer;
- begin
- k := Length(statement^.Elements);
- if (k < ALength) then begin
- k := ALength;
- if (k = 0) then begin
- k := 50;
- end else begin
- if (k < 10) then
- d := 10
- else
- d := 2;
- k := k * d;
- end;
- statement^.SetElementCount(k);
- end;
- end;
- procedure AddElement(
- const AChars : array of UCS4Char;
- const AWeigthKind : TReorderWeigthKind;
- const AContext : UTF8String
- );overload;
- var
- kp : PReorderUnit;
- kc, k : Integer;
- begin
- EnsureElementLength(elementActualCount+1);
- kp := @statement^.Elements[elementActualCount];
- kc := Length(AChars)-1;
- if (kc < 0) then
- kc := 0;
- SetLength(kp^.Characters,kc);
- for k := 0 to kc - 1 do
- kp^.Characters[k] := AChars[k];
- kp^.WeigthKind := AWeigthKind;
- elementActualCount := elementActualCount + 1;
- if (AContext <> '') then
- kp^.Context := String2UnicodeCodePointArray(AContext);
- end;
- procedure AddElement(
- const AChar : UCS4Char;
- const AWeigthKind : TReorderWeigthKind;
- const AContext : UTF8String
- );overload;
- var
- kp : PReorderUnit;
- kc, k : Integer;
- begin
- EnsureElementLength(elementActualCount+1);
- kp := @statement^.Elements[elementActualCount];
- SetLength(kp^.Characters,1);
- kp^.Characters[0] := AChar;
- kp^.WeigthKind := AWeigthKind;
- elementActualCount := elementActualCount + 1;
- if (AContext <> '') then
- kp^.Context := String2UnicodeCodePointArray(AContext);
- end;
- function ReadNextItem() : Boolean;
- var
- contextStr : UTF8String;
- w : TReorderWeigthKind;
- last : PReorderUnit;
- u4str : UCS4String;
- s, ts : UTF8String;
- expandStr : TUnicodeCodePointArray;
- k, kc, x : Integer;
- us : UnicodeString;
- begin
- contextStr := '';
- expandStr := nil;
- Result := False;
- SaveState();
- s := NextToken();
- if (s = '') then begin
- DiscardState();
- exit;
- end;
- if specialChararter and (s = '&') then begin
- RestoreState();
- exit;
- end;
- DiscardState();
- if not TryStringToReorderWeigthKind(s,w) then
- CheckToken(s,'Reorder Weigth');
- s := NextToken(True);
- if specialChararter then begin
- if (s = '[') then begin
- k := 1;
- while True do begin
- ts := NextToken(True);
- s := s + ts;
- if specialChararter then begin
- if (ts = '[') then
- k := k+1
- else if (ts = ']') then begin
- k := k-1;
- if (k = 0) then
- Break;
- end;
- end;
- end;
- if (Pos('variable',s) > 0) then
- exit(True);
- end else if (s = '*') then begin
- s := NextToken(True);
- us := UTF8Decode(s);
- u4str := UnicodeStringToUCS4String(us);
- kc := Length(u4str)-1;
- k := 0;
- while (k <= (kc-1)) do begin
- if (k > 0) and (u4str[k] = Ord('-')) then begin
- if (k = (kc-1)) then begin
- AddElement(u4str[k],w,contextStr);
- end else begin
- for x := (u4str[k-1]+1) to u4str[k+1] do
- AddElement(x,w,contextStr);
- k := k+1;
- end;
- end else begin
- AddElement(u4str[k],w,contextStr);
- end;
- k := k+1;
- end;
- exit(True);
- end;
- end;
- SaveState();
- ts := NextToken();
- if (ts = '') or not(specialChararter) then begin
- RestoreState();
- us := UTF8Decode(s);
- u4str := UnicodeStringToUCS4String(us);
- end else begin
- if (ts = '|') then begin
- DiscardState();
- contextStr := s;
- s := NextToken(True);
- SaveState();
- ts := NextToken();
- end;
- if specialChararter and (ts = '/') then begin
- expandStr := String2UnicodeCodePointArray(NextToken(True));
- DiscardState();
- end else begin
- RestoreState();
- end;
- u4str := UnicodeStringToUCS4String(UTF8Decode(s));
- end;
- AddElement(u4str,w,contextStr);
- if (Length(expandStr) > 0) then begin
- last := @statement^.Elements[elementActualCount-1];
- last^.ExpansionChars := expandStr;
- end;
- Result := True;
- end;
- function ReadUnicodeSet() : UTF8String;
- var
- k, c : Integer;
- ks : UTF8String;
- begin
- while True do begin
- while (linePos <= lineLength) and CharInSet(line[linePos],[' ', #9, #13]) do begin
- Inc(linePos);
- end;
- if (linePos > lineLength) or (line[linePos] = '#') then begin
- if not NextLine() then begin
- if (line[linePos] = '#') then
- linePos := lineLength+1; // A comment terminates a line !
- exit('');
- end;
- Continue;
- end ;
- Break;
- end;
- if (linePos > lineLength) then
- exit('');
- if (line[linePos] <> '[') then
- exit;
- k := linePos;
- c := 1;
- ks := '';
- linePos := linePos+1;
- while (linePos <= lineLength) do begin
- if (line[linePos] = '[') then
- c := c+1
- else if (line[linePos] = ']') then
- c := c-1;
- if (c = 0) then
- break;
- linePos := linePos+1;
- if (linePos > lineLength) then begin
- ks := ks+Copy(line,k,linePos);
- if not NextLine() then
- raise Exception.CreateFmt(sInvalidUnicodeSetExpression,[line]);
- k := linePos;
- end;
- end;
- if (line[linePos] <> ']') then
- raise Exception.CreateFmt(sInvalidUnicodeSetExpression,[line]);
- linePos := linePos+1;
- ks := ks+Copy(line,k,(linePos-k));
- Result := ks;
- end;
- function ParseSetting() : Boolean;
- var
- name, value : UTF8String;
- c, k : Integer;
- begin
- name := NextToken(True);
- if (name = ']') then
- raise Exception.CreateFmt(sInvalidSettingExpression,[line]);
- AStatement^.Setting.Name := name;
- AStatement^.Setting.OptionValue := StringToSettingOption(AStatement^.Setting.Name);
- if (AStatement^.Setting.OptionValue in SETTING_WITH_UNICODESET) then begin
- value := ReadUnicodeSet();
- if (value = '') then
- raise Exception.CreateFmt(sInvalidSettingExpression,[line]);
- CheckToken(NextToken(True),']');
- SetLength(AStatement^.Setting.Values,1);
- AStatement^.Setting.Values[0] := value;
- Result := True;
- end else begin
- c := 0;
- while True do begin
- value := NextToken((c = 0));
- if (value = '') or (specialChararter and (value = ']')) then begin
- if (c = 0) then
- raise Exception.CreateFmt(sInvalidSettingExpression,[line]);
- break;
- end;
- k := Length(AStatement^.Setting.Values);
- SetLength(AStatement^.Setting.Values,(k+1));
- AStatement^.Setting.Values[k] := value;
- c := c+1;
- end;
- Result := (c > 0);
- end;
- end;
- var
- locToken : UTF8String;
- begin
- Result := False;
- elementActualCount := 0;
- if (AStartPosition >= AMaxLen) then
- exit;
- historyItemIndex := -1;
- lineIndex := ALineCount;
- bufferLength := AMaxLen;
- bufferPos := AStartPosition;
- p := AData+AStartPosition;
- SetLength(line,LINE_LENGTH);
- Clear(AStatement^);
- if not NextLine() then
- exit;
- locToken := NextToken();
- if (locToken = '') then
- exit;
- if not specialChararter then
- raise Exception.CreateFmt(sSpecialCharacterExpected,[locToken,CurrentLine()]);
- if (locToken = '&') then begin
- AStatement.Kind := TStatementKind.Sequence;
- statement := @AStatement.ReorderSequence;
- if not parse_reset() then
- exit;
- while ReadNextItem() do begin
- // All done in the condition
- end;
- statement^.SetElementCount(elementActualCount);
- end else if (locToken = '[') then begin
- if not ParseSetting() then
- exit;
- AStatement.Kind := TStatementKind.Setting;
- end;
- if (linePos > lineLength) then
- linePos := lineLength+1;
- ANextPos := bufferPos-lineLength+linePos-1;
- Result := (ANextPos > AStartPosition);
- ALineCount := lineIndex;
- end;
- procedure ParseInitialDocument(
- ASequence : POrderedCharacters;
- ADoc : TCustomMemoryStream;
- ASettings : TSettingRecArray
- );
- var
- buffer : PAnsiChar;
- bufferLength : Integer;
- i, nextPost : Integer;
- statement : TParsedStatement;
- p : PReorderUnit;
- lineCount : Integer;
- begin
- if (ADoc.Size < 1) then
- exit;
- buffer := ADoc.Memory; //0xEF,0xBB,0xBF
- bufferLength := ADoc.Size;
- if (bufferLength >= 3) and
- (Byte(buffer[0]) = $EF) and
- (Byte(buffer[1]) = $BB) and
- (Byte(buffer[2]) = $BF)
- then begin
- Inc(buffer,3);
- Dec(bufferLength,3);
- end;
- lineCount := 0;
- ASequence^.Clear();
- SetLength(ASequence^.Data,50000);
- nextPost := 0;
- i := 0;
- while (i < bufferLength) do begin
- Clear(statement);
- if not ParseStatement(buffer,i,bufferLength,@statement,nextPost,lineCount) then
- Break;
- i := nextPost;
- try
- if (statement.Kind = TStatementKind.Sequence) then
- ASequence^.ApplyStatement(@statement.ReorderSequence)
- else
- AddItem(ASettings,@statement.Setting);
- except
- on e : Exception do begin
- e.Message := Format('%s Position = %d',[e.Message,i]);
- raise;
- end;
- end;
- end;
- if (ASequence^.ActualLength > 0) then begin
- p := @ASequence^.Data[0];
- for i := 0 to ASequence^.ActualLength - 1 do begin
- p^.Changed := False;
- Inc(p);
- end;
- end;
- end;
- procedure ParseInitialDocument(
- ASequence : POrderedCharacters;
- AFileName : string;
- ASettings : TSettingRecArray
- );
- var
- doc : TMemoryStream;
- begin
- doc := TMemoryStream.Create();
- try
- doc.LoadFromFile(AFileName);
- doc.Position := 0;
- ParseInitialDocument(ASequence,doc,ASettings);
- finally
- doc.Free();
- end;
- end;
- end.
|