/******************************Module*Header*******************************\ * Module Name: nlsconv.c * * * * DBCS specific routines * * * * Created: 15-Mar-1994 15:56:30 * * Author: Gerrit van Wingerden [gerritv] * * * * Copyright (c) 1994-1999 Microsoft Corporation * \**************************************************************************/ #include "precomp.h" #pragma hdrstop UINT fFontAssocStatus = 0; BYTE cLowTrailByteSet1 = 0xff; BYTE cHighTrailByteSet1 = 0x0; BYTE cLowTrailByteSet2 = 0xff; BYTE cHighTrailByteSet2 = 0x0; /******************************Public*Routine******************************\ * * * DBCS Trailling Byte validate check functions. * * * \**************************************************************************/ #define IS_DBCS_TRAIL_BYTE(Char) (\ ((Char >= cLowTrailByteSet1) && (Char <= cHighTrailByteSet1)) \ ||((Char >= cLowTrailByteSet2) && (Char <= cHighTrailByteSet2)) \ ) /**************************************************************************\ * * * SHIFT-JIS (Japanese) character set : CodePage 932 * * * * Valid LeadByte Range | Valid TailByte Range * * -----------------------+--------------------- * * From -> To | From -> To * * - - - - - - - - - - - - - - - - - - - - - - - * * 0x81 -> 0x9F | 0x40 -> 0xFC * * 0xE0 -> 0xFC | * * * \**************************************************************************/ /**************************************************************************\ * * * WANSANG (Korean) character set : CodePage 949 * * * * Valid LeadByte Range | Valid TailByte Range * * -----------------------+--------------------- * * From -> To | From -> To * * - - - - - - - - - - - - - - - - - - - - - - - * * 0xA1 -> 0xAC | 0x40 -> 0xFC * * 0xB0 -> 0xC8 | * * 0xCA -> 0xFD | * * * \**************************************************************************/ /**************************************************************************\ * * * GB2312 (PRC Chinese) character set : CodePage 936 * * * * Valid LeadByte Range | Valid TailByte Range * * -----------------------+--------------------- * * From -> To | From -> To * * - - - - - - - - - - - - - - - - - - - - - - - * * 0xA1 -> 0xA9 | 0xA1 -> 0xFE * * 0xB0 -> 0xF7 | * * * \**************************************************************************/ /**************************************************************************\ * * * Big 5 (Taiwan,Hong Kong Chinese) character set : CodePage 950 * * * * Valid LeadByte Range | Valid TailByte Range * * -----------------------+--------------------- * * From -> To | From -> To * * - - - - - - - - - - - - - - - - - - - - - - - * * 0x81 -> 0xFE | 0x40 -> 0x7E * * | 0xA1 -> 0xFE * * * \**************************************************************************/ /******************************Public*Routine******************************\ * vSetCheckDBCSTrailByte() * * This function setup function for the DBCS trailling byte validation of * specified character with specified Fareast codepage. * * Thu-15-Feb-1996 11:59:00 -by- Gerrit van Wingerden * Moved function pointer out of CFONT and into a global variable. * * Wed 20-Dec-1994 10:00:00 -by- Hideyuki Nagase [hideyukn] * Write it. \**************************************************************************/ VOID vSetCheckDBCSTrailByte(DWORD dwCodePage) { switch( dwCodePage ) { case 932: cLowTrailByteSet1 = (CHAR) 0x40; cHighTrailByteSet1 = (CHAR) 0xfc; cLowTrailByteSet2 = (CHAR) 0x40; cHighTrailByteSet2 = (CHAR) 0xfc; break; case 949: cLowTrailByteSet1 = (CHAR) 0x40; cHighTrailByteSet1 = (CHAR) 0xfc; cLowTrailByteSet2 = (CHAR) 0x40; cHighTrailByteSet2 = (CHAR) 0xfc; break; case 936: cLowTrailByteSet1 = (CHAR) 0xa1; cHighTrailByteSet1 = (CHAR) 0xfe; cLowTrailByteSet2 = (CHAR) 0xa1; cHighTrailByteSet2 = (CHAR) 0xfe; break; case 950: cLowTrailByteSet1 = (CHAR) 0x40; cHighTrailByteSet1 = (CHAR) 0x7e; cLowTrailByteSet2 = (CHAR) 0xa1; cHighTrailByteSet2 = (CHAR) 0xfe; break; default: cLowTrailByteSet1 = (CHAR) 0xff; cHighTrailByteSet1 = (CHAR) 0x0; cLowTrailByteSet2 = (CHAR) 0xff; cHighTrailByteSet2 = (CHAR) 0x0; WARNING("GDI32!INVALID DBCS codepage\n"); break; } } /******************************Public*Routine******************************\ * bComputeCharWidthsDBCS * * Client side version of GetCharWidth for DBCS fonts * * Wed 18-Aug-1993 10:00:00 -by- Gerrit van Wingerden [gerritv] * Stole it and converted for DBCS use. * * Sat 16-Jan-1993 04:27:19 -by- Charles Whitmer [chuckwh] * Wrote bComputeCharWidths on which this is based. \**************************************************************************/ BOOL bComputeCharWidthsDBCS ( CFONT *pcf, UINT iFirst, UINT iLast, ULONG fl, PVOID pv ) { USHORT *ps; USHORT ausWidths[256]; UINT ii, cc; if( iLast - iFirst > 0xFF ) { WARNING("bComputeCharWidthsDBCS iLast - iFirst > 0xFF" ); return(FALSE); } if( iLast < iFirst ) { WARNING("bComputeCharWidthsDBCS iLast < iFirst" ); return(FALSE); } // We want to compute the same widths that would be computed if // vSetUpUnicodeStringx were called with this first and last and then // GetCharWidthsW was called. The logic may be wierd but I assume it is // there for Win 3.1J char widths compatability. To do this first fill // in the plain widths in ausWidths and then do all the neccesary // computation on them. if ( gpwcDBCSCharSet[(UCHAR)(iFirst>>8)] == 0xFFFF ) { for( cc = 0 ; cc <= iLast - iFirst; cc++ ) { // If this is a legitimate DBCS character then use // MaxCharInc. ausWidths[cc] = pcf->wd.sDBCSInc; } } else { for( ii = (iFirst & 0x00FF), cc = 0; ii <= (iLast & 0x00FF); cc++, ii++ ) { // Just treat everything as a single byte unless we // encounter a DBCS lead byte which we will treat as a // default character. if( gpwcDBCSCharSet[ii] == 0xFFFF ) { ausWidths[cc] = pcf->wd.sDefaultInc; } else { ausWidths[cc] = pcf->sWidth[ii]; } } } switch (fl & (GCW_INT | GCW_16BIT)) { case GCW_INT: // Get LONG widths. { LONG *pl = (LONG *) pv; LONG fxOverhang = 0; // Check for Win 3.1 compatibility. if (fl & GCW_WIN3) fxOverhang = pcf->wd.sOverhang; // Do the trivial no-transform case. if (bIsOneSixteenthEFLOAT(pcf->efDtoWBaseline)) { fxOverhang += 8; // To round the final result. // for (ii=iFirst; ii<=iLast; ii++) // *pl++ = (pcf->sWidth[ii] + fxOverhang) >> 4; ps = ausWidths; ii = iLast - iFirst; unroll_1: switch(ii) { default: pl[4] = (ps[4] + fxOverhang) >> 4; case 3: pl[3] = (ps[3] + fxOverhang) >> 4; case 2: pl[2] = (ps[2] + fxOverhang) >> 4; case 1: pl[1] = (ps[1] + fxOverhang) >> 4; case 0: pl[0] = (ps[0] + fxOverhang) >> 4; } if (ii > 4) { ii -= 5; pl += 5; ps += 5; goto unroll_1; } return(TRUE); } // Otherwise use the back transform. else { for (ii=0; ii<=iLast-iFirst; ii++) *pl++ = lCvt(pcf->efDtoWBaseline,ausWidths[ii] + fxOverhang); return(TRUE); } } case GCW_INT+GCW_16BIT: // Get SHORT widths. { USHORT *psDst = (USHORT *) pv; USHORT fsOverhang = 0; // Check for Win 3.1 compatibility. if (fl & GCW_WIN3) fsOverhang = pcf->wd.sOverhang; // Do the trivial no-transform case. if (bIsOneSixteenthEFLOAT(pcf->efDtoWBaseline)) { fsOverhang += 8; // To round the final result. // for (ii=iFirst; ii<=iLast; ii++) // *psDst++ = (pcf->sWidth[ii] + fsOverhang) >> 4; ps = ausWidths; ii = iLast - iFirst; unroll_2: switch(ii) { default: psDst[4] = (ps[4] + fsOverhang) >> 4; case 3: psDst[3] = (ps[3] + fsOverhang) >> 4; case 2: psDst[2] = (ps[2] + fsOverhang) >> 4; case 1: psDst[1] = (ps[1] + fsOverhang) >> 4; case 0: psDst[0] = (ps[0] + fsOverhang) >> 4; } if (ii > 4) { ii -= 5; psDst += 5; ps += 5; goto unroll_2; } return(TRUE); } // Otherwise use the back transform. else { for (ii=0; ii<=iLast-iFirst; ii++) { *psDst++ = (USHORT) lCvt ( pcf->efDtoWBaseline, (LONG) (ausWidths[ii] + fsOverhang) ); } return(TRUE); } } case 0: // Get FLOAT widths. { LONG *pe = (LONG *) pv; // Cheat to avoid expensive copies. EFLOAT_S efWidth,efWidthLogical; for (ii=0; ii<=iLast-iFirst; ii++) { vFxToEf((LONG) ausWidths[ii],efWidth); vMulEFLOAT(efWidthLogical,efWidth,pcf->efDtoWBaseline); *pe++ = lEfToF(efWidthLogical); } return(TRUE); } } RIP("bComputeCharWidths: Don't come here!\n"); return(FALSE); } BOOL bIsDBCSString ( LPCSTR psz, int cc ) { int ii; BYTE *pc; pc = (BYTE *) psz; cc--; // do not go off the edge ! for (ii=0; iilTextExtra; lBreakExtra = pDcAttr->lBreakExtra; cBreak = pDcAttr->cBreak; pc = (BYTE *) psz; // Compute the basic extent. fxBasicExtent = 0; pc = (BYTE *) psz; for (ii=0; iiwd.sDBCSInc; } else { fxBasicExtent += pcf->sWidth[*pc++]; } cChars += 1; } // Adjust for CharExtra. if (lTextExtra) { int cNoBackup = 0; fxCharExtra = lCvt(pcf->efM11,lTextExtra); if( fxCharExtra < 0 ) { // the layout code won't backup a characters past it's origin regardless // of the value of iTextCharExtra so figure out for how many values // we will need to ignore fxCharExtra if( pcf->wd.sCharInc == 0 ) { for( ii = 0; ii < cc; ii++ ) { if( gpwcDBCSCharSet[(BYTE)psz[ii]] == 0xFFFF ) { if( pcf->wd.sDBCSInc + fxCharExtra <= 0 ) { cNoBackup += 1; } ii++; } else { if( pcf->sWidth[(BYTE)psz[ii]] + fxCharExtra <= 0 ) { cNoBackup += 1; } } } } else if( pcf->wd.sCharInc + fxCharExtra <= 0 ) { cNoBackup = cChars; } } if ( (fl & GGTE_WIN3_EXTENT) && (pcf->hdc == 0) && (!(pcf->flInfo & FM_INFO_TECH_STROKE)) ) fxExtra = fxCharExtra * ((lTextExtra > 0) ? cChars : (cChars - 1)); else fxExtra = fxCharExtra * ( cChars - cNoBackup ); } // Adjust for lBreakExtra. if (lBreakExtra && cBreak) { fxBreakExtra = lCvt(pcf->efM11,lBreakExtra) / cBreak; // Windows won't let us back up over a break. Set up the BreakExtra // to just cancel out what we've already got. if (fxBreakExtra + pcf->wd.sBreak + fxCharExtra < 0) fxBreakExtra = -(pcf->wd.sBreak + fxCharExtra); // Add it up for all breaks. pc = (BYTE *) psz; for (ii=0; iiwd.iBreak) { fxExtra += fxBreakExtra; } } } // Add in the extra stuff. fxBasicExtent += fxExtra; // Add in the overhang for font simulations. if (fl & GGTE_WIN3_EXTENT) fxBasicExtent += pcf->wd.sOverhang; // Transform the result to logical coordinates. if (bIsOneSixteenthEFLOAT(pcf->efDtoWBaseline)) psizl->cx = (fxBasicExtent + 8) >> 4; else psizl->cx = lCvt(pcf->efDtoWBaseline,fxBasicExtent); psizl->cy = pcf->lHeight; return(TRUE); } /******************************Public*Routine*****************************\ * QueryFontAssocStatus() * * * * History: * * 05-Jan-1994 -by- Pi-Sui Hsu [pisuih] * * Wrote it. * \*************************************************************************/ UINT APIENTRY QueryFontAssocStatus( VOID ) { return(fFontAssocStatus); } INT APIENTRY GetFontAssocStatus( HDC hdc ) { if(hdc == NULL) { return(0); } else { return(NtGdiQueryFontAssocInfo(hdc)); } } BOOL bToUnicodeNx(LPWSTR pwsz, LPCSTR psz, DWORD c, UINT codepage) { if(fFontAssocStatus && ((codepage == GetACP() || codepage == CP_ACP)) && ((c == 1) || ((c == 2 && *(psz) && *((LPCSTR)(psz + 1)) == '\0')))) { // // If this function is called with only 1 char, and font association // is enabled, we should forcely convert the chars to Unicode with // codepage 1252. // This is for enabling to output Latin-1 chars ( > 0x80 in Ansi codepage ) // Because, normally font association is enabled, we have no way to output // those charactres, then we provide the way, if user call TextOutA() with // A character and ansi font, we tempotary disable font association. // This might be Windows 3.1 (Korean/Taiwanese) version compatibility.. // codepage = 1252; } if(MultiByteToWideChar(codepage, 0, psz, c, pwsz, c)) { return(TRUE); } else { GdiSetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } } /******************************Public*Routine******************************\ * * vSetUpUnicodeStringx * * Effects: * * Warnings: * * History: * 14-Mar-1993 -by- Hideyuki Nagase [hideyukn] * Change hardcoded default character to defulat char is given as a parameter. * * 01-Mar-1993 -by- Takao Kitano [takaok] * Wrote it. \**************************************************************************/ BOOL bSetUpUnicodeStringDBCS ( IN UINT iFirst, // first ansi char IN UINT iLast, // last char IN PUCHAR puchTmp, // temporary buffer OUT PWCHAR pwc, // output fuffer with a unicode string IN UINT uiCodePage, // ansi codepage IN CHAR chDefaultChar // default character ) { PUCHAR puchBuf; BOOL bRet = FALSE; puchBuf = puchTmp; if(IsDBCSLeadByteEx(uiCodePage,(UCHAR)(iFirst >> 8))) { // This is DBCS character strings. for (; iFirst <= iLast; iFirst++ ) { *puchBuf++ = (UCHAR)(iFirst >> 8); *puchBuf++ = (UCHAR)(iFirst); } } else { // This is SBCS character strings. // if Hi-byte of iFirst is not valid DBCS LeadByte , we use only // lo-byte of it. for ( ; iFirst <= iLast; iFirst++ ) { // If this SBCS code in LeadByte area . It replce with default // character if ( IsDBCSLeadByteEx(uiCodePage,(UCHAR)iFirst) ) *puchBuf++ = chDefaultChar; else *puchBuf++ = (UCHAR)iFirst; } } //Sundown: safe to truncate to DWORD since puchBug - puchTmp won't exceed iLast bRet = bToUnicodeNx(pwc, puchTmp, (DWORD)(puchBuf - puchTmp), uiCodePage); return(bRet); } BOOL IsValidDBCSRange( UINT iFirst , UINT iLast ) { // DBCS & SBCS char parameter checking for DBCS font if( iFirst > 0x00ff ) { // DBCS char checking for DBCS font if ( // Check limit (iFirst > 0xffff) || (iLast > 0xffff) || // DBCSLeadByte shoud be same (iFirst & 0xff00) != (iLast & 0xff00) || // DBCSTrailByte of the First should be >= one of the Last (iFirst & 0x00ff) > (iLast & 0x00ff) ) { return(FALSE); } } // DBCS char checking for DBCS font else if( (iFirst > iLast) || (iLast & 0xffffff00) ) { return(FALSE); } return(TRUE); } /******************************Private*Routine*****************************\ * GetCurrentDefaultChar() * * History: * * Mon 15-Mar-1993 18:14:00 -by- Hideyuki Nagase * wrote it. ***************************************************************************/ BYTE GetCurrentDefaultChar(HDC hdc) { // WINBUG 365031 4-10-2001 pravins Consider optimization in GetCurrentDeafultChar // // Old Comment: // - This is slow for now. We should cache this value locally in the dcattr // but want to get other things working for now. [gerritv] 2-22-96 TEXTMETRICA tma; GetTextMetricsA( hdc , &tma ); return(tma.tmDefaultChar); } /*************************************************************************** * ConvertDxArray(UINT, char*, INT*, UINT, INT*) * * Tue 27-Feb-1996 23:45:00 -by- Gerrit van Wingerden [gerritv] * ***************************************************************************/ void ConvertDxArray(UINT CodePage, char *pDBCSString, INT *pDxDBCS, UINT Count, INT *pDxUnicode, BOOL bPdy ) { char *pDBCSStringEnd; if (!bPdy) { for(pDBCSStringEnd = pDBCSString + Count; pDBCSString < pDBCSStringEnd; ) { if(IsDBCSLeadByteEx(CodePage,*pDBCSString)) { pDBCSString += 2; *pDxUnicode = *pDxDBCS++; *pDxUnicode += *pDxDBCS++; } else { pDBCSString += 1; *pDxUnicode = *pDxDBCS++; } pDxUnicode += 1; } } else { POINTL *pdxdyUnicode = (POINTL *)pDxUnicode; POINTL *pdxdyDBCS = (POINTL *)pDxDBCS; for(pDBCSStringEnd = pDBCSString + Count; pDBCSString < pDBCSStringEnd; ) { if(IsDBCSLeadByteEx(CodePage,*pDBCSString)) { pDBCSString += 2; *pdxdyUnicode = *pdxdyDBCS++; pdxdyUnicode->x += pdxdyDBCS->x; pdxdyUnicode->y += pdxdyDBCS->y; pdxdyDBCS++; } else { pDBCSString += 1; *pdxdyUnicode = *pdxdyDBCS++; } pdxdyUnicode++; } } } ULONG APIENTRY EudcLoadLinkW ( LPCWSTR pBaseFaceName, LPCWSTR pEudcFontPath, INT iPriority, INT iFontLinkType ) { return(NtGdiEudcLoadUnloadLink(pBaseFaceName, (pBaseFaceName) ? wcslen(pBaseFaceName) : 0, pEudcFontPath, wcslen(pEudcFontPath), iPriority, iFontLinkType, TRUE)); } BOOL APIENTRY EudcUnloadLinkW ( LPCWSTR pBaseFaceName, LPCWSTR pEudcFontPath ) { return(NtGdiEudcLoadUnloadLink(pBaseFaceName, (pBaseFaceName) ? wcslen(pBaseFaceName) : 0, pEudcFontPath, wcslen(pEudcFontPath), 0, 0, FALSE)); } ULONG APIENTRY GetEUDCTimeStampExW ( LPCWSTR pBaseFaceName ) { return(NtGdiGetEudcTimeStampEx((LPWSTR) pBaseFaceName, (pBaseFaceName) ? wcslen(pBaseFaceName) : 0, FALSE)); } ULONG APIENTRY GetEUDCTimeStamp() { return(NtGdiGetEudcTimeStampEx(NULL,0,TRUE)); } UINT GetStringBitmapW( HDC hdc, LPWSTR pwc, UINT cwc, UINT cbData, BYTE *pSB ) { if(cwc != 1) { return(0); } return(NtGdiGetStringBitmapW(hdc,pwc,1,(PBYTE) pSB,cbData)); } UINT GetStringBitmapA( HDC hdc, LPSTR pc, UINT cch, UINT cbData, BYTE *pSB ) { WCHAR Character[2]; if(cch > 2 ) { return(0); } if(MultiByteToWideChar(CP_ACP,0,pc,cch,Character,2)!=1) { return(0); } return(GetStringBitmapW(hdc,Character,1,cbData,pSB)); } DWORD FontAssocHack(DWORD dwCodePage, CHAR *psz, UINT c) { // If a Text function is called with only 1 char, and font association // is enabled, we should forcely convert the chars to Unicode with // codepage 1252. // This is for enabling to output Latin-1 chars ( > 0x80 in Ansi codepage ) // Because, normally font association is enabled, we have no way to output // those charactres, then we provide the way, if user call TextOutA() with // A character and ansi font, we tempotary disable font association. // This might be Windows 3.1 (Korean/Taiwanese) version compatibility.. ASSERTGDI(fFontAssocStatus, "FontAssocHack called with FontAssocStatus turned off\n"); if(((dwCodePage == GetACP() || dwCodePage == CP_ACP)) && ((c == 1) || ((c == 2 && *(psz) && *((LPCSTR)(psz + 1)) == '\0')))) { return(1252); } else { return(dwCodePage); } }