소스 검색

* Use collation when comparing strings.

git-svn-id: branches/targetandroid@23402 -
yury 12 년 전
부모
커밋
87f14b072f
1개의 변경된 파일91개의 추가작업 그리고 23개의 파일을 삭제
  1. 91 23
      rtl/android/cwstring.pp

+ 91 - 23
rtl/android/cwstring.pp

@@ -32,13 +32,16 @@ type
   int32_t = longint;
   uint32_t = longword;
   PUConverter = pointer;
+  PUCollator = pointer;
   UBool = LongBool;
 
 var
   hlibICU: TLibHandle;
+  hlibICUi18n: TLibHandle;
   ucnv_open: function (converterName: PAnsiChar; var pErrorCode: UErrorCode): PUConverter; cdecl;
   ucnv_close: procedure (converter: PUConverter); cdecl;
   ucnv_setSubstChars: procedure (converter: PUConverter; subChars: PAnsiChar; len: byte; var pErrorCode: UErrorCode); cdecl;
+  ucnv_setFallback: procedure (cnv: PUConverter; usesFallback: UBool); cdecl;
   ucnv_fromUChars: function (cnv: PUConverter; dest: PAnsiChar; destCapacity: int32_t; src: PUnicodeChar; srcLength: int32_t; var pErrorCode: UErrorCode): int32_t; cdecl;
   ucnv_toUChars: function (cnv: PUConverter; dest: PUnicodeChar; destCapacity: int32_t; src: PAnsiChar; srcLength: int32_t; var pErrorCode: UErrorCode): int32_t; cdecl;
   u_strToUpper: function (dest: PUnicodeChar; destCapacity: int32_t; src: PUnicodeChar; srcLength: int32_t; locale: PAnsiChar; var pErrorCode: UErrorCode): int32_t; cdecl;
@@ -46,13 +49,31 @@ var
   u_strCompare: function (s1: PUnicodeChar; length1: int32_t; s2: PUnicodeChar; length2: int32_t; codePointOrder: UBool): int32_t; cdecl;
   u_strCaseCompare: function (s1: PUnicodeChar; length1: int32_t; s2: PUnicodeChar; length2: int32_t; options: uint32_t; var pErrorCode: UErrorCode): int32_t; cdecl;
 
+  ucol_open: function(loc: PAnsiChar; var status: UErrorCode): PUCollator; cdecl;
+  ucol_close: procedure (coll: PUCollator); cdecl;
+  ucol_strcoll: function (coll: PUCollator; source: PUnicodeChar; sourceLength: int32_t; target: PUnicodeChar; targetLength: int32_t): int32_t; cdecl;
+	ucol_setStrength: procedure (coll: PUCollator; strength: int32_t); cdecl;
+  u_errorName: function (code: UErrorCode): PAnsiChar; cdecl;
+
   DefConv, LastConv: PUConverter;
   LastCP: TSystemCodePage;
+  DefColl: PUCollator;
+
+function OpenConverter(const name: ansistring): PUConverter;
+var
+  err: UErrorCode;
+begin
+  err:=0;
+  Result:=ucnv_open(PAnsiChar(name), err);
+  if DefConv <> nil then begin
+    ucnv_setSubstChars(Result, '?', 1, err);
+    ucnv_setFallback(Result, True);
+  end;
+end;
 
 function GetConverter(cp: TSystemCodePage): PUConverter;
 var
   s: ansistring;
-  err: UErrorCode;
 begin
   if hlibICU = 0 then begin
     Result:=nil;
@@ -63,10 +84,7 @@ begin
   else begin
     if cp <> LastCP then begin
       Str(cp, s);
-      err:=0;
-      LastConv:=ucnv_open(PAnsiChar('cp' + s), err);
-      if LastConv <> nil then
-        ucnv_setSubstChars(LastConv, '?', 1, err);
+      LastConv:=OpenConverter('cp' + s);
       LastCP:=cp;
     end;
     Result:=LastConv;
@@ -201,7 +219,10 @@ begin
     Result:=_CompareStr(s1, s2);
     exit;
   end;
-  Result:=u_strCompare(PUnicodeChar(s1), Length(s1), PUnicodeChar(s2), Length(s2), True);
+  if DefColl <> nil then
+    Result:=ucol_strcoll(DefColl, PUnicodeChar(s1), Length(s1), PUnicodeChar(s2), Length(s2))
+  else
+    Result:=u_strCompare(PUnicodeChar(s1), Length(s1), PUnicodeChar(s2), Length(s2), True);
 end;
 
 function CompareTextUnicodeString(const s1, s2 : UnicodeString): PtrInt;
@@ -283,6 +304,30 @@ begin
   Result:=Str;
 end;
 
+function CodePointLength(const Str: PChar; MaxLookAead: PtrInt): Ptrint;
+var
+  c: byte;
+begin
+  // Only UTF-8 encoding is supported
+  c:=byte(Str^);
+  if c =  0 then
+    Result:=0
+  else begin
+    Result:=1;
+    if c < $80 then
+      exit; // 1-byte ASCII char
+    while c and $C0 = $C0 do begin
+      Inc(Result);
+      c:=c shl 1;
+    end;
+    if Result > 6 then
+      Result:=1 // Invalid code point
+    else
+      if Result > MaxLookAead then
+        Result:=-1; // Incomplete code point
+  end;
+end;
+
 function GetStandardCodePage(const stdcp: TStandardCodePageEnum): TSystemCodePage;
 begin
   Result := CP_UTF8; // Android always uses UTF-8
@@ -358,47 +403,58 @@ begin
       StrLICompAnsiStringProc:=@AnsiStrLIComp;
       StrLowerAnsiStringProc:=@AnsiStrLower;
       StrUpperAnsiStringProc:=@AnsiStrUpper;
-      { Unicode }
+
       Unicode2AnsiMoveProc:=@Unicode2AnsiMove;
       Ansi2UnicodeMoveProc:=@Ansi2UnicodeMove;
       UpperUnicodeStringProc:=@UpperUnicodeString;
       LowerUnicodeStringProc:=@LowerUnicodeString;
       CompareUnicodeStringProc:=@CompareUnicodeString;
       CompareTextUnicodeStringProc:=@CompareTextUnicodeString;
-      { CodePage }
+
       GetStandardCodePageProc:=@GetStandardCodePage;
+      CodePointLengthProc:=@CodePointLength;
     end;
   SetUnicodeStringManager(CWideStringManager);
 end;
 
 procedure UnloadICU;
 begin
-  if hlibICU = 0 then
-    exit;
-  if DefConv <> nil then
-    ucnv_close(DefConv);
-  if LastConv <> nil then
-    ucnv_close(LastConv);
-  UnloadLibrary(hlibICU);
-  hlibICU:=0;
+  if hlibICUi18n <> 0 then begin
+    if DefColl <> nil then
+      ucol_close(DefColl);
+    UnloadLibrary(hlibICUi18n);
+    hlibICUi18n:=0;
+  end;
+  if hlibICU <> 0 then begin
+    if DefConv <> nil then
+      ucnv_close(DefConv);
+    if LastConv <> nil then
+      ucnv_close(LastConv);
+    UnloadLibrary(hlibICU);
+    hlibICU:=0;
+  end;
 end;
 
 procedure LoadICU;
 var
   LibVer: ansistring;
 
-  function _GetProc(const Name: AnsiString; out ProcPtr): boolean;
+  function _GetProc(const Name: AnsiString; out ProcPtr; hLib: TLibHandle = 0): boolean;
   var
     p: pointer;
   begin
-    p:=GetProcedureAddress(hlibICU, Name + LibVer);
+    if hLib = 0 then
+      hLib:=hlibICU;
+    p:=GetProcedureAddress(hlib, Name + LibVer);
     if p = nil then begin
       // unload lib on failure
       UnloadICU;
       Result:=False;
     end
-    else
+    else begin
       pointer(ProcPtr):=p;
+      Result:=True;
+    end;
   end;
 
 const
@@ -411,8 +467,11 @@ var
   s: ansistring;
 begin
   hlibICU:=LoadLibrary('libicuuc.so');
-  if hlibICU = 0 then
+  hlibICUi18n:=LoadLibrary('libicui18n.so');
+  if (hlibICU = 0) or (hlibICUi18n = 0) then begin
+    UnloadICU;
     exit;
+  end;
   // Finding ICU version using known versions table
   for i:=High(ICUver) downto Low(ICUver) do begin
     s:='_' + ICUver[i];
@@ -447,6 +506,7 @@ begin
   if not _GetProc('ucnv_open', ucnv_open) then exit;
   if not _GetProc('ucnv_close', ucnv_close) then exit;
   if not _GetProc('ucnv_setSubstChars', ucnv_setSubstChars) then exit;
+  if not _GetProc('ucnv_setFallback', ucnv_setFallback) then exit;
   if not _GetProc('ucnv_fromUChars', ucnv_fromUChars) then exit;
   if not _GetProc('ucnv_toUChars', ucnv_toUChars) then exit;
   if not _GetProc('u_strToUpper', u_strToUpper) then exit;
@@ -454,10 +514,18 @@ begin
   if not _GetProc('u_strCompare', u_strCompare) then exit;
   if not _GetProc('u_strCaseCompare', u_strCaseCompare) then exit;
 
+  if not _GetProc('u_errorName', u_errorName) then exit;
+
+  if not _GetProc('ucol_open', ucol_open, hlibICUi18n) then exit;
+  if not _GetProc('ucol_close', ucol_close, hlibICUi18n) then exit;
+  if not _GetProc('ucol_strcoll', ucol_strcoll, hlibICUi18n) then exit;
+  if not _GetProc('ucol_setStrength', ucol_setStrength, hlibICUi18n) then exit;
+
+  DefConv:=OpenConverter('utf8');
   err:=0;
-  DefConv:=ucnv_open('utf8', err);
-  if DefConv <> nil then
-    ucnv_setSubstChars(DefConv, '?', 1, err);
+  DefColl:=ucol_open(nil, err);
+  if DefColl <> nil then
+    ucol_setStrength(DefColl, 2);
 end;
 
 initialization