charset.pp 22 KB

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