unit osencoding;

{$mode delphi}

interface

uses
  Classes,
  SysUtils,
  lconvencoding;

procedure initEncoding;
function reencode(const sourceText: string; const sourceEncoding: string): string;
  overload;
function reencode(const sourceText: string; const sourceEncoding: string;
  var usedSourceEncoding: string): string; overload;
function searchencoding(const searchText: string): string;


var
  supportedEncodings: TStringList;
  mysystemEncoding: string;

implementation

uses
  oslog;

var
  i, k: integer;
  additionalEncoding: string;

function isStringInList(const str: string; const list: TStringList): boolean;
  // list.IndexOf(str) > -1 does not work as expected: ucs2be is found if str is 'u c s 2 b e'
var
  i: integer;
begin
  Result := False;
  i := 0;
  repeat
    if list.Strings[i] = str then
    begin
      Result := True;
    end;
    Inc(i);
  until (Result = True) or (i >= list.Count);
end;

function searchencoding(const searchText: string): string;
  // tries to find entry: encoding=<encoding to use>
var
  mylist, myencodings: TStringList;
  i: integer;
  mytext: string;
  found: boolean;
  foundencodingstring, newencodingstring: string;
begin
  Result := '';
  found := False;
  mylist := TStringList.Create;
  myencodings := TStringList.Create;
  mylist.Text := searchText;
  GetSupportedEncodings(myencodings);
  if mylist.IndexOfName('encoding') <> -1 then
  begin
    // we found an entry: encoding=<encoding to use>
    foundencodingstring := mylist.Values['encoding'];
    logdatei.DependentAdd('foundencodingstring: ' + foundencodingstring, LLDebug2);
    if isStringInList(foundencodingstring, supportedEncodings) then
      Result := foundencodingstring
    else
    begin
      i := 0;
      repeat
        // convert via utf8
        newencodingstring := ConvertEncoding(foundencodingstring,
          myencodings.Strings[i], 'utf8');
        newencodingstring := ConvertEncoding(newencodingstring, 'utf8',
          mysystemEncoding);
        logdatei.DependentAdd('myencodings.Strings[i]: ' + myencodings.Strings[i] +
          'newencodingstring: ' + newencodingstring, LLDebug3);
        if isStringInList(newencodingstring, supportedEncodings) then
        begin
          // newencodingstring is a supported encoding
          Result := newencodingstring;
          found := True;
        end;
        Inc(i);
      until (found = True) or (i >= myencodings.Count);
    end;
    //logdatei.DependentAdd('searchText: '+searchText+', foundencodingstring: '+foundencodingstring+', mysystemEncoding: '+mysystemEncoding,LLEssential);
    //result := foundencodingstring;
  end
  else
  begin
    // it seems that we normally do not reach this branch
    //
    // we found no encoding entry
    // we have now 2 possibilities:
    // a) there is no encoding entry
    // b) there is one but we do not find it because of the wrong encoding
    i := 0;
    repeat
      begin
        mytext := ConvertEncoding(searchText, myencodings.Strings[i], mysystemEncoding);
        logdatei.DependentAdd('mytext: ' + mytext + ', myencodings.Strings[i]: ' +
          myencodings.Strings[i] + ', mysystemEncoding: ' + mysystemEncoding, LLDebug3);
        mylist.Text := mytext;
        if mylist.IndexOfName('encoding') <> -1 then
        begin
          // we found an entry: encoding=<encoding to use>
          Result := mylist.Values['encoding'];
          found := True;
        end;
        Inc(i);
      end;
    until (found = True) or (i >= myencodings.Count);
  end;
  myencodings.Free;
  mylist.Free;
end;

function reencode(const sourceText: string; const sourceEncoding: string): string;
var
  str: string;
begin
  Result := reencode(sourceText, sourceEncoding, str);
end;

function reencode(const sourceText: string; const sourceEncoding: string;
  var usedSourceEncoding: string): string;
var
  str: string;
  mylist: TStringList;
  i: integer;
begin
  //for i:= 0 to supportedEncodings.Count-1 do writeln(supportedEncodings.Strings[i]);
  Result := sourceText;
  usedSourceEncoding := sourceEncoding;
  if LowerCase(sourceEncoding) = 'system' then
    usedSourceEncoding := mysystemEncoding;
  // which means normally: do nothing
  if LowerCase(sourceEncoding) = 'auto' then
    usedSourceEncoding := guessEncoding(sourceText);
  if supportedEncodings.IndexOf(usedSourceEncoding) = -1 then
    logdatei.DependentAdd('Found or given Encoding: ' + usedSourceEncoding +
      ' is not supported.', LLWarning);
  if LowerCase(usedSourceEncoding) <> LowerCase(mysystemEncoding) then
  begin
    if (usedSourceEncoding = 'utf8') or (usedSourceEncoding = 'UTF-8') or
      (mysystemEncoding = 'utf8') or (mysystemEncoding = 'UTF-8') then
    begin
      Result := ConvertEncoding(sourceText, usedSourceEncoding, mysystemEncoding);
    end
    else
    begin
      if (usedSourceEncoding = 'ucs2be') or (usedSourceEncoding = 'UCS-2BE')
        or (usedSourceEncoding = 'ucs2le') or (usedSourceEncoding = 'UCS-2LE')then
      begin
        mylist := TStringList.Create;
        mylist.Text := sourceText;
        for i := 0 to mylist.Count - 1 do
        begin
          str := ConvertEncoding(mylist.Strings[i], usedSourceEncoding, 'utf8');
          mylist.Strings[i] := ConvertEncoding(str, 'utf8', mysystemEncoding);
        end;
        result := mylist.Text;
        mylist.Free;
      end
      else
      begin
        str := ConvertEncoding(sourceText, usedSourceEncoding, 'utf8');
        Result := ConvertEncoding(str, 'utf8', mysystemEncoding);
      end;
    end;
    logdatei.DependentAdd('Reencoding from ' + usedSourceEncoding +
      ' to ' + mysystemEncoding, LLDebug2);
    //mylist := TStringList.Create;
    //mylist.Text := Result;
    //for i := 0 to mylist.Count - 1 do
    //  logdatei.DependentAdd('Reencoded: ' + mylist.Strings[i], LLWarning);
    //mylist.Free;
  end;
end;

procedure initEncoding;
begin
  {$IFDEF LINUX}
  mysystemEncoding := 'utf8';
  {$ENDIF LINUX}
  {$IFDEF WINDOWS}
  //mysystemEncoding := 'utf8';
  mysystemEncoding := GetDefaultTextEncoding;
  {$ENDIF WINDOWS}
  // get the supported encodings
  supportedEncodings := TStringList.Create;
  GetSupportedEncodings(supportedEncodings);
  // add the aliases (utf8 is alias for UTF-8)
  k := supportedEncodings.Count;
  for i := 0 to k - 1 do
  begin
    additionalEncoding := LowerCase(supportedEncodings.Strings[i]);
    if pos('-', additionalEncoding) > 0 then
      additionalEncoding := copy(additionalEncoding, 0, pos('-', additionalEncoding) -
        1) + copy(additionalEncoding, pos('-', additionalEncoding) + 1,
        length(additionalEncoding));
    supportedEncodings.Add(additionalEncoding);
  end;
  //for i:= 0 to supportedEncodings.Count-1 do writeln(supportedEncodings.Strings[i]);
end;

end.
