12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2014-2015 by Tomas Hajny and other members
- of the Free Pascal development team.
- OS/2 UnicodeStrings support
- 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.
- **********************************************************************}
- (* The implementation is based on native Unicode support available under
- OS/2 Warp 4 and above; if running under OS/2 Warp 3 and UCONV.DLL
- library is not available, this implementation will resort to dummy
- routines. This still allows providing 3rd party implementation based
- e.g. on the ICONV library as an external unit.
- *)
- const
- MaxSpecialCPTranslation = 2;
- MaxNonEqualCPMapping = 35;
- MaxCPMapping = 76;
- CpxAll = 0;
- CpxSpecial = 1;
- CpxMappingOnly = 2;
- Uls_Success = 0;
- Uls_API_Error_Base = $20400;
- Uls_Other = $20401;
- Uls_IllegalSequence = $20402;
- Uls_MaxFilesPerProc = $20403;
- Uls_MaxFiles = $20404;
- Uls_NoOp = $20405;
- Uls_TooManyKbd = $20406;
- Uls_KbdNotFound = $20407;
- Uls_BadHandle = $204008;
- Uls_NoDead = $20409;
- Uls_NoScan = $2040A;
- Uls_InvalidScan = $2040B;
- Uls_NotImplemented = $2040C;
- Uls_NoMemory = $2040D;
- Uls_Invalid = $2040E;
- Uls_BadObject = $2040F;
- Uls_NoToken = $20410;
- Uls_NoMatch = $20411;
- Uls_BufferFull = $20412;
- Uls_Range = $20413;
- Uls_Unsupported = $20414;
- Uls_BadAttr = $20415;
- Uls_Version = $20416;
- UConvName: array [0..5] of char = 'UCONV'#0;
- OrdUniCreateUconvObject = 1;
- OrdUniUconvToUcs = 2;
- OrdUniUconvFromUcs = 3;
- OrdUniFreeUconvObject = 4;
- OrdUniQueryUconvObject = 7;
- OrdUniSetUconvObject = 8;
- OrdUniQueryUconvCp = 9;
- OrdUniMapCpToUcsCp = 10;
- OrdUniStrFromUcs = 11;
- OrdUniStrToUcs = 12;
- Ord_UniMalloc = 13;
- Ord_UniFree = 14;
- LibUniName: array [0..6] of char = 'LIBUNI'#0;
- OrdUniQueryXdigit = 1;
- OrdUniQuerySpace = 2;
- OrdUniQueryPrint = 3;
- OrdUniQueryGraph = 4;
- OrdUniQueryCntrl = 5;
- OrdUniQueryAlpha = 6;
- OrdUniFreeAttrObject = 7;
- OrdUniQueryCharAttr = 8;
- OrdUniQueryUpper = 9;
- OrdUniQueryPunct = 10;
- OrdUniQueryLower = 11;
- OrdUniQueryDigit = 12;
- OrdUniQueryBlank = 13;
- OrdUniQueryAlnum = 14;
- OrdUniScanForAttr = 15;
- OrdUniCreateAttrObject = 16;
- OrdUniCreateTransformObject = 17;
- OrdUniFreeTransformObject = 18;
- OrdUniQueryLocaleObject = 19;
- OrdUniCreateLocaleObject = 20;
- OrdUniFreeLocaleObject = 21;
- OrdUniFreeMem = 22;
- OrdUniFreeLocaleInfo = 28;
- OrdUniQueryLocaleInfo = 29;
- OrdUniQueryLocaleItem = 30;
- OrdUniStrcat = 31;
- OrdUniStrchr = 32;
- OrdUniStrcmp = 33;
- OrdUniStrcmpi = 34;
- OrdUniStrColl = 35;
- OrdUniStrcpy = 36;
- OrdUniStrcspn = 37;
- OrdUniStrfmon = 38;
- OrdUniStrftime = 39;
- OrdUniStrlen = 40;
- OrdUniStrncat = 41;
- OrdUniStrncmp = 42;
- OrdUniStrncmpi = 43;
- OrdUniStrncpy = 44;
- OrdUniStrpbrk = 45;
- OrdUniStrptime = 46;
- OrdUniStrrchr = 47;
- OrdUniStrspn = 48;
- OrdUniStrstr = 49;
- OrdUniStrtod = 50;
- OrdUniStrtol = 51;
- OrdUniStrtoul = 52;
- OrdUniStrxfrm = 53;
- OrdUniLocaleStrToToken = 54;
- OrdUniLocaleTokenToStr = 55;
- OrdUniTransformStr = 56;
- OrdUniTransLower = 57;
- OrdUniTransUpper = 58;
- OrdUniTolower = 59;
- OrdUniToupper = 60;
- OrdUniStrupr = 61;
- OrdUniStrlwr = 62;
- OrdUniStrtok = 63;
- OrdUniMapCtryToLocale = 67;
- OrdUniMakeKey = 70;
- OrdUniQueryChar = 71;
- OrdUniGetOverride = 72;
- OrdUniGetColval = 73;
- OrdUniQueryAttr = 74;
- OrdUniQueryStringType = 75;
- OrdUniQueryCharType = 76;
- OrdUniQueryNumericValue = 77;
- OrdUniQueryCharTypeTable = 78;
- OrdUniProcessUconv = 80;
- OrdLocale = 151;
- OrdUniMakeUserLocale = 152;
- OrdUniSetUserLocaleItem = 153;
- OrdUniDeleteUserLocale = 154;
- OrdUniCompleteUserLocale = 155;
- OrdUniQueryLocaleValue = 156;
- OrdUniQueryLocaleList = 157;
- OrdUniQueryLanguageName = 158;
- OrdUniQueryCountryName = 159;
- Uni_Token_Pointer = 1;
- Uni_MBS_String_Pointer = 2;
- Uni_UCS_String_Pointer = 3;
- Uni_System_Locales = 1;
- Uni_User_Locales = 2;
- WNull: WideChar = #0;
- WUniv: array [0..4] of WideChar = 'UNIV'#0;
- type
- (* CP_UTF16 should be in exceptions too, because OS/2 supports only UCS2 *)
- (* rather than UTF-16 - ignored at least for now. *)
- (* ExceptionWinCodepages = (CP_UTF16BE, CP_UTF7, 12000 {UTF32}, 12001 {UTF32BE});
- SpecialWinCodepages = (CP_UTF8, CP_ASCII);*)
- TCpRec = record
- WinCP: TSystemCodepage;
- OS2CP: word;
- UConvObj: TUConvObject;
- end;
- TCpXList = array [1..MaxCPMapping] of TCpRec;
- TDummyUConvObject = record
- CP: cardinal;
- CPNameLen: byte;
- CPName: record end;
- end;
- PDummyUConvObject = ^TDummyUConvObject;
- var
- DBCSLeadRanges: array [0..11] of char;
- CollationSequence: array [char] of char;
- const
- DefCpRec: TCpRec = (WinCP: 0; OS2CP: 0; UConvObj: nil);
- InInitDefaultCP: int64 = -1; (* Range is bigger than TThreadID to avoid conflict *)
- DefLocObj: TLocaleObject = nil;
- IBMPrefix: packed array [1..4] of WideChar = 'IBM-';
- CachedDefFSCodepage: TSystemCodepage = 0;
- EmptyCC: TCountryCode = (Country: 0; Codepage: 0); (* Empty = current *)
- (* 819 = IBM codepage number for ISO 8859-1 used in FPC default *)
- (* dummy translation between UnicodeString and AnsiString. *)
- IsoCC: TCountryCode = (Country: 1; Codepage: 819); (* US with ISO 8859-1 *)
- (* The following two arrays are initialized on startup in case that *)
- (* Dummy* routines must be used. First for current codepage... *)
- DBCSLeadRangesEnd: byte = 0;
- LowerChars: array [char] of char =
- (#0, #1, #2, #3, #4, #5, #6, #7, #8, #9, #10, #11, #12, #13, #14, #15, #16,
- #17, #18, #19, #20, #21, #22, #23, #24, #25, #26, #27, #28, #29, #30, #31,
- #32, #33, #34, #35, #36, #37, #38, #39, #40, #41, #42, #43, #44, #45, #46,
- #47, #48, #49, #50, #51, #52, #53, #54, #55, #56, #57, #58, #59, #60, #61,
- #62, #63, #64, #65, #66, #67, #68, #69, #70, #71, #72, #73, #74, #75, #76,
- #77, #78, #79, #80, #81, #82, #83, #84, #85, #86, #87, #88, #89, #90, #91,
- #92, #93, #94, #95, #96, #97, #98, #99, #100, #101, #102, #103, #104, #105,
- #106, #107, #108, #109, #110, #111, #112, #113, #114, #115, #116, #117,
- #118, #119, #120, #121, #122, #123, #124, #125, #126, #127, #128, #129,
- #130, #131, #132, #133, #134, #135, #136, #137, #138, #139, #140, #141,
- #142, #143, #144, #145, #146, #147, #148, #149, #150, #151, #152, #153,
- #154, #155, #156, #157, #158, #159, #160, #161, #162, #163, #164, #165,
- #166, #167, #168, #169, #170, #171, #172, #173, #174, #175, #176, #177,
- #178, #179, #180, #181, #182, #183, #184, #185, #186, #187, #188, #189,
- #190, #191, #192, #193, #194, #195, #196, #197, #198, #199, #200, #201,
- #202, #203, #204, #205, #206, #207, #208, #209, #210, #211, #212, #213,
- #214, #215, #216, #217, #218, #219, #220, #221, #222, #223, #224, #225,
- #226, #227, #228, #229, #230, #231, #232, #233, #234, #235, #236, #237,
- #238, #239, #240, #241, #242, #243, #244, #245, #246, #247, #248, #249,
- #250, #251, #252, #253, #254, #255);
- (* ...and now for ISO 8859-1 aka IBM codepage 819 *)
- LowerCharsISO88591: array [char] of char =
- (#0, #1, #2, #3, #4, #5, #6, #7, #8, #9, #10, #11, #12, #13, #14, #15, #16,
- #17, #18, #19, #20, #21, #22, #23, #24, #25, #26, #27, #28, #29, #30, #31,
- #32, #33, #34, #35, #36, #37, #38, #39, #40, #41, #42, #43, #44, #45, #46,
- #47, #48, #49, #50, #51, #52, #53, #54, #55, #56, #57, #58, #59, #60, #61,
- #62, #63, #64, #65, #66, #67, #68, #69, #70, #71, #72, #73, #74, #75, #76,
- #77, #78, #79, #80, #81, #82, #83, #84, #85, #86, #87, #88, #89, #90, #91,
- #92, #93, #94, #95, #96, #97, #98, #99, #100, #101, #102, #103, #104, #105,
- #106, #107, #108, #109, #110, #111, #112, #113, #114, #115, #116, #117,
- #118, #119, #120, #121, #122, #123, #124, #125, #126, #127, #128, #129,
- #130, #131, #132, #133, #134, #135, #136, #137, #138, #139, #140, #141,
- #142, #143, #144, #145, #146, #147, #148, #149, #150, #151, #152, #153,
- #154, #155, #156, #157, #158, #159, #160, #161, #162, #163, #164, #165,
- #166, #167, #168, #169, #170, #171, #172, #173, #174, #175, #176, #177,
- #178, #179, #180, #181, #182, #183, #184, #185, #186, #187, #188, #189,
- #190, #191, #192, #193, #194, #195, #196, #197, #198, #199, #200, #201,
- #202, #203, #204, #205, #206, #207, #208, #209, #210, #211, #212, #213,
- #214, #215, #216, #217, #218, #219, #220, #221, #222, #223, #224, #225,
- #226, #227, #228, #229, #230, #231, #232, #233, #234, #235, #236, #237,
- #238, #239, #240, #241, #242, #243, #244, #245, #246, #247, #248, #249,
- #250, #251, #252, #253, #254, #255);
- NoIso88591Support: boolean = false;
- threadvar
- (* Temporary allocations may be performed in parallel in different threads *)
- TempCpRec: TCpRec;
- function OS2GetStandardCodePage (const stdcp: TStandardCodePageEnum): TSystemCodePage;
- var
- RC, C, RetSize: cardinal;
- NoUConvObject: TUConvObject;
- begin
- RC := DosQueryCP (SizeOf (C), @C, RetSize);
- if (RC <> 0) and (RC <> 473) then
- begin
- OSErrorWatch (RC);
- C := 850;
- end
- else
- if RetSize < SizeOf (C) then
- C := 850;
- OS2GetStandardCodePage := OS2CpToRtlCp (C, cpxMappingOnly, NoUConvObject);
- end;
- function DummyUniCreateUConvObject (const CpName: PWideChar;
- var UConv_Object: TUConvObject): longint; cdecl;
- var
- P: pointer;
- PW, PCPN: PWideChar;
- S: string [20];
- C: cardinal;
- L: PtrInt;
- I: longint;
- A: array [0..7] of char;
- CPN2: UnicodeString;
- RC, RetSize: cardinal;
- begin
- UConv_Object := nil;
- if (CpName = nil) or (CpName^ = #0) then
- begin
- RC := DosQueryCP (SizeOf (C), @C, RetSize);
- if (RC <> 0) and (RC <> 473) then
- begin
- C := 850;
- OSErrorWatch (RC);
- end;
- Str (C, CPN2); (* Str should hopefully not use this function recurrently *)
- L := Length (CPN2);
- Insert (IBMPrefix, CPN2, 1);
- PCPN := @CPN2 [1];
- end
- else
- begin
- PCPN := CpName;
- for I := 0 to 7 do
- if I mod 2 = 0 then
- A [I] := UpCase (PChar (@PCPN [0]) [I])
- else
- A [I] := PChar (@PCPN [0]) [I];
- if PQWord (@A)^ <> PQWord (@IBMPrefix)^ then
- begin
- DummyUniCreateUConvObject := Uls_Invalid;
- Exit;
- end;
- L := 0;
- PW := PCPN + 4;
- while ((PW + L)^ <> #0) and (L <= SizeOf (S)) do
- begin
- S [Succ (L)] := char (Ord ((PW + L)^));
- Inc (L);
- end;
- if L > SizeOf (S) then
- begin
- DummyUniCreateUConvObject := Uls_Other;
- Exit;
- end;
- SetLength (S, L);
- Val (S, C, I);
- if I <> 0 then
- begin
- DummyUniCreateUConvObject := Uls_Invalid;
- Exit;
- end;
- end;
- Inc (L);
- GetMem (P, SizeOf (TDummyUConvObject) + (L + 4) * 2);
- if P = nil then
- DummyUniCreateUConvObject := Uls_NoMemory
- else
- begin
- DummyUniCreateUConvObject := Uls_Success;
- PDummyUConvObject (P)^.CP := C;
- PDummyUConvObject (P)^.CpNameLen := Pred (L) + 4;
- Move (PCPN [0], PDummyUConvObject (P)^.CpName, (L + 4) * 2);
- UConv_Object := TUConvObject (P);
- end;
- end;
- function DummyUniFreeUConvObject (UConv_Object: TUConvObject): longint; cdecl;
- begin
- if UConv_Object <> nil then
- FreeMem (UConv_Object, SizeOf (TDummyUConvObject) +
- Succ (PDummyUConvObject (UConv_Object)^.CpNameLen) * 2);
- DummyUniFreeUConvObject := Uls_Success;
- end;
- function DummyUniMapCpToUcsCp (const Codepage: cardinal;
- CodepageName: PWideChar; const N: cardinal): longint; cdecl;
- var
- S: UnicodeString;
- RC, CP, RetSize: cardinal;
- begin
- if Codepage = 0 then
- begin
- RC := DosQueryCP (SizeOf (CP), @CP, RetSize);
- if (RC <> 0) and (RC <> 473) then
- begin
- CP := 850;
- OSErrorWatch (RC);
- end;
- Str (CP, S);
- end
- else
- Str (Codepage, S);
- if (N <= Length (S) + 4) or (CodepageName = nil) then
- DummyUniMapCptoUcsCp := Uls_Invalid
- else
- begin
- Move (IBMPrefix, CodepageName^, SizeOf (IBMPrefix));
- Move (S [1], CodepageName [4], Length (S) * SizeOf (WideChar));
- CodepageName [Length (S) + 4] := #0;
- DummyUniMapCpToUcsCp := Uls_Success;
- end;
- end;
- function DummyUniUConvFromUcs (UConv_Object: TUConvObject;
- var UcsBuf: PWideChar; var UniCharsLeft: longint; var OutBuf: PChar;
- var OutBytesLeft: longint; var NonIdentical: longint): longint; cdecl;
- var
- Dest, Dest2: RawByteString;
- NoUConvObj: TUConvObject;
- RtlCp: TSystemCodepage;
- UcsLen: PtrInt;
- begin
- if UConv_Object = nil then
- RtlCp := OS2GetStandardCodePage (scpAnsi)
- else
- RtlCp := OS2CpToRtlCp (PDummyUConvObject (UConv_Object)^.CP, cpxMappingOnly,
- NoUConvObj);
- DefaultUnicode2AnsiMove (UcsBuf, Dest, RtlCp, UniCharsLeft);
- NonIdentical := 1; { Assume at least one substitution with dummy implementation }
- if Length (Dest) > OutBytesLeft then
- begin
- UcsLen := 1;
- repeat
- DefaultUnicode2AnsiMove (UcsBuf, Dest2, RtlCp, UcsLen);
- if Length (Dest2) <= OutBytesLeft then
- begin
- Dest := Dest2;
- end;
- Inc (UcsLen);
- until Length (Dest2) > OutBytesLeft;
- Dec (UcsLen);
- Inc (UcsBuf, UcsLen);
- Dec (UniCharsLeft, UcsLen);
- DummyUniUConvFromUcs := Uls_BufferFull;
- end
- else
- begin
- Inc (UcsBuf, UniCharsLeft);
- UniCharsLeft := 0;
- DummyUniUConvFromUcs := Uls_Success;
- end;
- Move (Dest [1], OutBuf^, Length (Dest));
- Inc (OutBuf, Length (Dest));
- Dec (OutBytesLeft, Length (Dest));
- end;
- function DummyUniUConvToUcs (UConv_Object: TUConvObject; var InBuf: PChar;
- var InBytesLeft: longint; var UcsBuf: PWideChar; var UniCharsLeft: longint;
- var NonIdentical: longint): longint; cdecl;
- var
- Dest, Dest2: UnicodeString;
- NoUConvObj: TUConvObject;
- RtlCp: TSystemCodepage;
- SrcLen: PtrInt;
- begin
- if UConv_Object = nil then
- RtlCp := OS2GetStandardCodePage (scpAnsi)
- else
- RtlCp := OS2CpToRtlCp (PDummyUConvObject (UConv_Object)^.CP, cpxMappingOnly,
- NoUConvObj);
- DefaultAnsi2UnicodeMove (InBuf, RtlCp, Dest, InBytesLeft);
- NonIdentical := 0; { Assume no need for substitutions in this direction }
- if Length (Dest) > UniCharsLeft then
- begin
- SrcLen := 1;
- repeat
- DefaultAnsi2UnicodeMove (InBuf, RtlCp, Dest2, SrcLen);
- if Length (Dest2) <= UniCharsLeft then
- begin
- Dest := Dest2;
- end;
- Inc (SrcLen);
- until Length (Dest2) > UniCharsLeft;
- Dec (SrcLen);
- Inc (InBuf, SrcLen);
- Dec (InBytesLeft, SrcLen);
- DummyUniUConvToUcs := Uls_BufferFull; { According to IBM documentation Uls_Invalid and not Uls_BufferFull is returned by UniUConvFromUcs?! }
- end
- else
- begin
- Inc (InBuf, InBytesLeft); { Shall it be increased in case of success too??? }
- InBytesLeft := 0;
- DummyUniUConvToUcs := Uls_Success;
- end;
- Move (Dest [1], UcsBuf^, Length (Dest) * 2);
- Inc (UcsBuf, Length (Dest)); { Shall it be increased in case of success too??? }
- Dec (UniCharsLeft, Length (Dest));
- end;
- function DummyUniMapCtryToLocale (CountryCode: cardinal; LocaleName: PWideChar;
- BufSize: longint): longint; cdecl;
- begin
- if BufSize = 0 then
- DummyUniMapCtryToLocale := Uls_Invalid
- else
- begin
- LocaleName^ := #0;
- DummyUniMapCtryToLocale := Uls_Unsupported;
- end;
- end;
- procedure InitDBCSLeadRanges;
- var
- RC: cardinal;
- begin
- RC := DosQueryDBCSEnv (SizeOf (DBCSLeadRanges), EmptyCC,
- @DBCSLeadRanges [0]);
- DBCSLeadRangesEnd := 0;
- if RC <> 0 then
- while (DBCSLeadRangesEnd < SizeOf (DBCSLeadRanges)) and
- ((DBCSLeadRanges [DBCSLeadRangesEnd] <> #0) or
- (DBCSLeadRanges [Succ (DBCSLeadRangesEnd)] <> #0)) do
- Inc (DBCSLeadRangesEnd, 2);
- end;
- procedure InitDummyAnsiSupport;
- var
- C: char;
- AllChars: array [char] of char;
- RetSize: cardinal;
- begin
- if DosQueryCollate (SizeOf (CollationSequence), EmptyCC, @CollationSequence,
- RetSize) <> 0 then
- Move (LowerChars, CollationSequence, SizeOf (CollationSequence));
- Move (LowerChars, AllChars, SizeOf (AllChars));
- if DosMapCase (SizeOf (AllChars), IsoCC, @AllChars [#0]) <> 0 then
- (* Codepage 819 may not be supported in all old OS/2 versions. *)
- begin
- Move (LowerCharsIso88591, AllChars, SizeOf (AllChars));
- DosMapCase (SizeOf (AllChars), EmptyCC, @AllChars [#0]);
- NoIso88591Support := true;
- end;
- for C := Low (char) to High (char) do
- if AllChars [C] <> C then
- LowerCharsIso88591 [AllChars [C]] := C;
- if NoIso88591Support then
- Move (LowerCharsIso88591, LowerChars, SizeOf (LowerChars))
- else
- begin
- Move (LowerChars, AllChars, SizeOf (AllChars));
- DosMapCase (SizeOf (AllChars), EmptyCC, @AllChars [#0]);
- for C := Low (char) to High (char) do
- if AllChars [C] <> C then
- LowerChars [AllChars [C]] := C;
- end;
- InitDBCSLeadRanges;
- end;
- procedure ReInitDummyAnsiSupport;
- var
- C: char;
- AllChars: array [char] of char;
- RetSize: cardinal;
- begin
- for C := Low (char) to High (char) do
- AllChars [C] := C;
- if DosQueryCollate (SizeOf (CollationSequence), EmptyCC, @CollationSequence,
- RetSize) <> 0 then
- Move (AllChars, CollationSequence, SizeOf (CollationSequence));
- DosMapCase (SizeOf (AllChars), EmptyCC, @AllChars [#0]);
- for C := Low (char) to High (char) do
- if AllChars [C] <> C then
- LowerChars [AllChars [C]] := C;
- InitDBCSLeadRanges;
- end;
- function DummyUniToLower (UniCharIn: WideChar): WideChar; cdecl;
- var
- C: char;
- begin
- C := UniCharIn;
- DummyUniToLower := LowerCharsIso88591 [C];
- end;
- function DummyUniToUpper (UniCharIn: WideChar): WideChar; cdecl;
- var
- C: char;
- begin
- DummyUniToUpper := UniCharIn;
- C := UniCharIn;
- if NoIso88591Support then
- begin
- if DosMapCase (1, EmptyCC, @C) = 0 then
- DummyUniToUpper := C;
- end
- else
- if DosMapCase (1, IsoCC, @C) = 0 then
- DummyUniToUpper := C
- end;
- function DummyUniStrColl (Locale_Object: TLocaleObject;
- const UCS1, UCS2: PWideChar): longint; cdecl;
- var
- S1, S2: ansistring;
- begin
- S1 := UCS1;
- S2 := UCS2;
- if S1 = S2 then
- DummyUniStrColl := 0
- else if S1 < S2 then
- DummyUniStrColl := -1
- else
- DummyUniStrColl := 1;
- end;
- function DummyUniCreateLocaleObject (LocaleSpecType: longint;
- const LocaleSpec: pointer; var Locale_Object: TLocaleObject): longint; cdecl;
- begin
- DummyUniCreateLocaleObject := ULS_Unsupported;
- end;
- function DummyUniFreeLocaleObject (Locale_Object: TLocaleObject): longint;
- cdecl;
- begin
- DummyUniFreeLocaleObject := ULS_BadObject;
- end;
- const
- CpXList: TCpXList = (
- (WinCP: CP_UTF8; OS2CP: 1208; UConvObj: nil),
- (WinCP: CP_ASCII; OS2CP: 367; UConvObj: nil),
- (WinCP: 28597; OS2CP: 813; UConvObj: nil),
- (WinCP: 28591; OS2CP: 819; UConvObj: nil),
- (WinCP: 28592; OS2CP: 912; UConvObj: nil),
- (WinCP: 28593; OS2CP: 913; UConvObj: nil),
- (WinCP: 28594; OS2CP: 914; UConvObj: nil),
- (WinCP: 28595; OS2CP: 915; UConvObj: nil),
- (WinCP: 28598; OS2CP: 916; UConvObj: nil),
- (WinCP: 28599; OS2CP: 920; UConvObj: nil),
- (WinCP: 28603; OS2CP: 921; UConvObj: nil),
- (WinCP: 28605; OS2CP: 923; UConvObj: nil),
- (WinCP: 10000; OS2CP: 1275; UConvObj: nil),
- (WinCP: 10006; OS2CP: 1280; UConvObj: nil),
- (WinCP: 10081; OS2CP: 1281; UConvObj: nil),
- (WinCP: 10029; OS2CP: 1282; UConvObj: nil),
- (WinCP: 10007; OS2CP: 1283; UConvObj: nil),
- (WinCP: 20273; OS2CP: 273; UConvObj: nil),
- (WinCP: 20277; OS2CP: 277; UConvObj: nil),
- (WinCP: 20278; OS2CP: 278; UConvObj: nil),
- (WinCP: 20280; OS2CP: 280; UConvObj: nil),
- (WinCP: 20284; OS2CP: 284; UConvObj: nil),
- (WinCP: 20285; OS2CP: 285; UConvObj: nil),
- (WinCP: 20290; OS2CP: 290; UConvObj: nil),
- (WinCP: 20297; OS2CP: 297; UConvObj: nil),
- (WinCP: 20420; OS2CP: 420; UConvObj: nil),
- (WinCP: 20424; OS2CP: 424; UConvObj: nil),
- (WinCP: 20833; OS2CP: 833; UConvObj: nil),
- (WinCP: 20838; OS2CP: 838; UConvObj: nil),
- (WinCP: 20866; OS2CP: 878; UConvObj: nil),
- (WinCP: 737; OS2CP: 851; UConvObj: nil),
- (WinCP: 20924; OS2CP: 924; UConvObj: nil),
- (WinCP: 20932; OS2CP: 932; UConvObj: nil),
- (WinCP: 20936; OS2CP: 936; UConvObj: nil),
- (WinCP: 21025; OS2CP: 1025; UConvObj: nil),
- (WinCP: CP_UTF16; OS2CP: CP_UTF16; UConvObj: nil),
- (WinCP: 37; OS2CP: 37; UConvObj: nil),
- (WinCP: 437; OS2CP: 437; UConvObj: nil),
- (WinCP: 500; OS2CP: 500; UConvObj: nil),
- (WinCP: 850; OS2CP: 850; UConvObj: nil),
- (WinCP: 852; OS2CP: 852; UConvObj: nil),
- (WinCP: 855; OS2CP: 855; UConvObj: nil),
- (WinCP: 857; OS2CP: 857; UConvObj: nil),
- (WinCP: 860; OS2CP: 860; UConvObj: nil),
- (WinCP: 861; OS2CP: 861; UConvObj: nil),
- (WinCP: 862; OS2CP: 862; UConvObj: nil),
- (WinCP: 863; OS2CP: 863; UConvObj: nil),
- (WinCP: 864; OS2CP: 864; UConvObj: nil),
- (WinCP: 865; OS2CP: 865; UConvObj: nil),
- (WinCP: 866; OS2CP: 866; UConvObj: nil),
- (WinCP: 869; OS2CP: 869; UConvObj: nil),
- (WinCP: 870; OS2CP: 870; UConvObj: nil),
- (WinCP: 874; OS2CP: 874; UConvObj: nil),
- (WinCP: 875; OS2CP: 875; UConvObj: nil),
- (WinCP: 949; OS2CP: 949; UConvObj: nil),
- (WinCP: 950; OS2CP: 950; UConvObj: nil),
- (WinCP: 1026; OS2CP: 1026; UConvObj: nil),
- (WinCP: 1047; OS2CP: 1047; UConvObj: nil),
- (WinCP: 1140; OS2CP: 1140; UConvObj: nil),
- (WinCP: 1141; OS2CP: 1141; UConvObj: nil),
- (WinCP: 1142; OS2CP: 1142; UConvObj: nil),
- (WinCP: 1143; OS2CP: 1143; UConvObj: nil),
- (WinCP: 1144; OS2CP: 1144; UConvObj: nil),
- (WinCP: 1145; OS2CP: 1145; UConvObj: nil),
- (WinCP: 1146; OS2CP: 1146; UConvObj: nil),
- (WinCP: 1147; OS2CP: 1147; UConvObj: nil),
- (WinCP: 1148; OS2CP: 1148; UConvObj: nil),
- (WinCP: 1149; OS2CP: 1149; UConvObj: nil),
- (WinCP: 1250; OS2CP: 1250; UConvObj: nil),
- (WinCP: 1251; OS2CP: 1251; UConvObj: nil),
- (WinCP: 1252; OS2CP: 1252; UConvObj: nil),
- (WinCP: 1253; OS2CP: 1253; UConvObj: nil),
- (WinCP: 1254; OS2CP: 1254; UConvObj: nil),
- (WinCP: 1255; OS2CP: 1255; UConvObj: nil),
- (WinCP: 1256; OS2CP: 1256; UConvObj: nil),
- (WinCP: 1257; OS2CP: 1257; UConvObj: nil)
- );
- (* Possibly add index tables for both directions and binary search??? *)
- {
- function GetRtlCpFromCpRec (const CpRec: TCpRec): TSystemCodepage; inline;
- begin
- if RtlUsesWinCp then
- GetRtlCp := CpRec.WinCP
- else
- GetRtlCp := TSystemCodepage (CpRec.Os2Cp);
- end;
- }
- function UConvObjectForCP (CP: cardinal; var UConvObj: TUConvObject): longint;
- var
- RC: longint;
- A: array [0..12] of WideChar;
- begin
- UConvObj := nil;
- RC := Sys_UniMapCpToUcsCp (CP, @A, 12);
- if RC = 0 then
- RC := Sys_UniCreateUconvObject (@A, UConvObj);
- {$WARNING: TODO: Deallocate some previously allocated UConvObj and try again if failed}
- UConvObjectForCP := RC;
- if RC <> 0 then
- OSErrorWatch (RC);
- end;
- procedure InitDefaultCP;
- var
- OS2CP, I: cardinal;
- NoUConvObj: TUConvObject;
- RCI: longint;
- RC: cardinal;
- CPArr: TCPArray;
- ReturnedSize: cardinal;
- WA: array [0..9] of WideChar; (* Even just 6 WideChars should be enough *)
- CI: TCountryInfo;
- begin
- if InInitDefaultCP <> -1 then
- begin
- repeat
- DosSleep (5);
- until InInitDefaultCP <> -1;
- Exit;
- end;
- InInitDefaultCP := ThreadID;
- if DefCpRec.UConvObj <> nil then
- begin
- (* Do not free the UConv object from DefCpRec, because it is also stored in
- the respective CPXList record! *)
- {
- RCI := Sys_UniFreeUConvObject (DefCpRec.UConvObj);
- if RCI <> 0 then
- OSErrorWatch (cardinal (RCI));
- }
- DefCpRec.UConvObj := nil;
- end;
- RC := DosQueryCP (SizeOf (CPArr), @CPArr, ReturnedSize);
- if (RC <> 0) and (RC <> 473) then
- begin
- OSErrorWatch (RC);
- CPArr [0] := 850;
- end
- else if (ReturnedSize < 4) then
- CPArr [0] := 850;
- DefaultFileSystemCodePage := OS2CPtoRtlCP (CPArr [0], cpxAll,
- DefCpRec.UConvObj);
- CachedDefFSCodepage := DefaultFileSystemCodePage;
- DefCpRec.OS2CP := CPArr [0];
- (* Find out WinCP _without_ considering RtlUsesWinCP *)
- I := 1;
- while (I <= MaxNonEqualCPMapping) and (CpXList [I].OS2CP <> DefCpRec.OS2CP)
- do
- Inc (I);
- if CpXList [I].OS2CP = CPArr [0] then
- DefCpRec.WinCP := CpXList [I].WinCP
- else
- DefCpRec.WinCP := CPArr [0];
- if DefLocObj <> nil then
- begin
- RCI := Sys_UniFreeLocaleObject (DefLocObj);
- if RCI <> 0 then
- OSErrorWatch (cardinal (RCI));
- DefLocObj := nil;
- end;
- if UniAPI then (* Do not bother with the locale object otherwise *)
- begin
- RCI := Sys_UniCreateLocaleObject (Uni_UCS_String_Pointer, @WNull, DefLocObj);
- if RCI <> 0 then
- begin
- OSErrorWatch (cardinal (RCI));
- DefLocObj := nil;
- (* The locale dependent routines like comparison require a valid locale *)
- (* setting, but the locale set using environment variable LANG is not *)
- (* recognized by OS/2 -> let's try to derive the locale from country *)
- RC := DosQueryCtryInfo (SizeOf (CI), EmptyCC, CI, ReturnedSize);
- if RC = 0 then
- begin
- RCI := Sys_UniMapCtryToLocale (CI.Country, @WA [0],
- SizeOf (WA) div SizeOf (WideChar));
- if RCI = 0 then
- begin
- RCI := Sys_UniCreateLocaleObject (Uni_UCS_String_Pointer, @WA [0],
- DefLocObj);
- if RCI <> 0 then
- begin
- OSErrorWatch (cardinal (RCI));
- DefLocObj := nil;
- end;
- end
- else
- OSErrorWatch (cardinal (RCI));
- end
- else
- OSErrorWatch (RC);
- if DefLocObj = nil then
- (* Still no success -> let's use the "Universal" locale as a fallback. *)
- begin
- RCI := Sys_UniCreateLocaleObject (Uni_UCS_String_Pointer, @WUniv [0],
- DefLocObj);
- if RCI <> 0 then
- begin
- OSErrorWatch (cardinal (RCI));
- DefLocObj := nil;
- end;
- end;
- end;
- end
- else (* not UniAPI *)
- ReInitDummyAnsiSupport;
- InInitDefaultCP := -1;
- end;
- function OS2CPtoRtlCP (CP: cardinal; ReqFlags: byte;
- var UConvObj: TUConvObject): TSystemCodepage;
- var
- I, I2: cardinal;
- RCI: longint;
- function CheckDefaultOS2CP: boolean;
- begin
- if CP = DefCpRec.OS2CP then
- begin
- CheckDefaultOS2CP := true;
- if RTLUsesWinCP then
- OS2CPtoRtlCP := DefCpRec.WinCP;
- if ReqFlags and CpxMappingOnly = 0 then
- UConvObj := DefCpRec.UConvObj;
- end
- else
- CheckDefaultOS2CP := false;
- end;
- begin
- OS2CPtoRtlCP := TSystemCodePage (CP);
- UConvObj := nil;
- if not UniAPI then (* No UniAPI => no need for UConvObj *)
- ReqFlags := ReqFlags or CpxMappingOnly;
- if CheckDefaultOS2CP then
- Exit;
- if (CachedDefFSCodepage <> DefaultFileSystemCodePage) and
- (InInitDefaultCP <> ThreadID) then
- (* InInitDefaultCP = ThreadID -> this thread is already re-initializing the cached information *)
- begin
- if InInitDefaultCP <> -1 then
- repeat
- DosSleep (5) (* Let's wait until the other thread finishes re-initialization of the cache *)
- until InInitDefaultCP = -1
- else
- InitDefaultCP;
- if CheckDefaultOS2CP then
- Exit;
- end;
- I := 1;
- if ReqFlags and CpxSpecial = CpxSpecial then
- I2 := 2
- else
- if ReqFlags and CpxMappingOnly = CpxMappingOnly then
- I2 := MaxNonEqualCPMapping
- else
- I2 := MaxCPMapping;
- while I <= I2 do
- begin
- if CP = CpXList [I].OS2CP then
- begin
- if RTLUsesWinCP then
- OS2CPtoRtlCP := CpXList [I].WinCP;
- if ReqFlags and CpxMappingOnly = 0 then
- begin
- if CpXList [I].UConvObj = nil then
- begin
- if UConvObjectForCP (CpXList [I].OS2CP, UConvObj) = Uls_Success then
- CpXList [I].UConvObj := UConvObj
- else
- UConvObj := nil;
- end
- else
- UConvObj := CpXList [I].UConvObj;
- end;
- Exit;
- end;
- Inc (I);
- end;
- (* If codepage was not found in the translation table and UConvObj is
- requested, allocate one in the temporary record. *)
- if ReqFlags and CpxMappingOnly = 0 then
- begin
- if TempCpRec.OS2CP = CP then
- UConvObj := TempCpRec.UConvObj
- else
- begin
- if TempCpRec.UConvObj <> nil then
- begin
- RCI := Sys_UniFreeUConvObject (TempCpRec.UConvObj);
- if RCI <> 0 then
- OSErrorWatch (cardinal (RCI));
- TempCpRec.UConvObj := nil;
- end;
- if UConvObjectForCP (CP, UConvObj) = Uls_Success then
- begin
- TempCpRec.UConvObj := UConvObj;
- TempCpRec.OS2CP := CP;
- end
- else
- UConvObj := nil;
- end;
- end;
- end;
- function RtlCPtoOS2CP (RtlCP: TSystemCodepage; ReqFlags: byte;
- var UConvObj: TUConvObject): cardinal;
- var
- I, I2: cardinal;
- function CheckDefaultWinCP: boolean;
- begin
- if RtlCP = DefCpRec.WinCP then
- begin
- CheckDefaultWinCP := true;
- RtlCPtoOS2CP := DefCpRec.WinCP;
- if ReqFlags and CpxMappingOnly = 0 then
- UConvObj := DefCpRec.UConvObj;
- end
- else
- CheckDefaultWinCP := false;
- end;
- begin
- RtlCPtoOS2CP := RtlCP;
- UConvObj := nil;
- if not UniAPI then (* No UniAPI => no need for UConvObj *)
- ReqFlags := ReqFlags or CpxMappingOnly;
- if not (RTLUsesWinCP) then
- begin
- if ReqFlags and CpxMappingOnly = 0 then
- OS2CPtoRtlCP (cardinal (RtlCp), ReqFlags, UConvObj);
- end
- else if CheckDefaultWinCp then
- Exit
- else
- begin
- if (CachedDefFSCodepage <> DefaultFileSystemCodePage) and
- (InInitDefaultCP <> ThreadID) then
- (* InInitDefaultCP = ThreadID -> this thread is already re-initializing the cached information *)
- begin
- if InInitDefaultCP <> -1 then
- repeat
- (* Let's wait until the other thread finishes re-initialization of the cache *)
- DosSleep (5)
- until InInitDefaultCP = -1
- else
- InitDefaultCP;
- if CheckDefaultWinCP then
- Exit;
- end;
- I := 1;
- if ReqFlags and CpxSpecial = CpxSpecial then
- I2 := 2
- else
- if ReqFlags and CpxMappingOnly = CpxMappingOnly then
- I2 := MaxNonEqualCPMapping
- else
- I2 := MaxCPMapping;
- while I <= I2 do
- begin
- if RtlCP = CpXList [I].WinCP then
- begin
- RtlCPtoOS2CP := CpXList [I].OS2CP;
- if ReqFlags and CpxMappingOnly = 0 then
- begin
- begin
- if UConvObjectForCP (CpXList [I].OS2CP, UConvObj) = Uls_Success then
- CpXList [I].UConvObj := UConvObj
- else
- UConvObj := nil;
- end
- end;
- Exit;
- end;
- Inc (I);
- end;
- (*
- Special processing for
- ExceptionWinCodepages = (CP_UTF16BE, CP_UTF7, 12000 {UTF32}, 12001 {UTF32BE})
- might be added here...or not ;-)
- if (TempCpRec.OS2CP <> High (TempCpRec.OS2CP)) or
- (TempCpRec.WinCP <> RtlCp) then
- begin
- if TempCpRec.UConvObj <> nil then
- begin
- RCI := Sys_UniFreeUConvObject (TempCpRec.UConvObj);
- if RCI <> 0 then
- OSErrorWatch (cardinal (RCI));
- end;
- TempCpRec.OS2CP := High (TempCpRec.OS2CP);
- TempCpRec.WinCP := RtlCp;
- end;
- Map to CP_ASCII aka OS2CP=367 if RtlCP not recognized and UConvObject
- is requested???
- *)
- (* Signalize unrecognized (untranslatable) MS Windows codepage *)
- OSErrorWatch (Uls_Invalid);
- end;
- end;
- function OS2CPtoRtlCP (CP: cardinal; ReqFlags: byte): TSystemCodepage;
- var
- NoUConvObj: TUConvObject;
- begin
- if RtlUsesWinCP then
- OS2CPtoRtlCP := OS2CPtoRtlCP (CP, ReqFlags or CpxMappingOnly, NoUConvObj)
- else
- OS2CPtoRtlCP := TSystemCodepage (CP);
- end;
- function RtlCPtoOS2CP (RtlCP: TSystemCodepage; ReqFlags: byte): cardinal;
- var
- NoUConvObj: TUConvObject;
- begin
- if RtlUsesWinCP then
- RtlCPtoOS2CP := RtlCPtoOS2CP (RtlCP, ReqFlags or CpxMappingOnly, NoUConvObj)
- else
- RtlCPtoOS2CP := RtlCP;
- end;
- procedure OS2Unicode2AnsiMove (Source: PUnicodeChar; var Dest: RawByteString;
- CP: TSystemCodePage; Len: SizeInt);
- var
- RCI: longint;
- UConvObj: TUConvObject;
- OS2CP: cardinal;
- Src2: PUnicodeChar;
- Len2, LenOut, OutOffset, NonIdentical: longint;
- Dest2: PChar;
- begin
- OS2CP := RtlCpToOS2CP (CP, CpxAll, UConvObj);
- { if UniAPI and (UConvObj = nil) then - OS2Unicode2AnsiMove should be never called if not UniAPI }
- if UConvObj = nil then
- begin
- {$WARNING Special cases like UTF-7 should be handled here, otherwise signalize error - how???}
- DefaultUnicode2AnsiMove (Source, Dest, CP, Len);
- Exit;
- end;
- LenOut := Succ (Len); (* Standard OS/2 CP is a SBCS *)
- SetLength (Dest, LenOut);
- SetCodePage (Dest, CP, false);
- Src2 := Source;
- Len2 := Len;
- Dest2 := PChar (Dest);
- RCI := Sys_UniUConvFromUcs (UConvObj, Src2, Len2, Dest2, LenOut,
- NonIdentical);
- repeat
- case RCI of
- Uls_Success:
- begin
- if LenOut > 0 then
- SetLength (Dest, Length (Dest) - LenOut);
- Break;
- end;
- Uls_IllegalSequence:
- begin
- OSErrorWatch (Uls_IllegalSequence);
- { skip and set to '?' }
- Inc (Src2);
- Dec (Len2);
- Dest2^ := '?';
- Inc (Dest2);
- Dec (LenOut);
- end;
- Uls_BufferFull:
- begin
- OutOffset := Dest2 - PChar (Dest);
- (* Use Len2 or Len decreased by difference between Source and Src2? *)
- (* Extend more this time - target is probably a DBCS or UTF-8 *)
- SetLength (Dest, Length (Dest) + Succ (Len2 * 2));
- { string could have been moved }
- Dest2 := PChar (Dest) + OutOffset;
- Inc (LenOut, Succ (Len2 * 2));
- end
- else
- begin
- SetLength (Dest, 0);
- OSErrorWatch (cardinal (RCI));
- { Break }
- RunError (231);
- end;
- end;
- RCI := Sys_UniUConvFromUcs (UConvObj, Src2, Len2, Dest2, LenOut,
- NonIdentical);
- until false;
- end;
- procedure OS2Ansi2UnicodeMove (Source: PChar; CP: TSystemCodePage;
- var Dest: UnicodeString; Len: SizeInt);
- var
- RCI: longint;
- UConvObj: TUConvObject;
- OS2CP: cardinal;
- Src2: PChar;
- Len2, LenOut, OutOffset, NonIdentical: longint;
- Dest2: PWideChar;
- begin
- OS2CP := RtlCpToOS2CP (CP, CpxAll, UConvObj);
- { if UniAPI and (UConvObj = nil) then - OS2Unicode2AnsiMove should be never called if not UniAPI }
- if UConvObj = nil then
- begin
- {$WARNING Special cases like UTF-7 should be handled here, otherwise signalize error - how???}
- DefaultAnsi2UnicodeMove (Source, CP, Dest, Len);
- Exit;
- end;
- LenOut := Succ (Len); (* Standard OS/2 CP is a SBCS *)
- SetLength (Dest, LenOut);
- Src2 := Source;
- Len2 := Len;
- Dest2 := PWideChar (Dest);
- RCI := Sys_UniUConvToUcs (UConvObj, Src2, Len2, Dest2, LenOut, NonIdentical);
- repeat
- case RCI of
- Uls_Success:
- begin
- if LenOut > 0 then
- SetLength (Dest, Length (Dest) - LenOut);
- Break;
- end;
- Uls_IllegalSequence:
- begin
- OSErrorWatch (Uls_IllegalSequence);
- { skip and set to '?' }
- Inc (Src2);
- Dec (Len2);
- Dest2^ := '?';
- Inc (Dest2);
- Dec (LenOut);
- end;
- Uls_BufferFull:
- begin
- OutOffset := Dest2 - PWideChar (Dest);
- (* Use Len2 or Len decreased by difference between Source and Src2? *)
- SetLength (Dest, Length (Dest) + Succ (Len2));
- { string could have been moved }
- Dest2 := PWideChar (Dest) + OutOffset;
- Inc (LenOut, Succ (Len2));
- end
- else
- begin
- SetLength (Dest, 0);
- OSErrorWatch (cardinal (RCI));
- { Break }
- RunError (231);
- end;
- end;
- RCI := Sys_UniUConvToUcs (UConvObj, Src2, Len2, Dest2, LenOut,
- NonIdentical);
- until false;
- end;
- function RtlChangeCP (CP: TSystemCodePage): longint;
- var
- OS2CP, I: cardinal;
- NoUConvObj: TUConvObject;
- RCI: longint;
- begin
- OS2CP := RtlCpToOS2Cp (CP, cpxMappingOnly, NoUConvObj);
- RtlChangeCP := longint (DosSetProcessCP (OS2CP));
- if RtlChangeCP <> 0 then
- OSErrorWatch (RtlChangeCP)
- else
- begin
- DefaultSystemCodePage := CP;
- DefaultRTLFileSystemCodePage := DefaultSystemCodePage;
- DefaultFileSystemCodePage := DefaultSystemCodePage;
- if OS2CP <> DefCpRec.OS2CP then
- begin
- if DefCpRec.UConvObj <> nil then
- begin
- (* Do not free the UConv object from DefCpRec, because it is also stored in
- the respective CpXList record! *)
- {
- RCI := Sys_UniFreeUConvObject (DefCpRec.UConvObj);
- if RCI <> 0 then
- OSErrorWatch (cardinal (RCI));
- }
- DefCpRec.UConvObj := nil;
- end;
- DefCPRec.OS2CP := OS2CP;
- RCI := Sys_UniCreateUConvObject (@WNull, DefCpRec.UConvObj);
- if RCI <> 0 then
- OSErrorWatch (cardinal (RCI));
- (* Find out WinCP _without_ considering RtlUsesWinCP *)
- I := 1;
- while (I <= MaxNonEqualCPMapping) and (CpXList [I].OS2CP <> OS2CP) do
- Inc (I);
- if CpXList [I].OS2CP = OS2CP then
- DefCpRec.WinCP := CpXList [I].WinCP
- else
- DefCpRec.WinCP := OS2CP;
- end;
- end;
- end;
- function OS2UpperUnicodeString (const S: UnicodeString): UnicodeString;
- var
- I: cardinal;
- begin
- SetLength (Result, Length (S));
- if Length (S) > 0 then
- for I := 0 to Pred (Length (S)) do
- PWideChar (Result) [I] := Sys_UniToUpper (S [Succ (I)]);
- end;
- function OS2LowerUnicodeString (const S: UnicodeString): UnicodeString;
- var
- I: cardinal;
- begin
- SetLength (Result, Length (S));
- if Length (S) > 0 then
- for I := 0 to Pred (Length (S)) do
- PWideChar (Result) [I] := Sys_UniToLower (S [Succ (I)]);
- end;
- function NoNullsUnicodeString (const S: UnicodeString): UnicodeString;
- var
- I: cardinal;
- begin
- Result := S;
- UniqueString (Result);
- if Length (S) > 0 then
- for I := 1 to Length (S) do
- if Result [I] = WNull then
- Result [I] := ' ';
- end;
- function OS2CompareUnicodeString (const S1, S2: UnicodeString; Options : TCompareOptions): PtrInt;
- var
- HS1, HS2: UnicodeString;
-
- begin
- { UniStrColl interprets null chars as end-of-string -> filter out }
- HS1 := NoNullsUnicodeString (S1);
- HS2 := NoNullsUnicodeString (S2);
- (*
- if coLingIgnoreCase in Options then
- begin
- HS1:=OS2UpperUnicodeString(HS1);
- HS2:=OS2UpperUnicodeString(HS2);
- {$WARNING TODO: Exclude null characters and convert to uppercase in one-pass}
- end
- else
- *)
- if coIgnoreCase in Options then
- begin
- HS1:=OS2UpperUnicodeString(HS1);
- HS2:=OS2UpperUnicodeString(HS2);
- {$WARNING TODO: Exclude null characters and convert to uppercase in one-pass}
- end;
- Result := Sys_UniStrColl (DefLocObj, PWideChar (HS1), PWideChar (HS2));
- if Result < -1 then
- Result := -1
- else if Result > 1 then
- Result := 1;
- end;
- (*
- function OS2CompareTextUnicodeString (const S1, S2: UnicodeString): PtrInt;
- begin
- Result := OS2CompareUnicodeString (OS2UpperUnicodeString (S1),
- OS2UpperUnicodeString (S2));
- {$WARNING Language independent uppercase routine may not be appropriate for language dependent case insensitive comparison!}
- end;
- *)
- function OS2UpperAnsiString (const S: AnsiString): AnsiString;
- var
- RC: cardinal;
- begin
- Result := S;
- UniqueString (Result);
- FillChar (EmptyCC, SizeOf (EmptyCC), 0);
- RC := DosMapCase (Length (Result), EmptyCC, PChar (Result));
- { What to do in case of a failure??? }
- if RC <> 0 then
- Result := UpCase (S); { Use a fallback? }
- end;
-
- function OS2LowerAnsiString (const S: AnsiString): AnsiString;
- var
- I: PtrUInt;
- function IsDBCSLeadChar (C: char): boolean;
- var
- D: byte;
- begin
- IsDBCSLeadChar := false;
- D := 0;
- while D < DBCSLeadRangesEnd do
- begin
- if (C >= DBCSLeadRanges [D]) and (C <= DBCSLeadRanges [Succ (D)]) then
- begin
- IsDBCSLeadChar := true;
- Exit;
- end;
- Inc (D, 2);
- end;
- end;
- begin
- (*
- OS/2 provides no direct solution for lowercase conversion of MBCS strings.
- If Unicode support is available, using Unicode routines is the best solution.
- If not, we use a translation table built at startup by translating the full
- character set to uppercase and using that for creation of a lookup table
- (as already done in sysutils). However, we need to check for DBCS (MBCS)
- codepages and avoid translating the DBCS lead bytes and the following
- character.
- *)
- if UniAPI then
- Result := AnsiString (OS2LowerUnicodeString (UnicodeString (S)))
- else
- begin
- Result := S;
- if Length (Result) > 0 then
- begin
- UniqueString (Result);
- if DBCSLeadRangesEnd > 0 then
- begin
- I := 1;
- while I <= Length (Result) do
- begin
- if IsDBCSLeadChar (Result [I]) then
- Inc (I, 2)
- else
- begin
- Result [I] := LowerChars [Result [I]];
- Inc (I);
- end;
- end;
- end
- else
- for I := 1 to Length (Result) do
- Result [I] := LowerChars [Result [I]];
- end;
- end;
- end;
- function OS2CompareStrAnsiString (const S1, S2: AnsiString): PtrInt;
- var
- I, MaxLen: PtrUInt;
- begin
- if UniAPI then
- Result := OS2CompareUnicodeString (UnicodeString (S1), UnicodeString (S2),
- [])
- else
- (* Older OS/2 versions without Unicode support do not provide direct means *)
- (* for case sensitive and codepage and language-aware string comparison. *)
- (* We have to resort to manual comparison of the original strings together *)
- (* with strings translated using the case insensitive collation sequence. *)
- begin
- if Length (S1) = 0 then
- begin
- if Length (S2) = 0 then
- Result := 0
- else
- Result := -1;
- Exit;
- end
- else
- if Length (S2) = 0 then
- begin
- Result := 1;
- Exit;
- end;
- I := 1;
- MaxLen := Length (S1);
- if Length (S2) < MaxLen then
- MaxLen := Length (S2);
- repeat
- if CollationSequence [S1 [I]] = CollationSequence [S2 [I]] then
- begin
- if S1 [I] < S2 [I] then
- begin
- Result := -1;
- Exit;
- end
- else if S1 [I] > S2 [I] then
- begin
- Result := 1;
- Exit;
- end;
- end
- else
- begin
- if CollationSequence [S1 [I]] < CollationSequence [S2 [I]] then
- Result := -1
- else
- Result := 1;
- Exit;
- end;
- Inc (I);
- until (I > MaxLen);
- if Length (S2) > MaxLen then
- Result := -1
- else if Length (S1) > MaxLen then
- Result := 1
- else
- Result := 0;
- end;
- end;
- function OS2StrCompAnsiString (S1, S2: PChar): PtrInt;
- var
- HSA1, HSA2: AnsiString;
- HSU1, HSU2: UnicodeString;
- begin
- (* Do not call OS2CompareUnicodeString to skip scanning for #0. *)
- HSA1 := AnsiString (S1);
- HSA2 := AnsiString (S2);
- if UniApi then
- begin
- HSU1 := UnicodeString (HSA1);
- HSU2 := UnicodeString (HSA2);
- Result := Sys_UniStrColl (DefLocObj, PWideChar (HSU1), PWideChar (HSU2));
- if Result < -1 then
- Result := -1
- else if Result > 1 then
- Result := 1;
- end
- else
- Result := OS2CompareStrAnsiString (HSA1, HSA2);
- end;
- function OS2CompareTextAnsiString (const S1, S2: AnsiString): PtrInt;
- var
- HSA1, HSA2: AnsiString;
- I: PtrUInt;
- begin
- if UniAPI then
- Result := OS2CompareUnicodeString (UnicodeString (S1), UnicodeString (S2),
- [coIgnoreCase])
- else
- begin
- (* Let's use collation strings here as a fallback *)
- SetLength (HSA1, Length (S1));
- if Length (HSA1) > 0 then
- (* Using assembler would be much faster, but never mind... *)
- for I := 1 to Length (HSA1) do
- HSA1 [I] := CollationSequence [S1 [I]];
- {$WARNING Results of using collation sequence with DBCS not known/tested!}
- SetLength (HSA2, Length (S2));
- if Length (HSA2) > 0 then
- for I := 1 to Length (HSA2) do
- HSA2 [I] := CollationSequence [S2 [I]];
- if HSA1 = HSA2 then
- Result := 0
- else if HSA1 < HSA2 then
- Result := -1
- else
- Result := 1;
- end;
- end;
- function OS2StrICompAnsiString (S1, S2: PChar): PtrInt;
- begin
- Result := OS2CompareTextAnsiString (AnsiString (S1), AnsiString (S2));
- end;
- function OS2StrLCompAnsiString (S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
- var
- A, B: AnsiString;
- begin
- if (MaxLen = 0) then
- Exit (0);
- SetLength (A, MaxLen);
- Move (S1^, A [1], MaxLen);
- SetLength (B, MaxLen);
- Move (S2^, B [1], MaxLen);
- Result := OS2CompareStrAnsiString (A, B);
- end;
- function OS2StrLICompAnsiString (S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
- var
- A, B: AnsiString;
- begin
- if (MaxLen = 0) then
- Exit (0);
- SetLength (A, MaxLen);
- Move (S1^, A [1], MaxLen);
- SetLength (B, MaxLen);
- Move (S2^, B [1], MaxLen);
- Result := OS2CompareTextAnsiString (A, B);
- end;
- procedure FPC_RangeError; [external name 'FPC_RANGEERROR'];
- procedure Ansi2PChar (const S: AnsiString; const OrgP: PChar; out P: Pchar);
- var
- NewLen: SizeUInt;
- begin
- NewLen := Length (S);
- if NewLen > StrLen (OrgP) then
- FPC_RangeError;
- P := OrgP;
- if (NewLen > 0) then
- Move (S [1], P [0], NewLen);
- P [NewLen] := #0;
- end;
- function OS2StrUpperAnsiString (Str: PChar): PChar;
- var
- Temp: AnsiString;
- begin
- Temp := OS2UpperAnsiString (Str);
- Ansi2PChar (Temp, Str, Result);
- end;
- function OS2StrLowerAnsiString (Str: PChar): PChar;
- var
- Temp: AnsiString;
- begin
- Temp := OS2LowerAnsiString (Str);
- Ansi2PChar (Temp, Str, Result);
- end;
- (*
- CWSTRING:
- { return value: number of code points in the string. Whenever an invalid
- code point is encountered, all characters part of this invalid code point
- are considered to form one "character" and the next character is
- considered to be the start of a new (possibly also invalid) code point }
- function CharLengthPChar(const Str: PChar): PtrInt;
- var
- nextlen: ptrint;
- s: pchar;
- {$ifndef beos}
- mbstate: mbstate_t;
- {$endif not beos}
- begin
- result:=0;
- s:=str;
- {$ifndef beos}
- fillchar(mbstate,sizeof(mbstate),0);
- {$endif not beos}
- repeat
- {$ifdef beos}
- nextlen:=ptrint(mblen(s,MB_CUR_MAX));
- {$else beos}
- nextlen:=ptrint(mbrlen(s,MB_CUR_MAX,@mbstate));
- {$endif beos}
- { skip invalid/incomplete sequences }
- if (nextlen<0) then
- nextlen:=1;
- inc(result,1);
- inc(s,nextlen);
- until (nextlen=0);
- end;
- function CodePointLength(const Str: PChar; maxlookahead: ptrint): PtrInt;
- var
- nextlen: ptrint;
- {$ifndef beos}
- mbstate: mbstate_t;
- {$endif not beos}
- begin
- {$ifdef beos}
- result:=ptrint(mblen(str,maxlookahead));
- {$else beos}
- fillchar(mbstate,sizeof(mbstate),0);
- result:=ptrint(mbrlen(str,maxlookahead,@mbstate));
- { mbrlen can also return -2 for "incomplete but potially valid character
- and data has been processed" }
- if result<0 then
- result:=-1;
- {$endif beos}
- end;
- *)
- procedure InitOS2WideStringManager; inline;
- var
- RC: cardinal;
- ErrName: array [0..MaxPathLen] of char;
- P: pointer;
- begin
- RC := DosLoadModule (@ErrName [0], SizeOf (ErrName), @UConvName [0],
- UConvHandle);
- if RC = 0 then
- begin
- RC := DosQueryProcAddr (UConvHandle, OrdUniCreateUConvObject, nil, P);
- if RC = 0 then
- begin
- Sys_UniCreateUConvObject := TUniCreateUConvObject (P);
- RC := DosQueryProcAddr (UConvHandle, OrdUniMapCpToUcsCp, nil, P);
- if RC = 0 then
- begin
- Sys_UniMapCpToUcsCp := TUniMapCpToUcsCp (P);
- RC := DosQueryProcAddr (UConvHandle, OrdUniFreeUConvObject, nil, P);
- if RC = 0 then
- begin
- Sys_UniFreeUConvObject := TUniFreeUConvObject (P);
- RC := DosQueryProcAddr (UConvHandle, OrdUniUConvFromUcs, nil, P);
- if RC = 0 then
- begin
- Sys_UniUConvFromUcs := TUniUConvFromUcs (P);
- RC := DosQueryProcAddr (UConvHandle, OrdUniUConvToUcs, nil, P);
- if RC = 0 then
- begin
- Sys_UniUConvToUcs := TUniUConvToUcs (P);
- RC := DosLoadModule (@ErrName [0], SizeOf (ErrName),
- @LibUniName [0], LibUniHandle);
- if RC = 0 then
- begin
- RC := DosQueryProcAddr (LibUniHandle, OrdUniToLower, nil, P);
- if RC = 0 then
- begin
- Sys_UniToLower := TUniToLower (P);
- RC := DosQueryProcAddr (LibUniHandle, OrdUniToUpper, nil, P);
- if RC = 0 then
- begin
- Sys_UniToUpper := TUniToUpper (P);
- RC := DosQueryProcAddr (LibUniHandle, OrdUniStrColl, nil,
- P);
- if RC = 0 then
- begin
- Sys_UniStrColl := TUniStrColl (P);
- RC := DosQueryProcAddr (LibUniHandle,
- OrdUniCreateLocaleObject, nil, P);
- if RC = 0 then
- begin
- Sys_UniCreateLocaleObject := TUniCreateLocaleObject
- (P);
- RC := DosQueryProcAddr (LibUniHandle,
- OrdUniFreeLocaleObject, nil, P);
- if RC = 0 then
- begin
- Sys_UniFreeLocaleObject := TUniFreeLocaleObject (P);
- RC := DosQueryProcAddr (LibUniHandle,
- OrdUniMapCtryToLocale, nil, P);
- if RC = 0 then
- begin
- Sys_UniMapCtryToLocale := TUniMapCtryToLocale (P);
- UniAPI := true;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- end;
- if RC <> 0 then
- OSErrorWatch (RC);
- if not (UniAPI) then
- begin
- Sys_UniCreateUConvObject := @DummyUniCreateUConvObject;
- Sys_UniMapCpToUcsCp := @DummyUniMapCpToUcsCp;
- Sys_UniFreeUConvObject := @DummyUniFreeUConvObject;
- Sys_UniUConvFromUcs := @DummyUniUConvFromUcs;
- Sys_UniUConvToUcs := @DummyUniUConvToUcs;
- Sys_UniToLower := @DummyUniToLower;
- Sys_UniToUpper := @DummyUniToUpper;
- Sys_UniStrColl := @DummyUniStrColl;
- Sys_UniCreateLocaleObject := @DummyUniCreateLocaleObject;
- Sys_UniFreeLocaleObject := @DummyUniFreeLocaleObject;
- Sys_UniMapCtryToLocale := @DummyUniMapCtryToLocale;
- InitDummyAnsiSupport;
- end;
- { Widestring }
- WideStringManager.Wide2AnsiMoveProc := @OS2Unicode2AnsiMove;
- WideStringManager.Ansi2WideMoveProc := @OS2Ansi2UnicodeMove;
- WideStringManager.UpperWideStringProc := @OS2UpperUnicodeString;
- WideStringManager.LowerWideStringProc := @OS2LowerUnicodeString;
- WideStringManager.CompareWideStringProc := @OS2CompareUnicodeString;
- { Unicode }
- WideStringManager.Unicode2AnsiMoveProc := @OS2Unicode2AnsiMove;
- WideStringManager.Ansi2UnicodeMoveProc := @OS2Ansi2UnicodeMove;
- WideStringManager.UpperUnicodeStringProc := @OS2UpperUnicodeString;
- WideStringManager.LowerUnicodeStringProc := @OS2LowerUnicodeString;
- WideStringManager.CompareUnicodeStringProc := @OS2CompareUnicodeString;
- { Codepage }
- WideStringManager.GetStandardCodePageProc := @OS2GetStandardCodePage;
- (*
- CharLengthPCharProc:=@CharLengthPChar;
- CodePointLengthProc:=@CodePointLength;
- *)
- WideStringManager.UpperAnsiStringProc := @OS2UpperAnsiString;
- WideStringManager.LowerAnsiStringProc := @OS2LowerAnsiString;
- WideStringManager.CompareStrAnsiStringProc := @OS2CompareStrAnsiString;
- WideStringManager.CompareTextAnsiStringProc := @OS2CompareTextAnsiString;
- WideStringManager.StrCompAnsiStringProc := @OS2StrCompAnsiString;
- WideStringManager.StrICompAnsiStringProc := @OS2StrICompAnsiString;
- WideStringManager.StrLCompAnsiStringProc := @OS2StrLCompAnsiString;
- WideStringManager.StrLICompAnsiStringProc := @OS2StrLICompAnsiString;
- WideStringManager.StrLowerAnsiStringProc := @OS2StrLowerAnsiString;
- WideStringManager.StrUpperAnsiStringProc := @OS2StrUpperAnsiString;
- end;
|