{ ****************************************************************************** }
{ * ini text library,writen by QQ 600585@qq.com                                * }
{ * https://zpascal.net                                                        * }
{ * https://github.com/PassByYou888/zAI                                        * }
{ * https://github.com/PassByYou888/ZServer4D                                  * }
{ * https://github.com/PassByYou888/PascalString                               * }
{ * https://github.com/PassByYou888/zRasterization                             * }
{ * https://github.com/PassByYou888/CoreCipher                                 * }
{ * https://github.com/PassByYou888/zSound                                     * }
{ * https://github.com/PassByYou888/zChinese                                   * }
{ * https://github.com/PassByYou888/zExpression                                * }
{ * https://github.com/PassByYou888/zGameWare                                  * }
{ * https://github.com/PassByYou888/zAnalysis                                  * }
{ * https://github.com/PassByYou888/FFMPEG-Header                              * }
{ * https://github.com/PassByYou888/zTranslate                                 * }
{ * https://github.com/PassByYou888/InfiniteIoT                                * }
{ * https://github.com/PassByYou888/FastMD5                                    * }
{ ****************************************************************************** }
(*
  update history
  2017-12-6
  performance optimization
*)

unit TextDataEngine;

{$INCLUDE zDefine.inc}

interface

uses SysUtils, Variants,
{$IFDEF FPC}
  FPCGenericStructlist,
{$ENDIF FPC}
  CoreClasses,
  UnicodeMixedLib,
  PascalStrings,
  ListEngine,
  MemoryStream64;

type
  THashTextEngine = class(TCoreClassObject)
  private
    FComment: TCoreClassStrings;
    FSectionList, FSectionHashVariantList, FSectionHashStringList: THashObjectList;
    FAutoUpdateDefaultValue: Boolean;
    FSectionPoolSize, FListPoolSize: Integer;

    function GetNames(n: SystemString): TCoreClassStrings;
    procedure SetNames(n: SystemString; const Value: TCoreClassStrings);
    function GetHitVariant(SName, VName: SystemString): Variant;
    procedure SetHitVariant(SName, VName: SystemString; const Value: Variant);
    function GetHitString(SName, VName: SystemString): SystemString;
    procedure SetHitString(SName, VName: SystemString; const Value: SystemString);

    // return override state
    function GetHVariantList(n: SystemString): THashVariantList;
    function GetHStringList(n: SystemString): THashStringList;
    procedure AddDataSection(aSection: SystemString; TextList: TCoreClassStrings);
  public
    constructor Create; overload;
    constructor Create(SectionPoolSize_: Integer); overload;
    constructor Create(SectionPoolSize_, ListPoolSize_: Integer); overload;
    destructor Destroy; override;

    procedure Rebuild;
    procedure Clear;
    procedure Delete(n: SystemString);

    function Exists(n: SystemString): Boolean;

    function GetDefaultValue(const SectionName, KeyName: SystemString; const DefaultValue: Variant): Variant;
    procedure SetDefaultValue(const SectionName, KeyName: SystemString; const Value: Variant);

    function GetDefaultText(const SectionName, KeyName: SystemString; const DefaultValue: SystemString): SystemString;
    procedure SetDefaultText(const SectionName, KeyName: SystemString; const Value: SystemString);

    // import section
    function DataImport(TextList: TCoreClassStrings): Boolean; overload;
    function DataImport(TextList: TListPascalString): Boolean; overload;

    // export section
    procedure DataExport(TextList: TCoreClassStrings); overload;
    procedure DataExport(TextList: TListPascalString); overload;

    procedure Merge(sour: THashTextEngine);
    procedure Assign(sour: THashTextEngine);
    function Same(sour: THashTextEngine): Boolean;

    procedure LoadFromStream(stream: TCoreClassStream);
    procedure SaveToStream(stream: TCoreClassStream);

    procedure LoadFromFile(FileName: SystemString);
    procedure SaveToFile(FileName: SystemString);

    function TotalCount: NativeInt;
    function MaxSectionNameLen: Integer;
    function MinSectionNameLen: Integer;

    function GetAsText: SystemString;
    procedure SetAsText(const Value: SystemString);
    property AsText: SystemString read GetAsText write SetAsText;

    procedure GetSectionList(dest: TCoreClassStrings); overload;
    procedure GetSectionList(dest: TListString); overload;
    procedure GetSectionList(dest: TListPascalString); overload;
    function GetSectionObjectName(_Obj: THashVariantList): SystemString; overload;
    function GetSectionObjectName(_Obj: THashStringList): SystemString; overload;

    property AutoUpdateDefaultValue: Boolean read FAutoUpdateDefaultValue write FAutoUpdateDefaultValue;

    property Comment: TCoreClassStrings read FComment write FComment;

    property Hit[SName, VName: SystemString]: Variant read GetHitVariant write SetHitVariant; default;
    property HitVariant[SName, VName: SystemString]: Variant read GetHitVariant write SetHitVariant;
    property HitString[SName, VName: SystemString]: SystemString read GetHitString write SetHitString;

    property Names[n: SystemString]: TCoreClassStrings read GetNames write SetNames;
    property Strings[n: SystemString]: TCoreClassStrings read GetNames write SetNames;

    property VariantList[n: SystemString]: THashVariantList read GetHVariantList;
    property HVariantList[n: SystemString]: THashVariantList read GetHVariantList;
    property StringList[n: SystemString]: THashStringList read GetHStringList;
    property HStringList[n: SystemString]: THashStringList read GetHStringList;
  end;

  TTextDataEngine = THashTextEngine;
  TSectionTextData = THashTextEngine;

  THashTextEngineList_Decl = {$IFDEF FPC}specialize {$ENDIF FPC} TGenericsList<THashTextEngine>;

implementation

function THashTextEngine.GetNames(n: SystemString): TCoreClassStrings;
var
  h: THashVariantTextStream;
begin
  if not FSectionList.Exists(n) then
      FSectionList[n] := TCoreClassStringList.Create;

  if FSectionHashVariantList.Exists(n) then
    begin
      Result := TCoreClassStringList.Create;
      h := THashVariantTextStream.Create(THashVariantList(FSectionHashVariantList[n]));
      h.DataExport(Result);
      DisposeObject(h);

      FSectionList[n] := Result;
    end;

  Result := TCoreClassStrings(FSectionList[n]);
end;

procedure THashTextEngine.SetNames(n: SystemString; const Value: TCoreClassStrings);
var
  ns: TCoreClassStrings;
begin
  ns := TCoreClassStringList.Create;
  ns.Assign(Value);
  FSectionList[n] := ns;
  FSectionHashVariantList.Delete(n);
end;

function THashTextEngine.GetHitVariant(SName, VName: SystemString): Variant;
var
  nsl: TCoreClassStrings;
  vl: THashVariantList;
  vt: THashVariantTextStream;
begin
  Result := Null;
  vl := THashVariantList(FSectionHashVariantList[SName]);
  if vl = nil then
    begin
      nsl := Names[SName];
      if nsl = nil then
          Exit;
      if nsl.Count = 0 then
          Exit;
      vl := THashVariantList.CustomCreate(FListPoolSize);
      vl.AutoUpdateDefaultValue := AutoUpdateDefaultValue;

      vt := THashVariantTextStream.Create(vl);
      vt.DataImport(nsl);
      DisposeObject(vt);

      FSectionHashVariantList[SName] := vl;
    end;
  Result := vl[VName];
end;

procedure THashTextEngine.SetHitVariant(SName, VName: SystemString; const Value: Variant);
var
  nsl: TCoreClassStrings;
  vl: THashVariantList;
  vt: THashVariantTextStream;
begin
  vl := THashVariantList(FSectionHashVariantList[SName]);
  if vl = nil then
    begin
      vl := THashVariantList.CustomCreate(FListPoolSize);
      vl.AutoUpdateDefaultValue := AutoUpdateDefaultValue;

      nsl := Names[SName];
      if nsl <> nil then
        begin
          vt := THashVariantTextStream.Create(vl);
          vt.DataImport(nsl);
          DisposeObject(vt);
        end;
      FSectionHashVariantList[SName] := vl;
    end;
  vl[VName] := Value;
end;

function THashTextEngine.GetHitString(SName, VName: SystemString): SystemString;
var
  nsl: TCoreClassStrings;
  sl: THashStringList;
  st: THashStringTextStream;
begin
  Result := '';
  sl := THashStringList(FSectionHashStringList[SName]);
  if sl = nil then
    begin
      nsl := Names[SName];
      if nsl = nil then
          Exit;
      if nsl.Count = 0 then
          Exit;
      sl := THashStringList.CustomCreate(FListPoolSize);
      sl.AutoUpdateDefaultValue := AutoUpdateDefaultValue;

      st := THashStringTextStream.Create(sl);
      st.DataImport(nsl);
      DisposeObject(st);

      FSectionHashStringList[SName] := sl;
    end;
  Result := sl[VName];
end;

procedure THashTextEngine.SetHitString(SName, VName: SystemString; const Value: SystemString);
var
  nsl: TCoreClassStrings;
  sl: THashStringList;
  st: THashStringTextStream;
begin
  sl := THashStringList(FSectionHashStringList[SName]);
  if sl = nil then
    begin
      sl := THashStringList.CustomCreate(FListPoolSize);
      sl.AutoUpdateDefaultValue := AutoUpdateDefaultValue;

      nsl := Names[SName];
      if nsl <> nil then
        begin
          st := THashStringTextStream.Create(sl);
          st.DataImport(nsl);
          DisposeObject(st);
        end;
      FSectionHashStringList[SName] := sl;
    end;
  sl[VName] := Value;
end;

function THashTextEngine.GetHVariantList(n: SystemString): THashVariantList;
var
  nsl: TCoreClassStrings;
  vt: THashVariantTextStream;
begin
  Result := THashVariantList(FSectionHashVariantList[n]);
  if Result = nil then
    begin
      Result := THashVariantList.CustomCreate(FListPoolSize);
      Result.AutoUpdateDefaultValue := FAutoUpdateDefaultValue;
      nsl := Names[n];
      if nsl <> nil then
        begin
          vt := THashVariantTextStream.Create(Result);
          vt.DataImport(nsl);
          DisposeObject(vt);
        end;

      FSectionHashVariantList[n] := Result;
    end;
end;

function THashTextEngine.GetHStringList(n: SystemString): THashStringList;
var
  nsl: TCoreClassStrings;
  st: THashStringTextStream;
begin
  Result := THashStringList(FSectionHashStringList[n]);
  if Result = nil then
    begin
      Result := THashStringList.CustomCreate(FListPoolSize);
      Result.AutoUpdateDefaultValue := FAutoUpdateDefaultValue;
      nsl := Names[n];
      if nsl <> nil then
        begin
          st := THashStringTextStream.Create(Result);
          st.DataImport(nsl);
          DisposeObject(st);
        end;

      FSectionHashStringList[n] := Result;
    end;
end;

procedure THashTextEngine.AddDataSection(aSection: SystemString; TextList: TCoreClassStrings);
begin
  while (TextList.Count > 0) and (TextList[0] = '') do
      TextList.Delete(0);
  while (TextList.Count > 0) and (TextList[TextList.Count - 1] = '') do
      TextList.Delete(TextList.Count - 1);

  FSectionList.Add(aSection, TextList);
end;

constructor THashTextEngine.Create;
begin
  Create(10, 10);
end;

constructor THashTextEngine.Create(SectionPoolSize_: Integer);
begin
  Create(SectionPoolSize_, 16);
end;

constructor THashTextEngine.Create(SectionPoolSize_, ListPoolSize_: Integer);
begin
  inherited Create;
  FSectionPoolSize := SectionPoolSize_;
  FListPoolSize := ListPoolSize_;

  FComment := TCoreClassStringList.Create;
  FSectionList := THashObjectList.CustomCreate(True, FSectionPoolSize);
  FSectionHashVariantList := THashObjectList.CustomCreate(True, FSectionPoolSize);
  FSectionHashStringList := THashObjectList.CustomCreate(True, FSectionPoolSize);
  FAutoUpdateDefaultValue := False;
end;

destructor THashTextEngine.Destroy;
begin
  Clear;
  DisposeObject(FSectionList);
  DisposeObject(FSectionHashVariantList);
  DisposeObject(FSectionHashStringList);
  DisposeObject(FComment);
  inherited Destroy;
end;

procedure THashTextEngine.Rebuild;
var
  i: Integer;
  tmpSecLst: TListPascalString;
  nsl: TCoreClassStrings;
  hv: THashVariantTextStream;
  hs: THashStringTextStream;
begin
  tmpSecLst := TListPascalString.Create;

  if FSectionHashVariantList.Count > 0 then
    begin
      FSectionHashVariantList.GetListData(tmpSecLst);
      for i := 0 to tmpSecLst.Count - 1 do
        begin
          nsl := TCoreClassStringList.Create;
          hv := THashVariantTextStream.Create(THashVariantList(tmpSecLst.Objects[i]));
          hv.DataExport(nsl);
          DisposeObject(hv);
          FSectionList[tmpSecLst[i]] := nsl;
        end;
      FSectionHashVariantList.Clear;
    end;

  if FSectionHashStringList.Count > 0 then
    begin
      FSectionHashStringList.GetListData(tmpSecLst);
      for i := 0 to tmpSecLst.Count - 1 do
        begin
          nsl := TCoreClassStringList.Create;
          hs := THashStringTextStream.Create(THashStringList(tmpSecLst.Objects[i]));
          hs.DataExport(nsl);
          DisposeObject(hs);
          FSectionList[tmpSecLst[i]] := nsl;
        end;
      FSectionHashStringList.Clear;
    end;

  DisposeObject(tmpSecLst);
end;

procedure THashTextEngine.Clear;
begin
  FSectionList.Clear;
  FSectionHashVariantList.Clear;
  FSectionHashStringList.Clear;
  FComment.Clear;
end;

procedure THashTextEngine.Delete(n: SystemString);
begin
  FSectionList.Delete(n);
  FSectionHashVariantList.Delete(n);
  FSectionHashStringList.Delete(n);
end;

function THashTextEngine.Exists(n: SystemString): Boolean;
begin
  Result := FSectionList.Exists(n) or FSectionHashVariantList.Exists(n) or FSectionHashStringList.Exists(n);
end;

function THashTextEngine.GetDefaultValue(const SectionName, KeyName: SystemString; const DefaultValue: Variant): Variant;
begin
  Result := VariantList[SectionName].GetDefaultValue(KeyName, DefaultValue);
end;

procedure THashTextEngine.SetDefaultValue(const SectionName, KeyName: SystemString; const Value: Variant);
begin
  Hit[SectionName, KeyName] := Value;
end;

function THashTextEngine.GetDefaultText(const SectionName, KeyName: SystemString; const DefaultValue: SystemString): SystemString;
begin
  Result := HStringList[SectionName].GetDefaultValue(KeyName, DefaultValue);
end;

procedure THashTextEngine.SetDefaultText(const SectionName, KeyName: SystemString; const Value: SystemString);
begin
  HitString[SectionName, KeyName] := Value;
end;

function THashTextEngine.DataImport(TextList: TCoreClassStrings): Boolean;
var
  i: Integer;
  ln: U_String;
  nsect: SystemString;
  ntLst: TCoreClassStrings;
begin
  // merge section
  Rebuild;

  // import new section
  ntLst := nil;
  nsect := '';
  Result := False;
  if Assigned(TextList) then
    begin
      if TextList.Count > 0 then
        begin
          i := 0;
          while i < TextList.Count do
            begin
              ln := umlTrimChar(TextList[i], ' ');
              if (ln.Len > 0) and (ln.First = '[') and (ln.Last = ']') then
                begin
                  if Result then
                      AddDataSection(nsect, ntLst);
                  ntLst := TCoreClassStringList.Create;
                  nsect := umlGetFirstStr(ln, '[]').Text;
                  Result := True;
                end
              else if Result then
                begin
                  ntLst.Append(ln);
                end
              else
                begin
                  if (ln.Len > 0) and (not CharIn(ln.First, [';'])) then
                      FComment.Append(ln);
                end;
              inc(i);
            end;
          if Result then
              AddDataSection(nsect, ntLst);
        end;

      while (FComment.Count > 0) and (FComment[0] = '') do
          FComment.Delete(0);
      while (FComment.Count > 0) and (FComment[FComment.Count - 1] = '') do
          FComment.Delete(FComment.Count - 1);
    end;
end;

function THashTextEngine.DataImport(TextList: TListPascalString): Boolean;
var
  i: Integer;
  ln: U_String;
  nsect: SystemString;
  ntLst: TCoreClassStrings;
begin
  // merge section
  Rebuild;

  // import new section
  ntLst := nil;
  nsect := '';
  Result := False;
  if Assigned(TextList) then
    begin
      if TextList.Count > 0 then
        begin
          i := 0;
          while i < TextList.Count do
            begin
              ln := TextList[i].TrimChar(' ');
              if (ln.Len > 0) and (ln.First = '[') and (ln.Last = ']') then
                begin
                  if Result then
                      AddDataSection(nsect, ntLst);
                  ntLst := TCoreClassStringList.Create;
                  nsect := umlGetFirstStr(ln, '[]').Text;
                  Result := True;
                end
              else if Result then
                begin
                  ntLst.Append(ln);
                end
              else
                begin
                  if (ln.Len > 0) and (not CharIn(ln.First, [';'])) then
                      FComment.Append(ln);
                end;
              inc(i);
            end;
          if Result then
              AddDataSection(nsect, ntLst);
        end;

      while (FComment.Count > 0) and (FComment[0] = '') do
          FComment.Delete(0);
      while (FComment.Count > 0) and (FComment[FComment.Count - 1] = '') do
          FComment.Delete(FComment.Count - 1);
    end;
end;

procedure THashTextEngine.DataExport(TextList: TCoreClassStrings);
var
  i: Integer;
  tmpSecLst: TListPascalString;
  nsl: TCoreClassStrings;
begin
  Rebuild;

  TextList.AddStrings(FComment);
  if FComment.Count > 0 then
      TextList.Append('');

  tmpSecLst := TListPascalString.Create;

  FSectionList.GetListData(tmpSecLst);
  if tmpSecLst.Count > 0 then
    for i := 0 to tmpSecLst.Count - 1 do
      if (tmpSecLst.Objects[i] is TCoreClassStrings) then
        begin
          nsl := TCoreClassStrings(tmpSecLst.Objects[i]);
          if nsl <> nil then
            begin
              TextList.Append('[' + tmpSecLst[i] + ']');
              TextList.AddStrings(nsl);
              TextList.Append('');
            end;
        end;

  DisposeObject(tmpSecLst);
end;

procedure THashTextEngine.DataExport(TextList: TListPascalString);
var
  i: Integer;
  tmpSecLst: TListPascalString;
  nsl: TCoreClassStrings;
begin
  Rebuild;

  TextList.AddStrings(FComment);
  if FComment.Count > 0 then
      TextList.Append('');

  tmpSecLst := TListPascalString.Create;

  FSectionList.GetListData(tmpSecLst);
  if tmpSecLst.Count > 0 then
    for i := 0 to tmpSecLst.Count - 1 do
      if (tmpSecLst.Objects[i] is TCoreClassStrings) then
        begin
          nsl := TCoreClassStrings(tmpSecLst.Objects[i]);
          if nsl <> nil then
            begin
              TextList.Append('[' + tmpSecLst[i].Text + ']');
              TextList.AddStrings(nsl);
              TextList.Append('');
            end;
        end;

  DisposeObject(tmpSecLst);
end;

procedure THashTextEngine.Merge(sour: THashTextEngine);
var
  ns: TCoreClassStringList;
begin
  try
    Rebuild;
    ns := TCoreClassStringList.Create;
    sour.Rebuild;
    sour.DataExport(ns);
    DataImport(ns);
    DisposeObject(ns);
    Rebuild;
  except
  end;
end;

procedure THashTextEngine.Assign(sour: THashTextEngine);
var
  ns: TCoreClassStringList;
begin
  try
    ns := TCoreClassStringList.Create;
    sour.Rebuild;
    sour.DataExport(ns);
    Clear;
    DataImport(ns);
    DisposeObject(ns);
  except
  end;
end;

function THashTextEngine.Same(sour: THashTextEngine): Boolean;
var
  i: Integer;
  ns: TCoreClassStringList;
  n: SystemString;
begin
  Result := False;
  Rebuild;
  sour.Rebuild;

  // if Comment.Text <> sour.Comment.Text then
  // Exit;

  if FSectionList.Count <> sour.FSectionList.Count then
      Exit;

  ns := TCoreClassStringList.Create;

  for i := 0 to ns.Count - 1 do
    begin
      n := ns[i];
      if not sour.Exists(n) then
        begin
          DisposeObject(ns);
          Exit;
        end;
    end;

  for i := 0 to ns.Count - 1 do
    begin
      n := ns[i];
      if not SameText(Strings[n].Text, sour.Strings[n].Text) then
        begin
          DisposeObject(ns);
          Exit;
        end;
    end;

  DisposeObject(ns);
  Result := True;
end;

procedure THashTextEngine.LoadFromStream(stream: TCoreClassStream);
var
  n: TListPascalString;
begin
  Clear;
  n := TListPascalString.Create;
  n.LoadFromStream(stream);
  DataImport(n);
  DisposeObject(n);
end;

procedure THashTextEngine.SaveToStream(stream: TCoreClassStream);
var
  n: TListPascalString;
begin
  n := TListPascalString.Create;
  DataExport(n);
  n.SaveToStream(stream);
  DisposeObject(n);
end;

procedure THashTextEngine.LoadFromFile(FileName: SystemString);
var
  m64: TMemoryStream64;
begin
  m64 := TMemoryStream64.Create;
  try
      m64.LoadFromFile(FileName);
  except
    DisposeObject(m64);
    Exit;
  end;

  try
      LoadFromStream(m64);
  finally
      DisposeObject(m64);
  end;
end;

procedure THashTextEngine.SaveToFile(FileName: SystemString);
var
  m64: TMemoryStream64;
begin
  m64 := TMemoryStream64.Create;
  try
    SaveToStream(m64);
    m64.SaveToFile(FileName);
  finally
      DisposeObject(m64);
  end;
end;

function THashTextEngine.TotalCount: NativeInt;
var
  i: Integer;
  tmpSecLst: TListPascalString;
begin
  Result := 0;
  tmpSecLst := TListPascalString.Create;

  FSectionList.GetListData(tmpSecLst);
  if tmpSecLst.Count > 0 then
    for i := 0 to tmpSecLst.Count - 1 do
      if (not FSectionHashVariantList.Exists(tmpSecLst[i])) and (not FSectionHashStringList.Exists(tmpSecLst[i])) then
          inc(Result, TCoreClassStrings(tmpSecLst.Objects[i]).Count);

  FSectionHashVariantList.GetListData(tmpSecLst);
  if tmpSecLst.Count > 0 then
    for i := 0 to tmpSecLst.Count - 1 do
        inc(Result, THashVariantList(tmpSecLst.Objects[i]).Count);

  FSectionHashStringList.GetListData(tmpSecLst);
  if tmpSecLst.Count > 0 then
    for i := 0 to tmpSecLst.Count - 1 do
        inc(Result, THashStringList(tmpSecLst.Objects[i]).Count);

  DisposeObject(tmpSecLst);
end;

function THashTextEngine.MaxSectionNameLen: Integer;
begin
  Result := umlMax(FSectionList.HashList.MaxNameLen,
    umlMax(FSectionHashVariantList.HashList.MaxNameLen, FSectionHashStringList.HashList.MaxNameLen));
end;

function THashTextEngine.MinSectionNameLen: Integer;
begin
  Result := umlMin(FSectionList.HashList.MinNameLen,
    umlMin(FSectionHashVariantList.HashList.MinNameLen, FSectionHashStringList.HashList.MinNameLen));
end;

function THashTextEngine.GetAsText: SystemString;
var
  ns: TPascalStringList;
begin
  ns := TPascalStringList.Create;
  DataExport(ns);
  Result := ns.AsText;
  DisposeObject(ns);
end;

procedure THashTextEngine.SetAsText(const Value: SystemString);
var
  ns: TListPascalString;
begin
  Clear;

  ns := TListPascalString.Create;
  ns.AsText := Value;
  DataImport(ns);
  DisposeObject(ns);
end;

procedure THashTextEngine.GetSectionList(dest: TCoreClassStrings);
begin
  Rebuild;
  FSectionList.GetListData(dest);
end;

procedure THashTextEngine.GetSectionList(dest: TListString);
begin
  Rebuild;
  FSectionList.GetListData(dest);
end;

procedure THashTextEngine.GetSectionList(dest: TListPascalString);
begin
  Rebuild;
  FSectionList.GetListData(dest);
end;

function THashTextEngine.GetSectionObjectName(_Obj: THashVariantList): SystemString;
begin
  Result := FSectionHashVariantList.GetObjAsName(_Obj);
end;

function THashTextEngine.GetSectionObjectName(_Obj: THashStringList): SystemString;
begin
  Result := FSectionHashStringList.GetObjAsName(_Obj);
end;

end.
