{%MainUnit ../lconvencoding.pp}

{******************************************************************************
                               Asian Unicode Functions
 ******************************************************************************

 *****************************************************************************
 *                                                                           *
 *  This file is part of the Lazarus Component Library (LCL)                 *
 *                                                                           *
 *  See the file COPYING.modifiedLGPL.txt, included in this distribution,    *
 *  for details about the copyright.                                         *
 *                                                                           *
 *  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.                     *
 *                                                                           *
 *****************************************************************************

  The clipboard is able to work with the windows and gtk behaviour/features.
}

function SingleByteToUTF8Ex(const s: string; CodeP: integer): string;
var
  len:  integer;
  i, j:    integer;
  Src:  PChar;
  Dest: PChar;
  c:    char;
  tempstr: ansistring;
  tempint: integer;
begin
  SetLength(tempstr, 4);
  if s = '' then
  begin
    Result := s;
    exit;
  end;
  len := length(s);
  SetLength(Result, len * 6);// Asia UTF-8 is at most 6 bytes
  Src  := PChar(s);
  Dest := PChar(Result);
  i    := 1;
  while i < len do
  begin
    c := Src^;
    Inc(Src);
    i := i + 1;
    if Ord(c) < 128 then
    begin
      Dest^ := c;
      Inc(Dest);
    end
    else
    begin
      tempint := Byte(c) shl 8;
      if i <= len then
      begin
        tempint := tempint + Byte(Src^);
        i := i + 1;
      end;

      Inc(Src);

      case CodeP of
        936:
          tempint := Uni936C[SearchTable(CP936CC, tempint)];
        950:
          tempint := Uni950C[SearchTable(CP950CC, tempint)];
        949:
          tempint := Uni949C[SearchTable(CP949CC, tempint)];
        932:
          tempint := Uni932C[SearchTable(CP932CC, tempint)];
        else
          tempint := -1;
      end;

      if tempint <> -1 then
      begin
        TempStr := UnicodeToUTF8(tempint);

        for j := 1 to Length(TempStr) do
        begin
          Dest^ := TempStr[j];
          Inc(Dest);
        end;
      end;
    end;
  end;
  SetLength(Result, PtrUInt(Dest) - PtrUInt(Result));
end;

function CP936ToUTF8(const s: string): string;
begin
  Result := SingleByteToUTF8Ex(s, 936);
end;

function CP950ToUTF8(const s: string): string;
begin
  Result := SingleByteToUTF8Ex(s, 950);
end;

function CP949ToUTF8(const s: string): string;
begin
  Result := SingleByteToUTF8Ex(s, 949);
end;

function CP932ToUTF8(const s: string): string;
begin
  Result := SingleByteToUTF8Ex(s, 932);
end;

function UnicodeToCP936(Unicode: cardinal): integer;
begin
  case Unicode of
    0..127: Result := Unicode;
    else
      Result := CP936CU[SearchTable(Uni936U, Unicode)];
  end;
end;

function UnicodeToCP950(Unicode: cardinal): integer;
begin
  case Unicode of
    0..127: Result := Unicode;
    else
      Result := CP950CU[SearchTable(Uni950U, Unicode)];
  end;
end;

function UnicodeToCP949(Unicode: cardinal): integer;
begin
  case Unicode of
    0..127: Result := Unicode;
    else
      Result := CP949CU[SearchTable(Uni949U, Unicode)];
  end;
end;

function UnicodeToCP932(Unicode: cardinal): integer;
begin
  case Unicode of
    0..127: Result := Unicode;
    else
      Result := CP932CU[SearchTable(Uni932U, Unicode)];
  end;
end;

function UTF8ToSingleByteEx(const s: string;
  const UTF8CharConvFunc: TUnicodeToCharID): string;
var
  len:  integer;
  Src:  PChar;
  Dest: PChar;
  c:    char;
  Unicode: longword;
  CharLen: integer;
  i:    integer;
begin
  if s = '' then
  begin
    Result := '';
    exit;
  end;
  len := length(s);
  SetLength(Result, len);
  Src  := PChar(s);
  Dest := PChar(Result);
  while len > 0 do
  begin
    c := Src^;
    if c < #128 then
    begin
      Dest^ := c;
      Inc(Dest);
      Inc(Src);
      Dec(len);
    end
    else
    begin
      Unicode := UTF8CharacterToUnicode(Src, CharLen);
      Inc(Src, CharLen);
      Dec(len, CharLen);
      i := UTF8CharConvFunc(Unicode);
      //writeln(Format('%X', [i]));
      if i >= 0 then
      begin
        if i > $ff then
        begin
          Dest^ := chr(i shr 8);
          Inc(Dest);
          Dest^ := chr(i);
        end
        else
          Dest^ := chr(i);
        Inc(Dest);
      end;
    end;
  end;
  //SetLength(Result, Dest - PChar(Result));
  SetLength(Result, PtrUInt(Dest) - PtrUInt(Result));
end;

function UTF8ToCP936(const s: string): string;
begin
  Result := UTF8ToSingleByteEx(s, @UnicodeToCP936);
end;

function UTF8ToCP950(const s: string): string;
begin
  Result := UTF8ToSingleByteEx(s, @UnicodeToCP950);
end;

function UTF8ToCP949(const s: string): string;
begin
  Result := UTF8ToSingleByteEx(s, @UnicodeToCP949);
end;

function UTF8ToCP932(const s: string): string;
begin
  Result := UTF8ToSingleByteEx(s, @UnicodeToCP932);
end;

