mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-31 21:09:38 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			780 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			780 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
|     This file is part of the Free Pascal run time library.
 | |
|     Copyright (c) 2000 by Florian Klaempfl
 | |
|     member of the Free Pascal development team.
 | |
| 
 | |
|     This unit implements several classes for charset conversions
 | |
| 
 | |
|     See the file COPYING.FPC, 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.
 | |
| 
 | |
|  **********************************************************************}
 | |
| {$mode objfpc}
 | |
| {$pointermath on}
 | |
| {$PACKENUM 1}
 | |
| {$IFNDEF FPC_DOTTEDUNITS}
 | |
| unit charset;
 | |
| {$ENDIF FPC_DOTTEDUNITS}
 | |
| 
 | |
|   interface
 | |
| 
 | |
|     type
 | |
|        tunicodechar = word;
 | |
|        tunicodestring = ^tunicodechar;
 | |
| 
 | |
|        tunicodecharmappingflag = (umf_noinfo,umf_leadbyte,umf_undefined,
 | |
|          umf_unused);
 | |
| 
 | |
|        punicodecharmapping = ^tunicodecharmapping;
 | |
|        tunicodecharmapping = packed record
 | |
|           unicode : tunicodechar;
 | |
|           flag : tunicodecharmappingflag;
 | |
|           reserved : byte;
 | |
|        end;
 | |
| 
 | |
|        preversecharmapping = ^treversecharmapping;
 | |
|        treversecharmapping = packed record
 | |
|           unicode : tunicodechar;
 | |
|           char1   : Byte;
 | |
|           char2   : Byte;
 | |
|        end;
 | |
| 
 | |
|        punicodemap = ^tunicodemap;
 | |
|        tunicodemap = record
 | |
|           cpname : string[20];
 | |
|           cp : word;
 | |
|           map : punicodecharmapping;
 | |
|           lastchar : longint;
 | |
|           reversemap : preversecharmapping;
 | |
|           reversemaplength : longint;
 | |
|           next : punicodemap;
 | |
|           internalmap : boolean;
 | |
|        end;
 | |
| 
 | |
|        TSerializedMapHeader = packed record
 | |
|           cpName           : string[20];
 | |
|           cp               : UInt16;
 | |
|           mapLength        : UInt32;
 | |
|           lastChar         : Int32;
 | |
|           reverseMapLength : UInt32;
 | |
|        end;
 | |
| 
 | |
|     const
 | |
|       BINARY_MAPPING_FILE_EXT = '.bcm';
 | |
| 
 | |
|     function loadunicodemapping(const cpname,f : string; cp :word) : punicodemap;
 | |
|     function loadbinaryunicodemapping(const directory,cpname : string) : punicodemap;overload;
 | |
|     function loadbinaryunicodemapping(const filename : string) : punicodemap;overload;
 | |
|     function loadbinaryunicodemapping(
 | |
|       const AData       : Pointer;
 | |
|       const ADataLength : Integer
 | |
|     ) : punicodemap;overload;
 | |
|     procedure registermapping(p : punicodemap);
 | |
|     function registerbinarymapping(const directory,cpname : string):Boolean;
 | |
|     function getmap(const s : string) : punicodemap;
 | |
|     function getmap(cp : word) : punicodemap;
 | |
|     function mappingavailable(const s : string) : boolean;inline;
 | |
|     function mappingavailable(cp :word) : boolean;inline;
 | |
|     function getunicode(c : AnsiChar;p : punicodemap) : tunicodechar;inline;
 | |
|     function getunicode(
 | |
|       AAnsiStr : pansichar;
 | |
|       AAnsiLen : LongInt;
 | |
|       AMap     : punicodemap;
 | |
|       ADest    : tunicodestring
 | |
|     ) : LongInt;
 | |
|     function getascii(c : tunicodechar;p : punicodemap) : string;
 | |
|     function getascii(c : tunicodechar;p : punicodemap; ABuffer : PAnsiChar; ABufferLen : LongInt) : LongInt;
 | |
| 
 | |
|   implementation
 | |
| 
 | |
|     const
 | |
|       UNKNOW_CHAR_A = ansichar(63);
 | |
|       UNKNOW_CHAR_W = tunicodechar(63);
 | |
|     var
 | |
|        mappings : punicodemap;
 | |
| 
 | |
| 
 | |
|     procedure QuickSort(AList: preversecharmapping; L, R : Longint);
 | |
|     var
 | |
|       I, J : Longint;
 | |
|       P, Q : treversecharmapping;
 | |
|     begin
 | |
|       repeat
 | |
|         I:=L;
 | |
|         J:=R;
 | |
|         P:=AList[(L + R) div 2];
 | |
|         repeat
 | |
|           while (P.unicode-AList[I].unicode) > 0 do
 | |
|             I:=I+1;
 | |
|           while (P.unicode-AList[J].unicode) < 0 do
 | |
|             J:=J-1;
 | |
|           if I<=J then
 | |
|             begin
 | |
|               Q:=AList[I];
 | |
|               AList[I]:=AList[J];
 | |
|               AList[J]:=Q;
 | |
|               I:=I+1;
 | |
|               J:=J-1;
 | |
|             end;
 | |
|         until I > J;
 | |
|         if J-L < R-I then
 | |
|           begin
 | |
|             if L<J then
 | |
|               QuickSort(AList, L, J);
 | |
|             L:=I;
 | |
|           end
 | |
|         else
 | |
|           begin
 | |
|             if I < R then
 | |
|               QuickSort(AList, I, R);
 | |
|             R:=J;
 | |
|           end;
 | |
|       until L>=R;
 | |
|     end;
 | |
| 
 | |
|     function find(
 | |
|       const c     : tunicodechar;
 | |
|       const AData : preversecharmapping;
 | |
|       const ALen  : LongInt
 | |
|     ) : preversecharmapping;overload;
 | |
|     var
 | |
|        l, h, m : longint;
 | |
|        r:preversecharmapping;
 | |
|     begin
 | |
|       if ALen=0 then
 | |
|         exit(nil);
 | |
|       r:=AData;
 | |
|       l:=0;
 | |
|       h:=ALen-1;
 | |
|       while l<h do begin
 | |
|         m:=(l+h) div 2;
 | |
|         if r[m].unicode<c then
 | |
|           l:=m+1
 | |
|         else
 | |
|           h:=m;
 | |
|       end;
 | |
|       if (l=h) and (r[l].unicode=c) then
 | |
|         Result:=@r[l]
 | |
|       else
 | |
|         Result:=nil;
 | |
|     end;
 | |
| 
 | |
|     function find(
 | |
|       const c : tunicodechar;
 | |
|       const p : punicodemap
 | |
|     ) : preversecharmapping;overload;inline;
 | |
|     begin
 | |
|       Result:=find(c,p^.reversemap,p^.reversemaplength);
 | |
|     end;
 | |
| 
 | |
|     function RemoveDuplicates(
 | |
|       const AData      : preversecharmapping;
 | |
|       const ALen       : LongInt;
 | |
|       out   AResultLen : LongInt
 | |
|     ) : preversecharmapping;
 | |
|     var
 | |
|       r0, r, p, t : preversecharmapping;
 | |
|       i, c, actualCount : LongInt;
 | |
|     begin
 | |
|       c:=ALen;
 | |
|       GetMem(r0,c*SizeOf(treversecharmapping));
 | |
|       r:=r0;
 | |
|       p:=AData;
 | |
|       actualCount:=0;
 | |
|       i:=0;
 | |
|       while i<c do
 | |
|         begin
 | |
|           t:=find(p^.unicode,r0,actualCount);
 | |
|           if t=nil then
 | |
|             begin
 | |
|               r^:=p^;
 | |
|               actualCount:=actualCount+1;
 | |
|               Inc(r);
 | |
|             end
 | |
|           else
 | |
|             begin
 | |
|               if (p^.char1<t^.char1) or
 | |
|                  ((p^.char1=t^.char1) and (p^.char2<t^.char2))
 | |
|               then
 | |
|                 t^:=p^;//keep the first mapping
 | |
|             end;
 | |
|           i:=i+1;
 | |
|           Inc(p);
 | |
|         end;
 | |
|       if c<>actualCount then
 | |
|         ReAllocMem(r0,actualCount*SizeOf(treversecharmapping));
 | |
|       AResultLen:=actualCount;
 | |
|       Result:=r0;
 | |
|     end;
 | |
| 
 | |
|     function buildreversemap(
 | |
|       const AMapping   : punicodecharmapping;
 | |
|       const ALen       : LongInt;
 | |
|       out   AResultLen : LongInt
 | |
|     ) : preversecharmapping;
 | |
|     var
 | |
|       r0, r, t : preversecharmapping;
 | |
|       i, c, actualCount, ti : LongInt;
 | |
|       p : punicodecharmapping;
 | |
|     begin
 | |
|       if (ALen<1) then
 | |
|         exit(nil);
 | |
|       p:=AMapping;
 | |
|       c:=ALen;
 | |
|       GetMem(r0,c*SizeOf(treversecharmapping));
 | |
|       r:=r0;
 | |
|       actualCount:=0;
 | |
|       i:=0;
 | |
|       while i<c do
 | |
|         begin
 | |
|           if (p^.flag=umf_noinfo) then
 | |
|             begin
 | |
|               r^.unicode:=p^.unicode;
 | |
|               if i<=High(Byte) then
 | |
|                 begin
 | |
|                   r^.char1:=i;
 | |
|                   r^.char2:=0;
 | |
|                 end
 | |
|               else
 | |
|                 begin
 | |
|                   r^.char1:=i div 256;
 | |
|                   r^.char2:=i mod 256;
 | |
|                 end;
 | |
|               actualCount:=actualCount+1;
 | |
|               Inc(r);
 | |
|             end;
 | |
|           Inc(p);
 | |
|           i:=i+1;
 | |
|         end;
 | |
|       if c<>actualCount then
 | |
|         ReAllocMem(r0,actualCount*SizeOf(treversecharmapping));
 | |
|       if actualCount>1 then
 | |
|         begin
 | |
|           QuickSort(r0,0,(actualCount-1));
 | |
|           t:=RemoveDuplicates(r0,actualCount,ti);
 | |
|           FreeMem(r0,actualCount*SizeOf(treversecharmapping));
 | |
|           r0:=t;
 | |
|           actualCount:=ti;
 | |
|         end;
 | |
|       AResultLen:=actualCount;
 | |
|       Result:=r0;
 | |
|     end;
 | |
| 
 | |
|     procedure inititems(const p : punicodecharmapping; const ALen : LongInt);
 | |
|     const
 | |
|       INIT_ITEM : tunicodecharmapping = (unicode:0; flag:umf_unused; reserved:0);
 | |
|     var
 | |
|       x : punicodecharmapping;
 | |
|       i : LongInt;
 | |
|     begin
 | |
|       x:=p;
 | |
|       for i:=0 to ALen-1 do
 | |
|         begin
 | |
|           x^:=INIT_ITEM;
 | |
|           Inc(x);
 | |
|         end;
 | |
|     end;
 | |
| 
 | |
|     function loadunicodemapping(const cpname,f : string; cp :word) : punicodemap;
 | |
| 
 | |
|       var
 | |
|          data : punicodecharmapping;
 | |
|          datasize : longint;
 | |
|          t : text;
 | |
|          s,hs : string;
 | |
|          scanpos,charpos,unicodevalue : longint;
 | |
|          code : word;
 | |
|          flag : tunicodecharmappingflag;
 | |
|          p : punicodemap;
 | |
|          lastchar, i : longint;
 | |
| 
 | |
|       begin
 | |
|          lastchar:=-1;
 | |
|          loadunicodemapping:=nil;
 | |
|          datasize:=256;
 | |
|          GetMem(data,sizeof(tunicodecharmapping)*datasize);
 | |
|          inititems(data,datasize);
 | |
|          assign(t,f);
 | |
|          {$I-}
 | |
|          reset(t);
 | |
|          {$I+}
 | |
|          if ioresult<>0 then
 | |
|            begin
 | |
|               freemem(data,sizeof(tunicodecharmapping)*datasize);
 | |
|               exit;
 | |
|            end;
 | |
|          while not(eof(t)) do
 | |
|            begin
 | |
|               readln(t,s);
 | |
|               if (s[1]='0') and (s[2]='x') then
 | |
|                 begin
 | |
|                    flag:=umf_unused;
 | |
|                    scanpos:=3;
 | |
|                    hs:='$';
 | |
|                    while s[scanpos] in ['0'..'9','A'..'F','a'..'f'] do
 | |
|                      begin
 | |
|                         hs:=hs+s[scanpos];
 | |
|                         inc(scanpos);
 | |
|                      end;
 | |
|                    val(hs,charpos,code);
 | |
|                    if code<>0 then
 | |
|                      begin
 | |
|                         freemem(data,sizeof(tunicodecharmapping)*datasize);
 | |
|                         close(t);
 | |
|                         exit;
 | |
|                      end;
 | |
|                    while not(s[scanpos] in ['0','#']) do
 | |
|                      inc(scanpos);
 | |
|                    if s[scanpos]='#' then
 | |
|                      begin
 | |
|                         { special char }
 | |
|                         unicodevalue:=$ffff;
 | |
|                         hs:=copy(s,scanpos,length(s)-scanpos+1);
 | |
|                         if hs='#DBCS LEAD BYTE' then
 | |
|                           flag:=umf_leadbyte;
 | |
|                      end
 | |
|                    else
 | |
|                      begin
 | |
|                         { C hex prefix }
 | |
|                         inc(scanpos,2);
 | |
|                         hs:='$';
 | |
|                         while s[scanpos] in ['0'..'9','A'..'F','a'..'f'] do
 | |
|                           begin
 | |
|                              hs:=hs+s[scanpos];
 | |
|                              inc(scanpos);
 | |
|                           end;
 | |
|                         val(hs,unicodevalue,code);
 | |
|                         if code<>0 then
 | |
|                           begin
 | |
|                              freemem(data,sizeof(tunicodecharmapping)*datasize);
 | |
|                              close(t);
 | |
|                              exit;
 | |
|                           end;
 | |
|                         if charpos>datasize then
 | |
|                           begin
 | |
|                              { allocate 1024 bytes more because         }
 | |
|                              { if we need more than 256 entries it's    }
 | |
|                              { probably a mbcs with a lot of            }
 | |
|                              { entries                                  }
 | |
|                              i:=datasize;
 | |
|                              datasize:=charpos+8*1024;
 | |
|                              reallocmem(data,sizeof(tunicodecharmapping)*datasize);
 | |
|                              inititems(@data[i],(datasize-i));
 | |
|                           end;
 | |
|                         flag:=umf_noinfo;
 | |
|                      end;
 | |
|                    data[charpos].flag:=flag;
 | |
|                    data[charpos].unicode:=unicodevalue;
 | |
|                    if charpos>lastchar then
 | |
|                      lastchar:=charpos;
 | |
|                 end;
 | |
|            end;
 | |
|          close(t);
 | |
|          new(p);
 | |
|          p^.lastchar:=lastchar;
 | |
|          p^.cpname:=cpname;
 | |
|          p^.cp:=cp;
 | |
|          p^.internalmap:=false;
 | |
|          p^.next:=nil;
 | |
|          p^.map:=data;
 | |
|          p^.reversemap:=buildreversemap(p^.map,(p^.lastchar+1),p^.reversemaplength);
 | |
|          loadunicodemapping:=p;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function loadbinaryunicodemapping(const directory, cpname : string) : punicodemap;
 | |
|       const
 | |
|         {$IFDEF ENDIAN_LITTLE}
 | |
|           ENDIAN_SUFFIX = 'le';
 | |
|         {$ENDIF ENDIAN_LITTLE}
 | |
|         {$IFDEF ENDIAN_BIG}
 | |
|           ENDIAN_SUFFIX = 'be';
 | |
|         {$ENDIF ENDIAN_BIG}
 | |
|       var
 | |
|         fileName : string;
 | |
|       begin
 | |
|         fileName := directory;
 | |
|         if (fileName <> '') then begin
 | |
|           if (fileName[Length(fileName)] <> DirectorySeparator) then
 | |
|             fileName := fileName + DirectorySeparator;
 | |
|         end;
 | |
|         fileName := fileName + cpname + '_' + ENDIAN_SUFFIX + BINARY_MAPPING_FILE_EXT;
 | |
|         Result := loadbinaryunicodemapping(fileName);
 | |
|       end;
 | |
| 
 | |
|     {$PUSH}
 | |
|       {$I-}
 | |
|     function loadbinaryunicodemapping(const filename : string) : punicodemap;
 | |
|       const
 | |
|         BLOCK_SIZE = 16*1024;
 | |
|       var
 | |
|         f : File of Byte;
 | |
|         locSize, locReaded, c : LongInt;
 | |
|         locBuffer : PByte;
 | |
|         locBlockSize : LongInt;
 | |
|       begin
 | |
|         Result := nil;
 | |
|         if (filename='') then
 | |
|           exit;
 | |
|         Assign(f,filename);
 | |
|         Reset(f);
 | |
|         if (IOResult<>0) then
 | |
|           exit;
 | |
|         locSize:=FileSize(f);
 | |
|         if (locSize<SizeOf(TSerializedMapHeader)) then
 | |
|           begin
 | |
|             Close(f);
 | |
|             exit;
 | |
|           end;
 | |
|         locBuffer:=GetMem(locSize);
 | |
|         locBlockSize:=BLOCK_SIZE;
 | |
|         locReaded:=0;
 | |
|         c := 0;
 | |
|         while (locReaded<locSize) do
 | |
|           begin
 | |
|             if (locBlockSize>(locSize-locReaded)) then
 | |
|               locBlockSize:=locSize-locReaded;
 | |
|             BlockRead(f,locBuffer[locReaded],locBlockSize,c);
 | |
|             if (IOResult<>0) or (c<=0) then
 | |
|               begin
 | |
|                 FreeMem(locBuffer,locSize);
 | |
|                 Close(f);
 | |
|                 exit;
 | |
|               end;
 | |
|             locReaded:=locReaded+c;
 | |
|           end;
 | |
|         Result:=loadbinaryunicodemapping(locBuffer,locSize);
 | |
|         FreeMem(locBuffer,locSize);
 | |
|         Close(f);
 | |
|       end;
 | |
|     {$POP}
 | |
| 
 | |
|     procedure freemapping(amapping : punicodemap);
 | |
|       begin
 | |
|         if (amapping = nil) then
 | |
|           exit;
 | |
|         if (amapping^.map <> nil) then
 | |
|           freemem(amapping^.map);
 | |
|         if (amapping^.reversemap <> nil) then
 | |
|           freemem(amapping^.reversemap);
 | |
|         dispose(amapping);
 | |
|       end;
 | |
| 
 | |
|     function loadbinaryunicodemapping(
 | |
|       const AData       : Pointer;
 | |
|       const ADataLength : Integer
 | |
|     ) : punicodemap;
 | |
|       var
 | |
|         dataPointer : PByte;
 | |
|         readedLength : LongInt;
 | |
| 
 | |
|         function ReadBuffer(ADest : Pointer; ALength : LongInt) : Boolean;
 | |
|           begin
 | |
|             Result := (readedLength + ALength) <= ADataLength;
 | |
|             if not result then
 | |
|               exit;
 | |
|             Move(dataPointer^,ADest^,ALength);
 | |
|             Inc(dataPointer,ALength);
 | |
|             readedLength := readedLength + ALength;
 | |
|           end;
 | |
| 
 | |
|       var
 | |
|         h : TSerializedMapHeader;
 | |
|         r : punicodemap;
 | |
|       begin
 | |
|         Result := nil;
 | |
|         readedLength := 0;
 | |
|         dataPointer := AData;
 | |
|         if not ReadBuffer(@h,SizeOf(h)) then
 | |
|           exit;
 | |
|         New(r);
 | |
|         FillChar(r^,SizeOf(tunicodemap),0);
 | |
|         r^.cpname := h.cpName;
 | |
|         r^.cp := h.cp;
 | |
|         r^.map := AllocMem(h.mapLength);
 | |
|         if not ReadBuffer(r^.map,h.mapLength) then
 | |
|           begin
 | |
|             freemapping(r);
 | |
|             exit;
 | |
|           end;
 | |
|         r^.lastchar := h.lastChar;
 | |
|         r^.reversemap := AllocMem(h.reverseMapLength);
 | |
|         if not ReadBuffer(r^.reversemap,h.reverseMapLength) then
 | |
|           begin
 | |
|             freemapping(r);
 | |
|             exit;
 | |
|           end;
 | |
|         r^.reversemaplength := (h.reverseMapLength div SizeOf(treversecharmapping));
 | |
|         Result := r;
 | |
|       end;
 | |
| 
 | |
|     procedure registermapping(p : punicodemap);
 | |
| 
 | |
|       begin
 | |
|          p^.next:=mappings;
 | |
|          mappings:=p;
 | |
|       end;
 | |
| 
 | |
|     {$ifdef FPC_HAS_FEATURE_THREADING}
 | |
|     threadvar
 | |
|     {$else FPC_HAS_FEATURE_THREADING}
 | |
|     var
 | |
|     {$endif FPC_HAS_FEATURE_THREADING}
 | |
|       strmapcache : string;
 | |
|       strmapcachep : punicodemap;
 | |
| 
 | |
|     function registerbinarymapping(const directory, cpname : string) : Boolean;
 | |
|       var
 | |
|         p : punicodemap;
 | |
|       begin
 | |
|         Result := False;
 | |
|         p := loadbinaryunicodemapping(directory,cpname);
 | |
|         if (p = nil) then
 | |
|           exit;
 | |
|         registermapping(p);
 | |
|         Result := True;
 | |
|       end;
 | |
| 
 | |
|     function getmap(const s : string) : punicodemap;
 | |
| 
 | |
|       var
 | |
|          hp : punicodemap;
 | |
| 
 | |
|       begin
 | |
|          if (strmapcache=s) and assigned(strmapcachep) and (strmapcachep^.cpname=s) then
 | |
|            begin
 | |
|               getmap:=strmapcachep;
 | |
|               exit;
 | |
|            end;
 | |
|          hp:=mappings;
 | |
|          while assigned(hp) do
 | |
|            begin
 | |
|               if hp^.cpname=s then
 | |
|                 begin
 | |
|                    getmap:=hp;
 | |
|                    strmapcache:=s;
 | |
|                    strmapcachep:=hp;
 | |
|                    exit;
 | |
|                 end;
 | |
|               hp:=hp^.next;
 | |
|            end;
 | |
|          getmap:=nil;
 | |
|       end;////////
 | |
| 
 | |
| 
 | |
|     {$ifdef FPC_HAS_FEATURE_THREADING}
 | |
|     threadvar
 | |
|     {$else FPC_HAS_FEATURE_THREADING}
 | |
|     var
 | |
|     {$endif FPC_HAS_FEATURE_THREADING}
 | |
|       intmapcache : word;
 | |
|       intmapcachep : punicodemap;
 | |
|     function getmap(cp : word) : punicodemap;
 | |
| 
 | |
|       var
 | |
|          hp : punicodemap;
 | |
| 
 | |
|       begin
 | |
|          if (intmapcache=cp) and assigned(intmapcachep) and (intmapcachep^.cp=cp) then
 | |
|            begin
 | |
|               getmap:=intmapcachep;
 | |
|               exit;
 | |
|            end;
 | |
|          hp:=mappings;
 | |
|          while assigned(hp) do
 | |
|            begin
 | |
|               if hp^.cp=cp then
 | |
|                 begin
 | |
|                    getmap:=hp;
 | |
|                    intmapcache:=cp;
 | |
|                    intmapcachep:=hp;
 | |
|                    exit;
 | |
|                 end;
 | |
|               hp:=hp^.next;
 | |
|            end;
 | |
|          getmap:=nil;
 | |
|       end;
 | |
| 
 | |
|     function mappingavailable(const s : string) : boolean;
 | |
| 
 | |
|       begin
 | |
|          mappingavailable:=getmap(s)<>nil;
 | |
|       end;
 | |
| 
 | |
|     function mappingavailable(cp : word) : boolean;
 | |
| 
 | |
|       begin
 | |
|          mappingavailable:=getmap(cp)<>nil;
 | |
|       end;
 | |
| 
 | |
|     function getunicode(c : AnsiChar;p : punicodemap) : tunicodechar;
 | |
| 
 | |
|       begin
 | |
|          if ord(c)<=p^.lastchar then
 | |
|            getunicode:=p^.map[ord(c)].unicode
 | |
|          else
 | |
|            getunicode:=0;
 | |
|       end;
 | |
| 
 | |
|     function getunicode(
 | |
|       AAnsiStr : pansichar;
 | |
|       AAnsiLen : LongInt;
 | |
|       AMap     : punicodemap;
 | |
|       ADest    : tunicodestring
 | |
|     ) : LongInt;
 | |
| 
 | |
|       var
 | |
|          i, c, k, destLen : longint;
 | |
|          ps : pansichar;
 | |
|          pd : ^tunicodechar;
 | |
| 
 | |
|       begin
 | |
|         if (AAnsiStr=nil) or (AAnsiLen<=0) then
 | |
|           exit(0);
 | |
|         ps:=AAnsiStr;
 | |
|         if (ADest=nil) then
 | |
|           begin
 | |
|             c:=AAnsiLen-1;
 | |
|             destLen:=0;
 | |
|             i:=0;
 | |
|             while (i<=c) do
 | |
|               begin
 | |
|                 if (ord(ps^)<=AMap^.lastchar) then
 | |
|                   begin
 | |
|                     if (AMap^.map[ord(ps^)].flag=umf_leadbyte) and (i<c) then
 | |
|                       begin
 | |
|                         Inc(ps);
 | |
|                         i:=i+1;
 | |
|                       end;
 | |
|                   end;
 | |
|                 i:=i+1;
 | |
|                 Inc(ps);
 | |
|                 destLen:=destLen+1;
 | |
|               end;
 | |
|             exit(destLen);
 | |
|           end;
 | |
| 
 | |
|         pd:=ADest;
 | |
|         c:=AAnsiLen-1;
 | |
|         i:=0;
 | |
|         while (i<=c) do
 | |
|           begin
 | |
|             if (ord(ps^)<=AMap^.lastchar) then
 | |
|               begin
 | |
|                 if (AMap^.map[ord(ps^)].flag=umf_leadbyte) then
 | |
|                   begin
 | |
|                     if (i<c) then
 | |
|                       begin
 | |
|                         k:=(Ord(ps^)*256);
 | |
|                         Inc(ps);
 | |
|                         i:=i+1;
 | |
|                         k:=k+Ord(ps^);
 | |
|                         if (k<=AMap^.lastchar) then
 | |
|                           pd^:=AMap^.map[k].unicode
 | |
|                         else
 | |
|                           pd^:=UNKNOW_CHAR_W;
 | |
|                       end
 | |
|                     else
 | |
|                       pd^:=UNKNOW_CHAR_W;
 | |
|                   end
 | |
|                 else
 | |
|                   pd^:=AMap^.map[ord(ps^)].unicode
 | |
|               end
 | |
|             else
 | |
|               pd^:=UNKNOW_CHAR_W;
 | |
|             i:=i+1;
 | |
|             Inc(ps);
 | |
|             Inc(pd);
 | |
|           end;
 | |
|         result:=((PtrUInt(pd)-PtrUInt(ADest)) div SizeOf(tunicodechar));
 | |
|       end;
 | |
| 
 | |
|     function getascii(c : tunicodechar;p : punicodemap) : string;
 | |
|       var
 | |
|          rm : preversecharmapping;
 | |
|       begin
 | |
|         rm:=find(c,p);
 | |
|         if rm<>nil then
 | |
|           begin
 | |
|             if rm^.char2=0 then
 | |
|               begin
 | |
|                 SetLength(Result,1);
 | |
|                 Byte(Result[1]):=rm^.char1;
 | |
|               end
 | |
|             else
 | |
|               begin
 | |
|                 SetLength(Result,2);
 | |
|                 Byte(Result[1]):=rm^.char1;
 | |
|                 Byte(Result[2]):=rm^.char2;
 | |
|               end;
 | |
|           end
 | |
|         else
 | |
|           Result:=UNKNOW_CHAR_A;
 | |
|       end;
 | |
| 
 | |
|     function getascii(c : tunicodechar;p : punicodemap; ABuffer : PAnsiChar; ABufferLen : LongInt) : LongInt;
 | |
|       var
 | |
|          rm : preversecharmapping;
 | |
|       begin
 | |
|          if (ABuffer<>nil) and (ABufferLen<=0) then
 | |
|            exit(-1);
 | |
|         rm:=find(c,p);
 | |
|         if rm<>nil then
 | |
|           begin
 | |
|             if (ABuffer=nil) then
 | |
|               begin
 | |
|                 if rm^.char2=0 then
 | |
|                   Result:=1
 | |
|                 else
 | |
|                   Result:=2;
 | |
|               end
 | |
|             else
 | |
|               begin
 | |
|                 if rm^.char2=0 then
 | |
|                   begin
 | |
|                     Byte(ABuffer^):=rm^.char1;
 | |
|                     Result:=1;
 | |
|                   end
 | |
|                 else
 | |
|                   begin
 | |
|                     if (ABufferLen<2) then
 | |
|                       Result:=-1
 | |
|                     else
 | |
|                       begin
 | |
|                         Byte(ABuffer^):=rm^.char1;
 | |
|                         Byte((ABuffer+1)^):=rm^.char2;
 | |
|                         Result:=2;
 | |
|                       end
 | |
|                   end;
 | |
|               end;
 | |
|           end
 | |
|         else
 | |
|           begin
 | |
|             ABuffer^:=UNKNOW_CHAR_A;
 | |
|             Result:=1;
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
|   var
 | |
|      hp : punicodemap;
 | |
| 
 | |
| initialization
 | |
|   mappings:=nil;
 | |
| finalization
 | |
|   while assigned(mappings) do
 | |
|     begin
 | |
|        hp:=mappings^.next;
 | |
|        if not(mappings^.internalmap) then
 | |
|          begin
 | |
|             freemem(mappings^.map);
 | |
|             freemem(mappings^.reversemap);
 | |
|             dispose(mappings);
 | |
|          end;
 | |
|        mappings:=hp;
 | |
|     end;
 | |
| end.
 | 
