charset.pp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  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. begin
  397. Close(f);
  398. exit;
  399. end;
  400. locSize:=FileSize(f);
  401. if (locSize<SizeOf(TSerializedMapHeader)) then
  402. begin
  403. Close(f);
  404. exit;
  405. end;
  406. locBuffer:=GetMem(locSize);
  407. locBlockSize:=BLOCK_SIZE;
  408. locReaded:=0;
  409. c := 0;
  410. while (locReaded<locSize) do
  411. begin
  412. if (locBlockSize>(locSize-locReaded)) then
  413. locBlockSize:=locSize-locReaded;
  414. BlockRead(f,locBuffer[locReaded],locBlockSize,c);
  415. if (IOResult<>0) or (c<=0) then
  416. begin
  417. FreeMem(locBuffer,locSize);
  418. Close(f);
  419. exit;
  420. end;
  421. locReaded:=locReaded+c;
  422. end;
  423. Result:=loadbinaryunicodemapping(locBuffer,locSize);
  424. FreeMem(locBuffer,locSize);
  425. Close(f);
  426. end;
  427. {$POP}
  428. procedure freemapping(amapping : punicodemap);
  429. begin
  430. if (amapping = nil) then
  431. exit;
  432. if (amapping^.map <> nil) then
  433. freemem(amapping^.map);
  434. if (amapping^.reversemap <> nil) then
  435. freemem(amapping^.reversemap);
  436. dispose(amapping);
  437. end;
  438. function loadbinaryunicodemapping(
  439. const AData : Pointer;
  440. const ADataLength : Integer
  441. ) : punicodemap;
  442. var
  443. dataPointer : PByte;
  444. readedLength : LongInt;
  445. function ReadBuffer(ADest : Pointer; ALength : LongInt) : Boolean;
  446. begin
  447. Result := (readedLength + ALength) <= ADataLength;
  448. if not result then
  449. exit;
  450. Move(dataPointer^,ADest^,ALength);
  451. Inc(dataPointer,ALength);
  452. readedLength := readedLength + ALength;
  453. end;
  454. var
  455. h : TSerializedMapHeader;
  456. r : punicodemap;
  457. begin
  458. Result := nil;
  459. readedLength := 0;
  460. dataPointer := AData;
  461. if not ReadBuffer(@h,SizeOf(h)) then
  462. exit;
  463. New(r);
  464. FillChar(r^,SizeOf(tunicodemap),0);
  465. r^.cpname := h.cpName;
  466. r^.cp := h.cp;
  467. r^.map := AllocMem(h.mapLength);
  468. if not ReadBuffer(r^.map,h.mapLength) then
  469. begin
  470. freemapping(r);
  471. exit;
  472. end;
  473. r^.lastchar := h.lastChar;
  474. r^.reversemap := AllocMem(h.reverseMapLength);
  475. if not ReadBuffer(r^.reversemap,h.reverseMapLength) then
  476. begin
  477. freemapping(r);
  478. exit;
  479. end;
  480. r^.reversemaplength := (h.reverseMapLength div SizeOf(treversecharmapping));
  481. Result := r;
  482. end;
  483. procedure registermapping(p : punicodemap);
  484. begin
  485. p^.next:=mappings;
  486. mappings:=p;
  487. end;
  488. {$ifdef FPC_HAS_FEATURE_THREADING}
  489. threadvar
  490. {$else FPC_HAS_FEATURE_THREADING}
  491. var
  492. {$endif FPC_HAS_FEATURE_THREADING}
  493. strmapcache : string;
  494. strmapcachep : punicodemap;
  495. function registerbinarymapping(const directory, cpname : string) : Boolean;
  496. var
  497. p : punicodemap;
  498. begin
  499. Result := False;
  500. p := loadbinaryunicodemapping(directory,cpname);
  501. if (p = nil) then
  502. exit;
  503. registermapping(p);
  504. Result := True;
  505. end;
  506. function getmap(const s : string) : punicodemap;
  507. var
  508. hp : punicodemap;
  509. begin
  510. if (strmapcache=s) and assigned(strmapcachep) and (strmapcachep^.cpname=s) then
  511. begin
  512. getmap:=strmapcachep;
  513. exit;
  514. end;
  515. hp:=mappings;
  516. while assigned(hp) do
  517. begin
  518. if hp^.cpname=s then
  519. begin
  520. getmap:=hp;
  521. strmapcache:=s;
  522. strmapcachep:=hp;
  523. exit;
  524. end;
  525. hp:=hp^.next;
  526. end;
  527. getmap:=nil;
  528. end;////////
  529. {$ifdef FPC_HAS_FEATURE_THREADING}
  530. threadvar
  531. {$else FPC_HAS_FEATURE_THREADING}
  532. var
  533. {$endif FPC_HAS_FEATURE_THREADING}
  534. intmapcache : word;
  535. intmapcachep : punicodemap;
  536. function getmap(cp : word) : punicodemap;
  537. var
  538. hp : punicodemap;
  539. begin
  540. if (intmapcache=cp) and assigned(intmapcachep) and (intmapcachep^.cp=cp) then
  541. begin
  542. getmap:=intmapcachep;
  543. exit;
  544. end;
  545. hp:=mappings;
  546. while assigned(hp) do
  547. begin
  548. if hp^.cp=cp then
  549. begin
  550. getmap:=hp;
  551. intmapcache:=cp;
  552. intmapcachep:=hp;
  553. exit;
  554. end;
  555. hp:=hp^.next;
  556. end;
  557. getmap:=nil;
  558. end;
  559. function mappingavailable(const s : string) : boolean;
  560. begin
  561. mappingavailable:=getmap(s)<>nil;
  562. end;
  563. function mappingavailable(cp : word) : boolean;
  564. begin
  565. mappingavailable:=getmap(cp)<>nil;
  566. end;
  567. function getunicode(c : char;p : punicodemap) : tunicodechar;
  568. begin
  569. if ord(c)<=p^.lastchar then
  570. getunicode:=p^.map[ord(c)].unicode
  571. else
  572. getunicode:=0;
  573. end;
  574. function getunicode(
  575. AAnsiStr : pansichar;
  576. AAnsiLen : LongInt;
  577. AMap : punicodemap;
  578. ADest : tunicodestring
  579. ) : LongInt;
  580. var
  581. i, c, k, destLen : longint;
  582. ps : pansichar;
  583. pd : ^tunicodechar;
  584. begin
  585. if (AAnsiStr=nil) or (AAnsiLen<=0) then
  586. exit(0);
  587. ps:=AAnsiStr;
  588. if (ADest=nil) then
  589. begin
  590. c:=AAnsiLen-1;
  591. destLen:=0;
  592. i:=0;
  593. while (i<=c) do
  594. begin
  595. if (ord(ps^)<=AMap^.lastchar) then
  596. begin
  597. if (AMap^.map[ord(ps^)].flag=umf_leadbyte) and (i<c) then
  598. begin
  599. Inc(ps);
  600. i:=i+1;
  601. end;
  602. end;
  603. i:=i+1;
  604. Inc(ps);
  605. destLen:=destLen+1;
  606. end;
  607. exit(destLen);
  608. end;
  609. pd:=ADest;
  610. c:=AAnsiLen-1;
  611. i:=0;
  612. while (i<=c) do
  613. begin
  614. if (ord(ps^)<=AMap^.lastchar) then
  615. begin
  616. if (AMap^.map[ord(ps^)].flag=umf_leadbyte) then
  617. begin
  618. if (i<c) then
  619. begin
  620. k:=(Ord(ps^)*256);
  621. Inc(ps);
  622. i:=i+1;
  623. k:=k+Ord(ps^);
  624. if (k<=AMap^.lastchar) then
  625. pd^:=AMap^.map[k].unicode
  626. else
  627. pd^:=UNKNOW_CHAR_W;
  628. end
  629. else
  630. pd^:=UNKNOW_CHAR_W;
  631. end
  632. else
  633. pd^:=AMap^.map[ord(ps^)].unicode
  634. end
  635. else
  636. pd^:=UNKNOW_CHAR_W;
  637. i:=i+1;
  638. Inc(ps);
  639. Inc(pd);
  640. end;
  641. result:=((PtrUInt(pd)-PtrUInt(ADest)) div SizeOf(tunicodechar));
  642. end;
  643. function getascii(c : tunicodechar;p : punicodemap) : string;
  644. var
  645. rm : preversecharmapping;
  646. begin
  647. rm:=find(c,p);
  648. if rm<>nil then
  649. begin
  650. if rm^.char2=0 then
  651. begin
  652. SetLength(Result,1);
  653. Byte(Result[1]):=rm^.char1;
  654. end
  655. else
  656. begin
  657. SetLength(Result,2);
  658. Byte(Result[1]):=rm^.char1;
  659. Byte(Result[2]):=rm^.char2;
  660. end;
  661. end
  662. else
  663. Result:=UNKNOW_CHAR_A;
  664. end;
  665. function getascii(c : tunicodechar;p : punicodemap; ABuffer : PAnsiChar; ABufferLen : LongInt) : LongInt;
  666. var
  667. rm : preversecharmapping;
  668. begin
  669. if (ABuffer<>nil) and (ABufferLen<=0) then
  670. exit(-1);
  671. rm:=find(c,p);
  672. if rm<>nil then
  673. begin
  674. if (ABuffer=nil) then
  675. begin
  676. if rm^.char2=0 then
  677. Result:=1
  678. else
  679. Result:=2;
  680. end
  681. else
  682. begin
  683. if rm^.char2=0 then
  684. begin
  685. Byte(ABuffer^):=rm^.char1;
  686. Result:=1;
  687. end
  688. else
  689. begin
  690. if (ABufferLen<2) then
  691. Result:=-1
  692. else
  693. begin
  694. Byte(ABuffer^):=rm^.char1;
  695. Byte((ABuffer+1)^):=rm^.char2;
  696. Result:=2;
  697. end
  698. end;
  699. end;
  700. end
  701. else
  702. begin
  703. ABuffer^:=UNKNOW_CHAR_A;
  704. Result:=1;
  705. end;
  706. end;
  707. var
  708. hp : punicodemap;
  709. initialization
  710. mappings:=nil;
  711. finalization
  712. while assigned(mappings) do
  713. begin
  714. hp:=mappings^.next;
  715. if not(mappings^.internalmap) then
  716. begin
  717. freemem(mappings^.map);
  718. freemem(mappings^.reversemap);
  719. dispose(mappings);
  720. end;
  721. mappings:=hp;
  722. end;
  723. end.