123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725 |
- {
- 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 <> 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 coIgnoreCase in Options then
- begin
- HS1:=OS2UpperUnicodeString(HS1);
- HS2:=OS2UpperUnicodeString(HS2);
- 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 := OS2LowerUnicodeString (S)
- { Two implicit conversions... ;-) }
- 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 (S1, S2) (* implicit conversions *)
- 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 := HSA1; (* implicit conversion *)
- HSU2 := HSA2; (* implicit conversion *)
- 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 := OS2CompareTextUnicodeString (S1, S2) (* implicit conversions *)
- 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;
|