2
0

charset.pp 21 KB

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