/************************* MODULE HEADER *********************************** * ctt2rle * Convert Win 3.1 CTT format tables to NT's RLE spec. * * Copyright (C) 1992 - 1993, Microsoft Corporation. * ****************************************************************************/ #include #include #include #include #include #include #include #include "rasdd.h" /* * Some useful definitions for memory sizes and masks. */ #define BBITS 8 /* Bits in a byte */ #define DWBITS (BBITS * sizeof( DWORD )) /* Bits in a DWORD */ #define DW_MASK (DWBITS - 1) /************************ Function Header *********************************** * pntrleConvCTT * Convert a Win 3.1 CTT structure into the corresponding NT RLE * format data. Allocates memory from the heap for this. * * RETURNS: * Pointer to the NT_RLE structure generated; NULL on failure. * * HISTORY: * 13:10 on Thu 04 Mar 1993 -by- Lindsay Harris [lindsayh] * Use correct mapping from Win 3.1 character set to Unicode. * * 14:18 on Tue 01 Dec 1992 -by- Lindsay Harris [lindsayh] * First version. * ****************************************************************************/ NT_RLE * pntrleConvCTT( hheap, pCTT, bOffset, iChMin, iChMax ) HANDLE hheap; /* Access to heap - temporary and long term use */ TRANSTAB *pCTT; /* Pointer to the 3.1 format translate table */ BOOL bOffset; /* If true, WCRUN.phg is offset, else address */ int iChMin; /* Lowest glyph handle we create */ int iChMax; /* Highest glyph handle we create */ { int iI; /* Loop index */ int iMax; /* Find the longest data length for CTT_WTYPE_COMPOSE */ int cHandles; /* The number of handles we need */ int cjExtra; /* Extra storage needed for offset modes */ int cjTotal; /* Total amount of storage to be requested */ int iIndex; /* Index we install in the HGLYPH for widths etc */ int cRuns; /* Number of runs we create */ NT_RLE ntrle; /* Our stuff - while building it up */ NT_RLE *pntrle; /* Allocated memory, and returned to caller */ HGLYPH *phg; /* For working through the array of HGLYPHS */ BYTE *pb; /* Current address in overflow area */ BYTE *pbBase; /* Start of overflow area containing data */ WCRUN *pwcr; /* Scanning the run data */ DWORD *pdwBits; /* For figuring out runs */ DWORD cdwBits; /* Size of this area */ BOOL bInRun; /* For processing run accumulations */ BYTE ajAnsi[ 256 ]; WCHAR awch[ 256 ]; /* Converted array of points */ WCHAR wchMin; /* Find the first unicode value */ WCHAR wchMax; /* Find the last unicode value */ /* * Since we can have up to 4 bytes per entry without going to the * offset mode, we scan the data to see if any entries are longer * than 4 bytes. If so, offset mode is required, otherwise we * can simply put the data into the glyph handles. */ ZeroMemory( &ntrle, sizeof( ntrle ) ); ntrle.wchFirst = min( iChMin, pCTT->chFirstChar ); ntrle.wchLast = max( iChMax, pCTT->chLastChar ); cHandles = ntrle.wchLast - ntrle.wchFirst + 1; if( cHandles > 256 ) return NULL; /* This code does not handle that situation */ cjExtra = 0; /* Presume no extra storage required */ /* See what we have, and if extra storage is needed */ #define OVERFLOW_SZ sizeof( WORD ) switch( pCTT->wType ) { case CTT_WTYPE_COMPOSE: /* Look for the longest length available */ iMax = -1; for( iI = pCTT->chLastChar - pCTT->chFirstChar; --iI >= 0; ) { int iLen; iLen = pCTT->uCode.psCode[ iI + 1 ] - pCTT->uCode.psCode[ iI ]; if( iLen > OVERFLOW_SZ ) { /* * Need to use the overflow arrangement, so remember * how much storage is required. */ cjExtra += iLen; } if( iLen > iMax ) iMax = iLen; } if( iMax <= OVERFLOW_SZ ) { /* Can all fit in DWORD, so use that directly */ ntrle.wType = RLE_DIRECT; /* Allows up to 4 bytes */ } else { /* * Requires an offset style format. We need to decide * how much extra storage to allocate for these, over * and above the HGLYPHS. This is not hard: we allocate * one byte for all glyphs not covered by the CTT, then * add as much as the CTT currently uses. */ /* * For now, assume that we can use the short form of offset. * This may be changed when we calculate storage size later. */ /* We know there are <= 256 entries */ ntrle.wType = RLE_LI_OFFSET; /* Length, Index + 2 bytes offset */ } break; case CTT_WTYPE_DIRECT: /* Single byte - easy to handle */ ntrle.wType = RLE_DIRECT; break; case CTT_WTYPE_PAIRED: /* Pair of bytes, overstruck */ ntrle.wType = RLE_PAIRED; break; default: #if DBG DbgPrint( "Rasdd!pntrleConvCTT: Invalid wtype = %d\n", pCTT->wType ); #endif return NULL; } /* * We need to figure out how many runs are required to describe * this font. First obtain the correct Unicode encoding of these * values, then examine them to find the number of runs, and * hence much extra storage is required. */ for( iI = 0; iI < cHandles; ++iI ) ajAnsi[ iI ] = (BYTE)(iI + ntrle.wchFirst); /* We know it is < 256 */ #ifdef NTGDIKM EngMultiByteToUnicodeN(awch,cHandles * sizeof(WCHAR),NULL,ajAnsi,cHandles); #else MultiByteToWideChar( CP_ACP, 0, ajAnsi, cHandles, awch, cHandles ); #endif /* * Find the largest Unicode value, then allocate storage to allow us * to create a bit array of valid unicode points. Then we can * examine this to determine the number of runs. */ for( wchMax = 0, wchMin = 0xffff, iI = 0; iI < cHandles; ++iI ) { if( awch[ iI ] > wchMax ) wchMax = awch[ iI ]; if( awch[ iI ] < wchMin ) wchMin = awch[ iI ]; } /* * Note that the expression 1 + wchMax IS correct. This comes about * from using these values as indices into the bit array, and that * this is essentially 1 based. */ cdwBits = (1 + wchMax + DWBITS - 1) / DWBITS * sizeof( DWORD ); if( !(pdwBits = (DWORD *)HeapAlloc( hheap, 0, cdwBits )) ) { return NULL; /* Nothing going */ } ZeroMemory( pdwBits, cdwBits ); /* Set bits in this array corresponding to Unicode code points */ for( iI = 0; iI < cHandles; ++iI ) { pdwBits[ awch[ iI ] / DWBITS ] |= (1 << (awch[ iI ] & DW_MASK)); } /* * Now we can examine the number of runs required. For starters, * we stop a run whenever a hole is discovered in the array of 1 * bits we just created. Later we MIGHT consider being a little * less pedantic. */ bInRun = FALSE; cRuns = 0; /* None so far */ for( iI = 1; iI <= (int)wchMax; ++iI ) { if( pdwBits[ iI / DWBITS ] & (1 << (iI & DW_MASK)) ) { /* Not in a run: is this the end of one? */ if( !bInRun ) { /* It's time to start one */ bInRun = TRUE; ++cRuns; } } else { if( bInRun ) { /* Not any more! */ bInRun = FALSE; } } } cjTotal = sizeof( ntrle ) + (cRuns - 1) * sizeof( WCRUN ) + cHandles * sizeof( HGLYPH ) + cjExtra; if( ntrle.wType == RLE_LI_OFFSET && cjTotal > 0xffff ) { /* * Won't fit, so need to go to the 24 bit offset + index. We * assume we need 3 extra bytes for each entry: this is likely * to be pessimistic, but we need to add 2 bytes ALIGNED on a * WORD boundary, so now is the time to play it safe and assume * ALL entries will require padding. */ ntrle.wType = RLE_L_OFFSET; cjTotal += cHandles * (sizeof( WORD ) + 1); #if DBG DbgPrint( "^G.... CANNOT HANDLE THIS...\n" ); #endif } if( !(pntrle = (NT_RLE *)HeapAlloc( hheap, 0, cjTotal )) ) { HeapFree( hheap, 0, (LPSTR)pdwBits ); return pntrle; } /* For calculating offsets, we need these addresses */ pbBase = (BYTE *)pntrle; ZeroMemory( pbBase, cjTotal ); /* Safer if we miss something */ phg = (HGLYPH *)(pbBase + sizeof( ntrle ) + (cRuns - 1) * sizeof( WCRUN )); pb = (BYTE *)phg + cHandles * sizeof( HGLYPH ); pntrle->wType = ntrle.wType; /* Mode we are using */ pntrle->bMagic0 = RLE_MAGIC0; pntrle->bMagic1 = RLE_MAGIC1; pntrle->cjThis = cjTotal; pntrle->wchFirst = wchMin; /* Lowest unicode code point */ pntrle->wchLast = wchMax; /* Highest unicode code point */ pntrle->fdg.cjThis = sizeof( FD_GLYPHSET ) + (cRuns - 1) * sizeof( WCRUN ); pntrle->fdg.cGlyphsSupported = cHandles; pntrle->fdg.cRuns = cRuns; pntrle->fdg.awcrun[ 0 ].wcLow = ntrle.wchFirst; pntrle->fdg.awcrun[ 0 ].cGlyphs = cHandles; pntrle->fdg.awcrun[ 0 ].phg = phg; /* * We now wish to fill in the awcrun data. Filling it in now * simplifies operations later on. Now we can scan the bit array * data, and so easily figure out how large the runs are and * where abouts a particular HGLYPH is located. */ bInRun = FALSE; cRuns = 0; /* None so far */ iMax = 0; /* Count glyphs for address arithmetic */ for( iI = 1; iI <= (int)wchMax; ++iI ) { if( pdwBits[ iI / DWBITS ] & (1 << (iI & DW_MASK)) ) { /* Not in a run: is this the end of one? */ if( !bInRun ) { /* It's time to start one */ bInRun = TRUE; pntrle->fdg.awcrun[ cRuns ].wcLow = (WCHAR)iI; pntrle->fdg.awcrun[ cRuns ].cGlyphs = 0; pntrle->fdg.awcrun[ cRuns ].phg = phg + iMax; } pntrle->fdg.awcrun[ cRuns ].cGlyphs++; /* One more */ ++iMax; } else { if( bInRun ) { /* Not any more! */ bInRun = FALSE; ++cRuns; /* Onto the next structure */ } } } if( bInRun ) ++cRuns; /* It has finished now */ /* * Now go fill in the array of HGLYPHS. The actual format varies * depending upon the range of glyphs, and upon the CTT format. */ for( iIndex = 0, iI = ntrle.wchFirst; iI <= ntrle.wchLast; ++iI, ++iIndex ) { int iVal; /* Needs an address */ int cjData; /* Length of data to use */ WCHAR wchTemp; /* For Unicode mapping */ BYTE *pbData; /* Data to convert/move */ UHG uhg; /* Clearer (?) access to HGLYPH contents */ /* * Need to map this BYTE value into the appropriate WCHAR * value, then look for the location of the phg that fits. */ wchTemp = awch[ iIndex ]; phg = NULL; /* Flag that we failed */ pwcr = pntrle->fdg.awcrun; for( iMax = 0; iMax < cRuns; ++iMax ) { if( pwcr->wcLow <= wchTemp && (pwcr->wcLow + pwcr->cGlyphs) > wchTemp ) { /* Found the range, so now select the slot */ phg = pwcr->phg + wchTemp - pwcr->wcLow; break; } ++pwcr; } if( phg == NULL ) continue; /* Should not happen */ if( iI >= pCTT->chFirstChar && iI <= pCTT->chLastChar ) { /* * We need to look at the CTT data to see what we need to do. * How we do it depends upon the format we are using and * decided upon above. */ WCHAR wchTemp; wchTemp = iI - pCTT->chFirstChar; switch( pCTT->wType ) { case CTT_WTYPE_DIRECT: pbData = &pCTT->uCode.bCode[ wchTemp ]; cjData = 1; break; case CTT_WTYPE_PAIRED: pbData = &pCTT->uCode.bPairs[ wchTemp ][ 0 ]; cjData = *(pbData + 1) ? 2 : 1; break; case CTT_WTYPE_COMPOSE: pbData = (BYTE *)pCTT + pCTT->uCode.psCode[ wchTemp ]; cjData = pCTT->uCode.psCode[ wchTemp + 1 ] - pCTT->uCode.psCode[ wchTemp ]; break; } } else { /* Simple extension of the glyph index */ pbData = (BYTE *)&iVal; iVal = iI; cjData = (iI & 0xff00) ? 2 : 1; } /* * Now write out the resulting data. We have both an * address and a length, so turn this data into the desired * format, as decided above. */ switch( ntrle.wType ) { case RLE_L_OFFSET: /* Data is located following the array of HGLYPHs */ pb = (BYTE *)((int)((pb + sizeof( WORD ))) & ~(sizeof( WORD ) - 1)); /* Start of data is a WORD aligned WORD containing the index */ *((WORD *)pb) = iIndex; pb += sizeof( WORD ); memcpy( pb, pbData, cjData ); *phg = (HGLYPH)((cjData << 24) | (pb - pbBase)); pb += cjData; break; case RLE_LI_OFFSET: /* 8 bits index, length + 16 bit offset */ if( cjData <= OVERFLOW_SZ ) { /* Data fits in HGLYPH directly */ uhg.rlic.b0 = *pbData; uhg.rlic.b1 = cjData > 1 ? *(pbData + 1) : '\0'; } else { /* Data must be placed into the overflow area at the end */ uhg.rli.wOffset = pb - pbBase; memcpy( pb, pbData, cjData ); pb += cjData; } uhg.rli.bIndex = iIndex; uhg.rli.bLength = cjData; *phg = uhg.hg; break; case RLE_DIRECT: /* One or two bytes, as is */ case RLE_PAIRED: /* Two bytes, overstruck */ /* Relatively straight forward, depends upon CTT format */ uhg.rd.b0 = *pbData; uhg.rd.b1 = cjData > 1 ? *(pbData + 1) : '\0'; uhg.rd.wIndex = iIndex; *phg = uhg.hg; break; } } /* * If the bOffset parameter is true, then we are to return offset * values in the fdg.awcrun[].phg fields. These are offsets relative * to the beginning of the NT_RLE structure. Typically these are used * when converting the CTT tables to RLE format for inclusion in * the resource data of NT built minidrivers. The addresses are used * when doing the conversion on the fly within rasdd. */ if( bOffset ) { pwcr = pntrle->fdg.awcrun; /* Base address of WCRUNs */ for( iI = 0; iI < cRuns; ++iI, ++pwcr ) { (BYTE *)pwcr->phg -= (DWORD)pbBase; } } #if DBG if( (pb - pbBase) > cjTotal ) { DbgPrint( "Rasdd!ctt2rle: overflow of data area: alloc %ld, used %ld\n", cjTotal, pb - pbBase ); } #endif HeapFree( hheap, 0, (LPSTR)pdwBits ); return pntrle; }