2
0

charset.pp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2000 by Florian Klaempfl
  4. member of the Free Pascal development team.
  5. This unit implements several classes for charset conversions
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$mode objfpc}
  13. {$pointermath on}
  14. {$PACKENUM 1}
  15. {$IFNDEF FPC_DOTTEDUNITS}
  16. unit charset;
  17. {$ENDIF FPC_DOTTEDUNITS}
  18. interface
  19. type
  20. tunicodechar = word;
  21. tunicodestring = ^tunicodechar;
  22. tunicodecharmappingflag = (umf_noinfo,umf_leadbyte,umf_undefined,
  23. umf_unused);
  24. punicodecharmapping = ^tunicodecharmapping;
  25. tunicodecharmapping = packed record
  26. unicode : tunicodechar;
  27. flag : tunicodecharmappingflag;
  28. reserved : byte;
  29. end;
  30. preversecharmapping = ^treversecharmapping;
  31. treversecharmapping = packed record
  32. unicode : tunicodechar;
  33. char1 : Byte;
  34. char2 : Byte;
  35. end;
  36. punicodemap = ^tunicodemap;
  37. tunicodemap = record
  38. cpname : string[20];
  39. cp : word;
  40. map : punicodecharmapping;
  41. lastchar : longint;
  42. reversemap : preversecharmapping;
  43. reversemaplength : longint;
  44. next : punicodemap;
  45. internalmap : boolean;
  46. end;
  47. TSerializedMapHeader = packed record
  48. cpName : string[20];
  49. cp : UInt16;
  50. mapLength : UInt32;
  51. lastChar : Int32;
  52. reverseMapLength : UInt32;
  53. end;
  54. const
  55. BINARY_MAPPING_FILE_EXT = '.bcm';
  56. function loadunicodemapping(const cpname,f : string; cp :word) : punicodemap;
  57. function loadbinaryunicodemapping(const directory,cpname : string) : punicodemap;overload;
  58. function loadbinaryunicodemapping(const filename : string) : punicodemap;overload;
  59. function loadbinaryunicodemapping(
  60. const AData : Pointer;
  61. const ADataLength : Integer
  62. ) : punicodemap;overload;
  63. procedure registermapping(p : punicodemap);
  64. function registerbinarymapping(const directory,cpname : string):Boolean;
  65. function getmap(const s : string) : punicodemap;
  66. function getmap(cp : word) : punicodemap;
  67. function mappingavailable(const s : string) : boolean;inline;
  68. function mappingavailable(cp :word) : boolean;inline;
  69. function getunicode(c : AnsiChar;p : punicodemap) : tunicodechar;inline;
  70. function getunicode(
  71. AAnsiStr : pansichar;
  72. AAnsiLen : LongInt;
  73. AMap : punicodemap;
  74. ADest : tunicodestring
  75. ) : LongInt;
  76. function getascii(c : tunicodechar;p : punicodemap) : string;
  77. function getascii(c : tunicodechar;p : punicodemap; ABuffer : PAnsiChar; ABufferLen : LongInt) : LongInt;
  78. implementation
  79. const
  80. UNKNOW_CHAR_A = ansichar(63);
  81. UNKNOW_CHAR_W = tunicodechar(63);
  82. var
  83. mappings : punicodemap;
  84. procedure QuickSort(AList: preversecharmapping; L, R : Longint);
  85. var
  86. I, J : Longint;
  87. P, Q : treversecharmapping;
  88. begin
  89. repeat
  90. I:=L;
  91. J:=R;
  92. P:=AList[(L + R) div 2];
  93. repeat
  94. while (P.unicode-AList[I].unicode) > 0 do
  95. I:=I+1;
  96. while (P.unicode-AList[J].unicode) < 0 do
  97. J:=J-1;
  98. if I<=J then
  99. begin
  100. Q:=AList[I];
  101. AList[I]:=AList[J];
  102. AList[J]:=Q;
  103. I:=I+1;
  104. J:=J-1;
  105. end;
  106. until I > J;
  107. if J-L < R-I then
  108. begin
  109. if L<J then
  110. QuickSort(AList, L, J);
  111. L:=I;
  112. end
  113. else
  114. begin
  115. if I < R then
  116. QuickSort(AList, I, R);
  117. R:=J;
  118. end;
  119. until L>=R;
  120. end;
  121. function find(
  122. const c : tunicodechar;
  123. const AData : preversecharmapping;
  124. const ALen : LongInt
  125. ) : preversecharmapping;overload;
  126. var
  127. l, h, m : longint;
  128. r:preversecharmapping;
  129. begin
  130. if ALen=0 then
  131. exit(nil);
  132. r:=AData;
  133. l:=0;
  134. h:=ALen-1;
  135. while l<h do begin
  136. m:=(l+h) div 2;
  137. if r[m].unicode<c then
  138. l:=m+1
  139. else
  140. h:=m;
  141. end;
  142. if (l=h) and (r[l].unicode=c) then
  143. Result:=@r[l]
  144. else
  145. Result:=nil;
  146. end;
  147. function find(
  148. const c : tunicodechar;
  149. const p : punicodemap
  150. ) : preversecharmapping;overload;inline;
  151. begin
  152. Result:=find(c,p^.reversemap,p^.reversemaplength);
  153. end;
  154. function RemoveDuplicates(
  155. const AData : preversecharmapping;
  156. const ALen : LongInt;
  157. out AResultLen : LongInt
  158. ) : preversecharmapping;
  159. var
  160. r0, r, p, t : preversecharmapping;
  161. i, c, actualCount : LongInt;
  162. begin
  163. c:=ALen;
  164. GetMem(r0,c*SizeOf(treversecharmapping));
  165. r:=r0;
  166. p:=AData;
  167. actualCount:=0;
  168. i:=0;
  169. while i<c do
  170. begin
  171. t:=find(p^.unicode,r0,actualCount);
  172. if t=nil then
  173. begin
  174. r^:=p^;
  175. actualCount:=actualCount+1;
  176. Inc(r);
  177. end
  178. else
  179. begin
  180. if (p^.char1<t^.char1) or
  181. ((p^.char1=t^.char1) and (p^.char2<t^.char2))
  182. then
  183. t^:=p^;//keep the first mapping
  184. end;
  185. i:=i+1;
  186. Inc(p);
  187. end;
  188. if c<>actualCount then
  189. ReAllocMem(r0,actualCount*SizeOf(treversecharmapping));
  190. AResultLen:=actualCount;
  191. Result:=r0;
  192. end;
  193. function buildreversemap(
  194. const AMapping : punicodecharmapping;
  195. const ALen : LongInt;
  196. out AResultLen : LongInt
  197. ) : preversecharmapping;
  198. var
  199. r0, r, t : preversecharmapping;
  200. i, c, actualCount, ti : LongInt;
  201. p : punicodecharmapping;
  202. begin
  203. if (ALen<1) then
  204. exit(nil);
  205. p:=AMapping;
  206. c:=ALen;
  207. GetMem(r0,c*SizeOf(treversecharmapping));
  208. r:=r0;
  209. actualCount:=0;
  210. i:=0;
  211. while i<c do
  212. begin
  213. if (p^.flag=umf_noinfo) then
  214. begin
  215. r^.unicode:=p^.unicode;
  216. if i<=High(Byte) then
  217. begin
  218. r^.char1:=i;
  219. r^.char2:=0;
  220. end
  221. else
  222. begin
  223. r^.char1:=i div 256;
  224. r^.char2:=i mod 256;
  225. end;
  226. actualCount:=actualCount+1;
  227. Inc(r);
  228. end;
  229. Inc(p);
  230. i:=i+1;
  231. end;
  232. if c<>actualCount then
  233. ReAllocMem(r0,actualCount*SizeOf(treversecharmapping));
  234. if actualCount>1 then
  235. begin
  236. QuickSort(r0,0,(actualCount-1));
  237. t:=RemoveDuplicates(r0,actualCount,ti);
  238. FreeMem(r0,actualCount*SizeOf(treversecharmapping));
  239. r0:=t;
  240. actualCount:=ti;
  241. end;
  242. AResultLen:=actualCount;
  243. Result:=r0;
  244. end;
  245. procedure inititems(const p : punicodecharmapping; const ALen : LongInt);
  246. const
  247. INIT_ITEM : tunicodecharmapping = (unicode:0; flag:umf_unused; reserved:0);
  248. var
  249. x : punicodecharmapping;
  250. i : LongInt;
  251. begin
  252. x:=p;
  253. for i:=0 to ALen-1 do
  254. begin
  255. x^:=INIT_ITEM;
  256. Inc(x);
  257. end;
  258. end;
  259. function loadunicodemapping(const cpname,f : string; cp :word) : punicodemap;
  260. var
  261. data : punicodecharmapping;
  262. datasize : longint;
  263. t : text;
  264. s,hs : string;
  265. scanpos,charpos,unicodevalue : longint;
  266. code : word;
  267. flag : tunicodecharmappingflag;
  268. p : punicodemap;
  269. lastchar, i : longint;
  270. begin
  271. lastchar:=-1;
  272. loadunicodemapping:=nil;
  273. datasize:=256;
  274. GetMem(data,sizeof(tunicodecharmapping)*datasize);
  275. inititems(data,datasize);
  276. assign(t,f);
  277. {$I-}
  278. reset(t);
  279. {$I+}
  280. if ioresult<>0 then
  281. begin
  282. freemem(data,sizeof(tunicodecharmapping)*datasize);
  283. exit;
  284. end;
  285. while not(eof(t)) do
  286. begin
  287. readln(t,s);
  288. if (s[1]='0') and (s[2]='x') then
  289. begin
  290. flag:=umf_unused;
  291. scanpos:=3;
  292. hs:='$';
  293. while s[scanpos] in ['0'..'9','A'..'F','a'..'f'] do
  294. begin
  295. hs:=hs+s[scanpos];
  296. inc(scanpos);
  297. end;
  298. val(hs,charpos,code);
  299. if code<>0 then
  300. begin
  301. freemem(data,sizeof(tunicodecharmapping)*datasize);
  302. close(t);
  303. exit;
  304. end;
  305. while not(s[scanpos] in ['0','#']) do
  306. inc(scanpos);
  307. if s[scanpos]='#' then
  308. begin
  309. { special char }
  310. unicodevalue:=$ffff;
  311. hs:=copy(s,scanpos,length(s)-scanpos+1);
  312. if hs='#DBCS LEAD BYTE' then
  313. flag:=umf_leadbyte;
  314. end
  315. else
  316. begin
  317. { C hex prefix }
  318. inc(scanpos,2);
  319. hs:='$';
  320. while s[scanpos] in ['0'..'9','A'..'F','a'..'f'] do
  321. begin
  322. hs:=hs+s[scanpos];
  323. inc(scanpos);
  324. end;
  325. val(hs,unicodevalue,code);
  326. if code<>0 then
  327. begin
  328. freemem(data,sizeof(tunicodecharmapping)*datasize);
  329. close(t);
  330. exit;
  331. end;
  332. if charpos>datasize then
  333. begin
  334. { allocate 1024 bytes more because }
  335. { if we need more than 256 entries it's }
  336. { probably a mbcs with a lot of }
  337. { entries }
  338. i:=datasize;
  339. datasize:=charpos+8*1024;
  340. reallocmem(data,sizeof(tunicodecharmapping)*datasize);
  341. inititems(@data[i],(datasize-i));
  342. end;
  343. flag:=umf_noinfo;
  344. end;
  345. data[charpos].flag:=flag;
  346. data[charpos].unicode:=unicodevalue;
  347. if charpos>lastchar then
  348. lastchar:=charpos;
  349. end;
  350. end;
  351. close(t);
  352. new(p);
  353. p^.lastchar:=lastchar;
  354. p^.cpname:=cpname;
  355. p^.cp:=cp;
  356. p^.internalmap:=false;
  357. p^.next:=nil;
  358. p^.map:=data;
  359. p^.reversemap:=buildreversemap(p^.map,(p^.lastchar+1),p^.reversemaplength);
  360. loadunicodemapping:=p;
  361. end;
  362. function loadbinaryunicodemapping(const directory, cpname : string) : punicodemap;
  363. const
  364. {$IFDEF ENDIAN_LITTLE}
  365. ENDIAN_SUFFIX = 'le';
  366. {$ENDIF ENDIAN_LITTLE}
  367. {$IFDEF ENDIAN_BIG}
  368. ENDIAN_SUFFIX = 'be';
  369. {$ENDIF ENDIAN_BIG}
  370. var
  371. fileName : string;
  372. begin
  373. fileName := directory;
  374. if (fileName <> '') then begin
  375. if (fileName[Length(fileName)] <> DirectorySeparator) then
  376. fileName := fileName + DirectorySeparator;
  377. end;
  378. fileName := fileName + cpname + '_' + ENDIAN_SUFFIX + BINARY_MAPPING_FILE_EXT;
  379. Result := loadbinaryunicodemapping(fileName);
  380. end;
  381. {$PUSH}
  382. {$I-}
  383. function loadbinaryunicodemapping(const filename : string) : punicodemap;
  384. const
  385. BLOCK_SIZE = 16*1024;
  386. var
  387. f : File of Byte;
  388. locSize, locReaded, c : LongInt;
  389. locBuffer : PByte;
  390. locBlockSize : LongInt;
  391. begin
  392. Result := nil;
  393. if (filename='') then
  394. exit;
  395. Assign(f,filename);
  396. Reset(f);
  397. if (IOResult<>0) then
  398. exit;
  399. locSize:=FileSize(f);
  400. if (locSize<SizeOf(TSerializedMapHeader)) then
  401. begin
  402. Close(f);
  403. exit;
  404. end;
  405. locBuffer:=GetMem(locSize);
  406. locBlockSize:=BLOCK_SIZE;
  407. locReaded:=0;
  408. c := 0;
  409. while (locReaded<locSize) do
  410. begin
  411. if (locBlockSize>(locSize-locReaded)) then
  412. locBlockSize:=locSize-locReaded;
  413. BlockRead(f,locBuffer[locReaded],locBlockSize,c);
  414. if (IOResult<>0) or (c<=0) then
  415. begin
  416. FreeMem(locBuffer,locSize);
  417. Close(f);
  418. exit;
  419. end;
  420. locReaded:=locReaded+c;
  421. end;
  422. Result:=loadbinaryunicodemapping(locBuffer,locSize);
  423. FreeMem(locBuffer,locSize);
  424. Close(f);
  425. end;
  426. {$POP}
  427. procedure freemapping(amapping : punicodemap);
  428. begin
  429. if (amapping = nil) then
  430. exit;
  431. if (amapping^.map <> nil) then
  432. freemem(amapping^.map);
  433. if (amapping^.reversemap <> nil) then
  434. freemem(amapping^.reversemap);
  435. dispose(amapping);
  436. end;
  437. function loadbinaryunicodemapping(
  438. const AData : Pointer;
  439. const ADataLength : Integer
  440. ) : punicodemap;
  441. var
  442. dataPointer : PByte;
  443. readedLength : LongInt;
  444. function ReadBuffer(ADest : Pointer; ALength : LongInt) : Boolean;
  445. begin
  446. Result := (readedLength + ALength) <= ADataLength;
  447. if not result then
  448. exit;
  449. Move(dataPointer^,ADest^,ALength);
  450. Inc(dataPointer,ALength);
  451. readedLength := readedLength + ALength;
  452. end;
  453. var
  454. h : TSerializedMapHeader;
  455. r : punicodemap;
  456. begin
  457. Result := nil;
  458. readedLength := 0;
  459. dataPointer := AData;
  460. if not ReadBuffer(@h,SizeOf(h)) then
  461. exit;
  462. New(r);
  463. FillChar(r^,SizeOf(tunicodemap),0);
  464. r^.cpname := h.cpName;
  465. r^.cp := h.cp;
  466. r^.map := AllocMem(h.mapLength);
  467. if not ReadBuffer(r^.map,h.mapLength) then
  468. begin
  469. freemapping(r);
  470. exit;
  471. end;
  472. r^.lastchar := h.lastChar;
  473. r^.reversemap := AllocMem(h.reverseMapLength);
  474. if not ReadBuffer(r^.reversemap,h.reverseMapLength) then
  475. begin
  476. freemapping(r);
  477. exit;
  478. end;
  479. r^.reversemaplength := (h.reverseMapLength div SizeOf(treversecharmapping));
  480. Result := r;
  481. end;
  482. procedure registermapping(p : punicodemap);
  483. begin
  484. p^.next:=mappings;
  485. mappings:=p;
  486. end;
  487. {$ifdef FPC_HAS_FEATURE_THREADING}
  488. threadvar
  489. {$else FPC_HAS_FEATURE_THREADING}
  490. var
  491. {$endif FPC_HAS_FEATURE_THREADING}
  492. strmapcache : string;
  493. strmapcachep : punicodemap;
  494. function registerbinarymapping(const directory, cpname : string) : Boolean;
  495. var
  496. p : punicodemap;
  497. begin
  498. Result := False;
  499. p := loadbinaryunicodemapping(directory,cpname);
  500. if (p = nil) then
  501. exit;
  502. registermapping(p);
  503. Result := True;
  504. end;
  505. function getmap(const s : string) : punicodemap;
  506. var
  507. hp : punicodemap;
  508. begin
  509. if (strmapcache=s) and assigned(strmapcachep) and (strmapcachep^.cpname=s) then
  510. begin
  511. getmap:=strmapcachep;
  512. exit;
  513. end;
  514. hp:=mappings;
  515. while assigned(hp) do
  516. begin
  517. if hp^.cpname=s then
  518. begin
  519. getmap:=hp;
  520. strmapcache:=s;
  521. strmapcachep:=hp;
  522. exit;
  523. end;
  524. hp:=hp^.next;
  525. end;
  526. getmap:=nil;
  527. end;////////
  528. {$ifdef FPC_HAS_FEATURE_THREADING}
  529. threadvar
  530. {$else FPC_HAS_FEATURE_THREADING}
  531. var
  532. {$endif FPC_HAS_FEATURE_THREADING}
  533. intmapcache : word;
  534. intmapcachep : punicodemap;
  535. function getmap(cp : word) : punicodemap;
  536. var
  537. hp : punicodemap;
  538. begin
  539. if (intmapcache=cp) and assigned(intmapcachep) and (intmapcachep^.cp=cp) then
  540. begin
  541. getmap:=intmapcachep;
  542. exit;
  543. end;
  544. hp:=mappings;
  545. while assigned(hp) do
  546. begin
  547. if hp^.cp=cp then
  548. begin
  549. getmap:=hp;
  550. intmapcache:=cp;
  551. intmapcachep:=hp;
  552. exit;
  553. end;
  554. hp:=hp^.next;
  555. end;
  556. getmap:=nil;
  557. end;
  558. function mappingavailable(const s : string) : boolean;
  559. begin
  560. mappingavailable:=getmap(s)<>nil;
  561. end;
  562. function mappingavailable(cp : word) : boolean;
  563. begin
  564. mappingavailable:=getmap(cp)<>nil;
  565. end;
  566. function getunicode(c : AnsiChar;p : punicodemap) : tunicodechar;
  567. begin
  568. if ord(c)<=p^.lastchar then
  569. getunicode:=p^.map[ord(c)].unicode
  570. else
  571. getunicode:=0;
  572. end;
  573. function getunicode(
  574. AAnsiStr : pansichar;
  575. AAnsiLen : LongInt;
  576. AMap : punicodemap;
  577. ADest : tunicodestring
  578. ) : LongInt;
  579. var
  580. i, c, k, destLen : longint;
  581. ps : pansichar;
  582. pd : ^tunicodechar;
  583. begin
  584. if (AAnsiStr=nil) or (AAnsiLen<=0) then
  585. exit(0);
  586. ps:=AAnsiStr;
  587. if (ADest=nil) then
  588. begin
  589. c:=AAnsiLen-1;
  590. destLen:=0;
  591. i:=0;
  592. while (i<=c) do
  593. begin
  594. if (ord(ps^)<=AMap^.lastchar) then
  595. begin
  596. if (AMap^.map[ord(ps^)].flag=umf_leadbyte) and (i<c) then
  597. begin
  598. Inc(ps);
  599. i:=i+1;
  600. end;
  601. end;
  602. i:=i+1;
  603. Inc(ps);
  604. destLen:=destLen+1;
  605. end;
  606. exit(destLen);
  607. end;
  608. pd:=ADest;
  609. c:=AAnsiLen-1;
  610. i:=0;
  611. while (i<=c) do
  612. begin
  613. if (ord(ps^)<=AMap^.lastchar) then
  614. begin
  615. if (AMap^.map[ord(ps^)].flag=umf_leadbyte) then
  616. begin
  617. if (i<c) then
  618. begin
  619. k:=(Ord(ps^)*256);
  620. Inc(ps);
  621. i:=i+1;
  622. k:=k+Ord(ps^);
  623. if (k<=AMap^.lastchar) then
  624. pd^:=AMap^.map[k].unicode
  625. else
  626. pd^:=UNKNOW_CHAR_W;
  627. end
  628. else
  629. pd^:=UNKNOW_CHAR_W;
  630. end
  631. else
  632. pd^:=AMap^.map[ord(ps^)].unicode
  633. end
  634. else
  635. pd^:=UNKNOW_CHAR_W;
  636. i:=i+1;
  637. Inc(ps);
  638. Inc(pd);
  639. end;
  640. result:=((PtrUInt(pd)-PtrUInt(ADest)) div SizeOf(tunicodechar));
  641. end;
  642. function getascii(c : tunicodechar;p : punicodemap) : string;
  643. var
  644. rm : preversecharmapping;
  645. begin
  646. rm:=find(c,p);
  647. if rm<>nil then
  648. begin
  649. if rm^.char2=0 then
  650. begin
  651. SetLength(Result,1);
  652. Byte(Result[1]):=rm^.char1;
  653. end
  654. else
  655. begin
  656. SetLength(Result,2);
  657. Byte(Result[1]):=rm^.char1;
  658. Byte(Result[2]):=rm^.char2;
  659. end;
  660. end
  661. else
  662. Result:=UNKNOW_CHAR_A;
  663. end;
  664. function getascii(c : tunicodechar;p : punicodemap; ABuffer : PAnsiChar; ABufferLen : LongInt) : LongInt;
  665. var
  666. rm : preversecharmapping;
  667. begin
  668. if (ABuffer<>nil) and (ABufferLen<=0) then
  669. exit(-1);
  670. rm:=find(c,p);
  671. if rm<>nil then
  672. begin
  673. if (ABuffer=nil) then
  674. begin
  675. if rm^.char2=0 then
  676. Result:=1
  677. else
  678. Result:=2;
  679. end
  680. else
  681. begin
  682. if rm^.char2=0 then
  683. begin
  684. Byte(ABuffer^):=rm^.char1;
  685. Result:=1;
  686. end
  687. else
  688. begin
  689. if (ABufferLen<2) then
  690. Result:=-1
  691. else
  692. begin
  693. Byte(ABuffer^):=rm^.char1;
  694. Byte((ABuffer+1)^):=rm^.char2;
  695. Result:=2;
  696. end
  697. end;
  698. end;
  699. end
  700. else
  701. begin
  702. ABuffer^:=UNKNOW_CHAR_A;
  703. Result:=1;
  704. end;
  705. end;
  706. var
  707. hp : punicodemap;
  708. initialization
  709. mappings:=nil;
  710. finalization
  711. while assigned(mappings) do
  712. begin
  713. hp:=mappings^.next;
  714. if not(mappings^.internalmap) then
  715. begin
  716. freemem(mappings^.map);
  717. freemem(mappings^.reversemap);
  718. dispose(mappings);
  719. end;
  720. mappings:=hp;
  721. end;
  722. end.