unit QExport4IniFiles;

{$I QExport4VerCtrl.inc}

interface

uses
  {$IFDEF VCL16}
    System.Classes,
    System.IniFiles,
    System.SysUtils,
  {$ELSE}
    Classes,
    IniFiles,
    SysUtils,
  {$ENDIF}
  QExport4Types;

type
  TQIniFile = class(TObject)
  private
    FIniFile: TCustomIniFile;
    FStream: TStream;
    FStrings: TStrings;
    FVersion: Integer;
    function GetFileName: string;
    function GetInnerIniFile: TCustomIniFile;
  public
    constructor Create(const AFileName: string); overload;
    constructor Create(AStream: TStream); overload;
    constructor CreateWritingVersion(const AFileName: string; ANumVersion: Integer); overload;
    constructor CreateWritingVersion(AStream: TStream; ANumVersion: Integer); overload;
    destructor Destroy; override;

    function SectionExists(const Section: string): Boolean;
    function ReadString(const Section, Ident, Default: string): string;
    procedure WriteString(const Section, Ident, Value: String);
    function ReadBool(const Section, Ident: string; Default: Boolean): Boolean;
    procedure WriteBool(const Section, Ident: string; Value: Boolean);
    function ReadInteger(const Section, Ident: string; Default: Longint): Longint;
    procedure WriteInteger(const Section, Ident: string; Value: Longint);

    function ReadDate(const Section, Name: string; Default: TDateTime): TDateTime;
    procedure WriteDate(const Section, Name: string; Value: TDateTime);
    function ReadDateTime(const Section, Name: string; Default: TDateTime): TDateTime;
    procedure WriteDateTime(const Section, Name: string; Value: TDateTime);
    function ReadFloat(const Section, Name: string; Default: Double): Double;
    procedure WriteFloat(const Section, Name: string; Value: Double);
    function ReadTime(const Section, Name: string; Default: TDateTime): TDateTime;
    procedure WriteTime(const Section, Name: string; Value: TDateTime);

    procedure DeleteKey(const Section, Ident: string);
    procedure EraseSection(const Section: string);
    procedure ReadSection(const Section: string; Strings: TStrings);
    procedure ReadSections(Strings: TStrings);
    procedure ReadSectionValues(const Section: string; Strings: TStrings);
    procedure UpdateFile;
    function ValueExists(const Section, Ident: string): Boolean; 

    procedure ReadSectionValuesW(const Section: string; Strings: TqeStrings);
    function ReadStringW(const Section, Ident: string;
      const Default: QEString): QEString;
    function TryReadChar(const Section: string; Ident: string; const Default: Char): Char;
    procedure WriteStringW(const Section, Ident: string; const Value: QEString);
    procedure WriteVersionSection;
    procedure ReadVersionSection;
    procedure LoadFromStream;
    procedure SaveToStream;

    property InnerIniFile: TCustomIniFile read GetInnerIniFile;
    property Version: Integer read FVersion write FVersion;
    property FileName: string read GetFileName;
  end;


  {$IFDEF VER130}
  function Utf8Decode(AString: Widestring): WideString;
  function Utf8Encode(AString: Widestring): WideString;
  {$ENDIF}

implementation

  {$IFDEF VER130}
  function Utf8Decode(AString: Widestring): WideString;
  begin
    Result := AString;
  end;

  function Utf8Encode(AString: Widestring): WideString;
  begin
    Result := AString;
  end;

 {$ENDIF}

{ TQIniFile }
constructor TQIniFile.Create(const AFileName: string);
begin
  inherited Create;
  FIniFile := TIniFile.Create(AFileName);
  FVersion := 0;
  FStrings := nil;
  FStream := nil;
end;

constructor TQIniFile.CreateWritingVersion(const AFileName: string; ANumVersion: Integer);
begin
  inherited Create;
  FIniFile := TIniFile.Create(AFileName);
  FVersion := ANumVersion;                                                       
  FStrings := nil;
  FStream := nil;
  WriteVersionSection;
end;

constructor TQIniFile.CreateWritingVersion(AStream: TStream;
  ANumVersion: Integer);
begin
  inherited Create;
  FIniFile := TMemIniFile.Create(EmptyStr);
  FVersion := ANumVersion;
  FStrings := TStringList.Create;
  FStream := AStream;    
  WriteVersionSection;
end;

procedure TQIniFile.DeleteKey(const Section, Ident: string);
begin
  FIniFile.DeleteKey(Section, Ident);
end;

destructor TQIniFile.Destroy;
begin
  FIniFile.Free;
  FStrings.Free;
  inherited;
end;

procedure TQIniFile.EraseSection(const Section: string);
begin
  FIniFile.EraseSection(Section);
end;

function TQIniFile.GetFileName: string;
begin
  Result := FIniFile.FileName;
end;

function TQIniFile.GetInnerIniFile: TCustomIniFile;
begin
  Result := FIniFile;
end;

procedure TQIniFile.LoadFromStream;
begin
  if not Assigned(FStrings) then
    Exit;

  FStrings.LoadFromStream(FStream);
  (FIniFile as TMemIniFile).SetStrings(FStrings);
end;

function TQIniFile.ReadBool(const Section, Ident: string;
  Default: Boolean): Boolean;
begin
  Result := FIniFile.ReadBool(Section, Ident, Default);
end;

function TQIniFile.ReadDate(const Section, Name: string;
  Default: TDateTime): TDateTime;
begin
  Result := FIniFile.ReadDate(Section, Name, Default);
end;

function TQIniFile.ReadDateTime(const Section, Name: string;
  Default: TDateTime): TDateTime;
begin
  Result := FIniFile.ReadDateTime(Section, Name, Default);
end;

function TQIniFile.ReadFloat(const Section, Name: string;
  Default: Double): Double;
begin
  Result := FIniFile.ReadFloat(Section, Name, Default);
end;

function TQIniFile.ReadInteger(const Section, Ident: string;
  Default: Integer): Longint;
begin
  Result := FIniFile.ReadInteger(Section, Ident, Default);
end;

procedure TQIniFile.ReadSection(const Section: string; Strings: TStrings);
begin
  FIniFile.ReadSection(Section, Strings);
end;

procedure TQIniFile.ReadSections(Strings: TStrings);
begin
  FIniFile.ReadSections(Strings);
end;

procedure TQIniFile.ReadSectionValues(const Section: string; Strings: TStrings);
begin
  FIniFile.ReadSectionValues(Section, Strings);
end;

procedure TQIniFile.ReadSectionValuesW(const Section: string; Strings: TqeStrings);
{$IFDEF QE_UNICODE}
var
  TempStrList: TStrings;
  I: Integer;
{$ENDIF}
begin
{$IFDEF QE_UNICODE}
  TempStrList := TStringList.Create;
  ReadSectionValues(Section, TempStrList);
  if Version >= 400 then
    for I := 0 to TempStrList.Count - 1 do
      Strings.Add(Utf8Decode(AnsiString(TempStrList[I])))
  else
    for I := 0 to TempStrList.Count - 1 do
      Strings.Add(TempStrList[I]);
  TempStrList.Free;
{$ELSE}
  ReadSectionValues(Section, Strings);
{$ENDIF}
end;

function TQIniFile.ReadString(const Section, Ident, Default: string): string;
begin
  Result := FIniFile.ReadString(Section, Ident, Default);
end;

function TQIniFile.ReadStringW(const Section, Ident: string;
  const Default: QEString): QEString;
begin
{$IFDEF QE_UNICODE}
  if Version >= 400 then
    Result := Utf8Decode(AnsiString(ReadString(Section, Ident, Default)))
  else
    Result := ReadString(Section, Ident, Default);
{$ELSE}
  Result := ReadString(Section, Ident, Default);
{$ENDIF} 
end;

function TQIniFile.ReadTime(const Section, Name: string;
  Default: TDateTime): TDateTime;
begin
  Result := FIniFile.ReadTime(Section, Name, Default);
end;

procedure TQIniFile.ReadVersionSection;
begin
  Version := StrToIntDef(ReadString('IniVersion', 'Number', '0'), 0);
end;

procedure TQIniFile.SaveToStream;
var
  I: Integer;
begin
  if not Assigned(FStrings) then
    Exit;

  (FIniFile as TMemIniFile).GetStrings(FStrings);
  for I := FStrings.Count - 1 downto 0 do
    if FStrings[I] = EmptyStr then
      FStrings.Delete(I);
  FStrings.SaveToStream(FStream);
end;

function TQIniFile.SectionExists(const Section: string): Boolean;
begin
  Result := FIniFile.SectionExists(Section);
end;

function TQIniFile.TryReadChar(const Section: string; Ident: string;
  const Default: Char): Char;
var
  S: string;
begin
  S := ReadString(Section, Ident, Default);
  if S = '' then
    Result := Default
  else
    Result := S[1];
end;

procedure TQIniFile.UpdateFile;
begin
  FIniFile.UpdateFile;
end;

function TQIniFile.ValueExists(const Section, Ident: string): Boolean;
begin
  Result := FIniFile.ValueExists(Section, Ident);
end;

procedure TQIniFile.WriteBool(const Section, Ident: string; Value: Boolean);
begin
  FIniFile.WriteBool(Section, Ident, Value);
end;

procedure TQIniFile.WriteDate(const Section, Name: string; Value: TDateTime);
begin
  FIniFile.WriteDate(Section, Name, Value);
end;

procedure TQIniFile.WriteDateTime(const Section, Name: string;
  Value: TDateTime);
begin
  FIniFile.WriteDateTime(Section, Name, Value);
end;

procedure TQIniFile.WriteFloat(const Section, Name: string; Value: Double);
begin
  FIniFile.WriteFloat(Section, Name, Value);
end;

procedure TQIniFile.WriteInteger(const Section, Ident: string; Value: Integer);
begin
  FIniFile.WriteInteger(Section, Ident, Value);
end;

procedure TQIniFile.WriteString(const Section, Ident, Value: String);
begin
  FIniFile.WriteString(Section, Ident, Value);
end;

procedure TQIniFile.WriteStringW(const Section, Ident: string;
  const Value: QEString);
begin
{$IFDEF QE_UNICODE}
  if Version >= 400 then
    WriteString(Section, Ident, string(Utf8Encode(Value)))
  else
    WriteString(Section, Ident, Value);
{$ELSE}
  WriteString(Section, Ident, Value);
{$ENDIF}
end;

procedure TQIniFile.WriteTime(const Section, Name: string; Value: TDateTime);
begin
  FIniFile.WriteTime(Section, Name, Value);
end;

procedure TQIniFile.WriteVersionSection;
begin
  WriteString('IniVersion', 'Number', IntToStr(Version));
end;

constructor TQIniFile.Create(AStream: TStream);
begin
  inherited Create;
  FIniFile := TMemIniFile.Create(EmptyStr);
  FVersion := 0;
  FStrings := TStringList.Create;
  FStream := AStream;
end;

end.
