#include #include #include #include #include #include #include #include #include "bootfont.h" // // The following structures and constants are used in font files: // DOS image header // OS/2 image header // OS/2 executable resource information structure // OS/2 executable resource name information structure // typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header USHORT e_magic; // Magic number USHORT e_cblp; // Bytes on last page of file USHORT e_cp; // Pages in file USHORT e_crlc; // Relocations USHORT e_cparhdr; // Size of header in paragraphs USHORT e_minalloc; // Minimum extra paragraphs needed USHORT e_maxalloc; // Maximum extra paragraphs needed USHORT e_ss; // Initial (relative) SS value USHORT e_sp; // Initial SP value USHORT e_csum; // Checksum USHORT e_ip; // Initial IP value USHORT e_cs; // Initial (relative) CS value USHORT e_lfarlc; // File address of relocation table USHORT e_ovno; // Overlay number USHORT e_res[4]; // Reserved words USHORT e_oemid; // OEM identifier (for e_oeminfo) USHORT e_oeminfo; // OEM information; e_oemid specific USHORT e_res2[10]; // Reserved words ULONG e_lfanew; // File address of new exe header } IMAGE_DOS_HEADER; #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ typedef struct _IMAGE_OS2_HEADER { // OS/2 .EXE header USHORT ne_magic; // Magic number CHAR ne_ver; // Version number CHAR ne_rev; // Revision number USHORT ne_enttab; // Offset of Entry Table USHORT ne_cbenttab; // Number of bytes in Entry Table long ne_crc; // Checksum of whole file USHORT ne_flags; // Flag word USHORT ne_autodata; // Automatic data segment number USHORT ne_heap; // Initial heap allocation USHORT ne_stack; // Initial stack allocation long ne_csip; // Initial CS:IP setting long ne_sssp; // Initial SS:SP setting USHORT ne_cseg; // Count of file segments USHORT ne_cmod; // Entries in Module Reference Table USHORT ne_cbnrestab; // Size of non-resident name table USHORT ne_segtab; // Offset of Segment Table USHORT ne_rsrctab; // Offset of Resource Table USHORT ne_restab; // Offset of resident name table USHORT ne_modtab; // Offset of Module Reference Table USHORT ne_imptab; // Offset of Imported Names Table long ne_nrestab; // Offset of Non-resident Names Table USHORT ne_cmovent; // Count of movable entries USHORT ne_align; // Segment alignment shift count USHORT ne_cres; // Count of resource segments UCHAR ne_exetyp; // Target Operating system UCHAR ne_flagsothers; // Other .EXE flags USHORT ne_pretthunks; // offset to return thunks USHORT ne_psegrefbytes; // offset to segment ref. bytes USHORT ne_swaparea; // Minimum code swap area size USHORT ne_expver; // Expected Windows version number } IMAGE_OS2_HEADER; #define IMAGE_OS2_SIGNATURE 0x454E // NE typedef struct _RESOURCE_TYPE_INFORMATION { USHORT Ident; USHORT Number; long Proc; } RESOURCE_TYPE_INFORMATION; #define FONT_DIRECTORY 0x8007 #define FONT_RESOURCE 0x8008 typedef struct _RESOURCE_NAME_INFORMATION { USHORT Offset; USHORT Length; USHORT Flags; USHORT Ident; USHORT Handle; USHORT Usage; } RESOURCE_NAME_INFORMATION; #pragma pack(1) typedef struct _OEM_FONT_FILE_HEADER { USHORT Version; ULONG FileSize; UCHAR Copyright[60]; USHORT Type; USHORT Points; USHORT VerticalResolution; USHORT HorizontalResolution; USHORT Ascent; USHORT InternalLeading; USHORT ExternalLeading; UCHAR Italic; UCHAR Underline; UCHAR StrikeOut; USHORT Weight; UCHAR CharacterSet; USHORT PixelWidth; USHORT PixelHeight; UCHAR Family; USHORT AverageWidth; USHORT MaximumWidth; UCHAR FirstCharacter; UCHAR LastCharacter; UCHAR DefaultCharacter; UCHAR BreakCharacter; USHORT WidthInBytes; ULONG Device; ULONG Face; ULONG BitsPointer; ULONG BitsOffset; UCHAR Filler; } OEM_FONT_FILE_HEADER; #pragma pack() #define OEM_FONT_VERSION 0x200 #define OEM_FONT_TYPE 0 #define OEM_FONT_CHARACTER_SET 255 #define OEM_FONT_FAMILY (3 << 4) #define FONT_WIDTH 8 typedef struct _FONT_CHAR { USHORT Width; USHORT Offset; } FONT_CHAR; union { IMAGE_DOS_HEADER DosHeader; IMAGE_OS2_HEADER Os2Header; OEM_FONT_FILE_HEADER FontHeader; RESOURCE_TYPE_INFORMATION ResourceType; RESOURCE_NAME_INFORMATION ResourceName; BOOTFONTBIN_HEADER BfbHeader; } FontHeaders; FONT_CHAR *FontCharMap; BYTE *FontCharData; unsigned FontDataBaseOffset; BYTE GlyphHeight; BYTE FontFirstChar,FontLastChar,FontDefaultChar; BYTE TopPad,BottomPad; unsigned BootfontFileHandle = (unsigned)(-1); UCHAR PendingLeadByte; unsigned SbcsCharCount; unsigned DbcsCharCount; ULONG SbcsFileOffset; ULONG DbcsFileOffset; #define DBCS_FIRST_LEAD 0x81 #define DBCS_LAST_LEAD 0xfe #define DBCS_FIRST_TRAIL 0x40 #define DBCS_LAST_TRAIL 0xfe // // HACK: the only place this lib is used is with enduser, // which already has the table of bit values we want. // Save the 8 bytes and use them. // extern BYTE BitValue[8]; BYTE LeadByteTable[128/8]; // 128 bits unsigned *DbcsCharOrdinalOffsetTable; unsigned *SbcsCharOrdinalOffsetTable; unsigned *FontCacheTable; BYTE *FontCache; unsigned NextCacheSlot; #define FONT_CACHE_CAPACITY 750 BOOL LoadBootfontBin( IN unsigned FileHandle, IN ULONG FileSize ); VOID UnloadBootfontBin( VOID ); VOID FontWriteBfbChar( IN UCHAR c, IN USHORT x, IN USHORT y, IN BYTE ForegroundPixelValue, IN BYTE BackgroundPixelValue ); BOOL _far FontLoadAndInit( IN FPCHAR Filename ) { BOOL b; ULONG FileSize; unsigned FileHandle; unsigned Count; int ScaleFactor; unsigned Offset,TableEndOffset; FONT_CHAR *map; unsigned hi,lo; FPVOID data; b = FALSE; // // Open the file and determine its size. // if(_dos_open(Filename,SH_DENYWR,&FileHandle)) { goto c0; } if(((FileSize = DosSeek(FileHandle,0,DOSSEEK_END)) == -1) || DosSeek(FileHandle,0,DOSSEEK_START)) { goto c1; } // // Read the DOS header. // if(_dos_read(FileHandle,&FontHeaders.DosHeader,sizeof(IMAGE_DOS_HEADER),&Count) || (Count != sizeof(IMAGE_DOS_HEADER))) { goto c1; } // // Special check for bootfont.bin-style font. // if(((BOOTFONTBIN_HEADER *)&FontHeaders.DosHeader)->Signature == BOOTFONTBIN_SIGNATURE) { return(LoadBootfontBin(FileHandle,FileSize)); } // // Cap file size to something reasonable (and that fits in a // 16 bit value). // if(FileSize > 60000) { goto c1; } // // Basic header check. // if((FontHeaders.DosHeader.e_magic != IMAGE_DOS_SIGNATURE) || (FontHeaders.DosHeader.e_lfanew < sizeof(IMAGE_DOS_HEADER))) { goto c1; } // // Retrieve some info from the dos header before overwriting it. // Offset = (unsigned)FontHeaders.DosHeader.e_lfanew; // // Read the OS/2 header and make sure the resource table exists. // if((DosSeek(FileHandle,FontHeaders.DosHeader.e_lfanew,DOSSEEK_START) != FontHeaders.DosHeader.e_lfanew) || _dos_read(FileHandle,&FontHeaders.Os2Header,sizeof(IMAGE_OS2_HEADER),&Count) || (Count != sizeof(IMAGE_OS2_HEADER)) || (FontHeaders.Os2Header.ne_magic != IMAGE_OS2_SIGNATURE) || (FontHeaders.Os2Header.ne_restab > 65535L) || (FontHeaders.Os2Header.ne_rsrctab > 65535L) || !(FontHeaders.Os2Header.ne_restab - FontHeaders.Os2Header.ne_rsrctab)) { goto c1; } // // Search for font resource. // TableEndOffset = Offset; Offset += (unsigned)FontHeaders.Os2Header.ne_rsrctab; TableEndOffset += (unsigned)FontHeaders.Os2Header.ne_restab; if((DosSeek(FileHandle,Offset,DOSSEEK_START) != Offset) || _dos_read(FileHandle,&ScaleFactor,2,&Count) || (Count != 2)) { goto c1; } Offset += 2; // skip scale factor FontHeaders.ResourceType.Ident = 0; while(Offset < TableEndOffset) { if((DosSeek(FileHandle,Offset,DOSSEEK_START) != Offset) || _dos_read(FileHandle,&FontHeaders.ResourceType,sizeof(RESOURCE_TYPE_INFORMATION),&Count) || (Count != sizeof(RESOURCE_TYPE_INFORMATION))) { goto c1; } if(FontHeaders.ResourceType.Ident == FONT_RESOURCE) { break; } Offset += sizeof(RESOURCE_TYPE_INFORMATION) + (FontHeaders.ResourceType.Number * sizeof(RESOURCE_NAME_INFORMATION)); } if(FontHeaders.ResourceType.Ident != FONT_RESOURCE) { goto c1; } // // Get to resource name information. // Offset += sizeof(RESOURCE_TYPE_INFORMATION); if((DosSeek(FileHandle,Offset,DOSSEEK_START) != Offset) || _dos_read(FileHandle,&FontHeaders.ResourceName,sizeof(RESOURCE_NAME_INFORMATION),&Count) || (Count != sizeof(RESOURCE_NAME_INFORMATION))) { goto c1; } // // Read the oem font file header and validate it. We don't read the // table map in this part, we read that later. // Offset = FontHeaders.ResourceName.Offset << ScaleFactor; if((DosSeek(FileHandle,Offset,DOSSEEK_START) != Offset) || _dos_read(FileHandle,&FontHeaders,sizeof(OEM_FONT_FILE_HEADER),&Count) || (Count != sizeof(OEM_FONT_FILE_HEADER)) || (FontHeaders.FontHeader.Version != OEM_FONT_VERSION) || (FontHeaders.FontHeader.Type != OEM_FONT_TYPE) || FontHeaders.FontHeader.Italic || FontHeaders.FontHeader.Underline || FontHeaders.FontHeader.StrikeOut || (FontHeaders.FontHeader.CharacterSet != OEM_FONT_CHARACTER_SET) || (FontHeaders.FontHeader.Family != OEM_FONT_FAMILY) || (FontHeaders.FontHeader.PixelWidth != FONT_WIDTH) || (FontHeaders.FontHeader.PixelHeight > 16 )) { goto c1; } // // Allocate memory for the mapping table and read it in. // FileSize = (FontHeaders.FontHeader.LastCharacter - FontHeaders.FontHeader.FirstCharacter) + 1; map = malloc((unsigned)FileSize * sizeof(FONT_CHAR)); if(!map) { goto c1; } if(_dos_read(FileHandle,map,(unsigned)FileSize*sizeof(FONT_CHAR),&Count) || (Count != ((unsigned)FileSize*sizeof(FONT_CHAR)))) { goto c2; } // // Find the lowest and highest offsets to determine where the file data is. // hi = 0; lo = (unsigned)(-1); for(Count=0; Count<(unsigned)FileSize; Count++) { if(map[Count].Offset < lo) { lo = map[Count].Offset; } if(map[Count].Offset > hi) { hi = map[Count].Offset; } } FileSize = (unsigned)((hi - lo) + FontHeaders.FontHeader.PixelHeight); data = malloc((unsigned)FileSize); if(!data) { goto c2; } Offset += lo; if((DosSeek(FileHandle,Offset,DOSSEEK_START) != Offset) || _dos_read(FileHandle,data,(unsigned)FileSize,&Count) || (Count != (unsigned)FileSize)) { goto c3; } if(FontCharMap) { free(FontCharMap); } FontCharMap = map; if(FontCharData) { free(FontCharData); } FontCharData = data; FontDataBaseOffset = lo; GlyphHeight = (BYTE)FontHeaders.FontHeader.PixelHeight; FontFirstChar = FontHeaders.FontHeader.FirstCharacter; FontLastChar = FontHeaders.FontHeader.LastCharacter; FontDefaultChar = FontHeaders.FontHeader.DefaultCharacter; TopPad = 1; BottomPad = 1; if(BootfontFileHandle != (unsigned)(-1)) { UnloadBootfontBin(); } b = TRUE; c3: if(!b) { free(data); } c2: if(!b) { free(map); } c1: _dos_close(FileHandle); c0: return(b); } BOOL LoadBootfontBin( IN unsigned FileHandle, IN ULONG FileSize ) /*++ Routine Description: This routine loads and initializes a font file in NT setup's bootfont.bin format. Arguments: FileHandle - supplies DOS file handle of file. FileSize - supplies size of file in bytes. Return Value: Boolean value indicating outcome. If TRUE, the file handle will be left open. If FALSE the file handle will have been closed. --*/ { BOOL b; unsigned Count; unsigned i; unsigned MaxChars,CharsLeft; unsigned BytesPerChar; unsigned index; unsigned ordinal; unsigned nextslot; FPBYTE p; FPBYTE ScratchBuffer; unsigned *Table1,*Table2,*Table3; BYTE *cache; unsigned CacheOrd; b = FALSE; // // Rewind the file and read the header. // if(DosSeek(FileHandle,0,DOSSEEK_START) || _dos_read(FileHandle,&FontHeaders.BfbHeader,sizeof(BOOTFONTBIN_HEADER),&Count) || (Count != sizeof(BOOTFONTBIN_HEADER))) { goto c1; } // // Basic checks. // if((FontHeaders.BfbHeader.CharacterImageSbcsWidth != FONT_WIDTH) || (FontHeaders.BfbHeader.CharacterImageDbcsWidth != (2*FONT_WIDTH))) { goto c1; } // // Make sure the DBCS table looks good. No ranges can be in ASCII range, // the ranges must be legal (ie, end greater than start), and the table // must be terminated with a pair of 0s. // for(Count=0; FontHeaders.BfbHeader.DbcsLeadTable[Count] && FontHeaders.BfbHeader.DbcsLeadTable[Count+1] && (Count < (2*MAX_DBCS_RANGE)); Count+=2) { if((FontHeaders.BfbHeader.DbcsLeadTable[Count] < DBCS_FIRST_LEAD) || (FontHeaders.BfbHeader.DbcsLeadTable[Count+1] < DBCS_FIRST_LEAD) || (FontHeaders.BfbHeader.DbcsLeadTable[Count] > DBCS_LAST_LEAD) || (FontHeaders.BfbHeader.DbcsLeadTable[Count+1] > DBCS_LAST_LEAD) || (FontHeaders.BfbHeader.DbcsLeadTable[Count] > FontHeaders.BfbHeader.DbcsLeadTable[Count+1])) { goto c1; } } if(FontHeaders.BfbHeader.DbcsLeadTable[Count] || FontHeaders.BfbHeader.DbcsLeadTable[Count+1]) { goto c1; } // // Now we build a table of characters and offset numbers // into the file, indexed by character value. The theoretical // maximum number of DBCS chars is when all of 81-fe are leads and // each of 40-fe are trails for each lead byte; 7e * bf = 5e02 (24066) // separate DBCS characters. (Actually 7f is not a valid trail byte but // that only shaves 126 chars off the total, which not worth the headache.) // Each character requires 2 bytes for an ordinal number in the font file, // which gives a theoretical maximum table size of bc04 bytes. Mercifully // this is much less than the malloc max of ffe8 bytes. // // We do something similar for the SBCS case also. // #define TABLE1_SIZE (2*(((DBCS_LAST_LEAD-DBCS_FIRST_LEAD)+1) * ((DBCS_LAST_TRAIL-DBCS_FIRST_TRAIL)+1))) #define TABLE2_SIZE (2*255) #define TABLE3_SIZE (2*(FontHeaders.BfbHeader.NumSbcsChars + FontHeaders.BfbHeader.NumDbcsChars)) Table1 = malloc(TABLE1_SIZE); if(!Table1) { goto c1; } Table2 = malloc(TABLE2_SIZE); if(!Table2) { goto c2; } Table3 = malloc(TABLE3_SIZE); if(!Table3) { goto c3; } // // Each slot in the font cache is a 2 byte header indicating the ordinal // value of the character cached in the slot, and then the bits that // make up the glyph. Entries are sized for double-byte chars even though // this wastes space for the single-byte case. // cache = malloc(FONT_CACHE_CAPACITY * (FontHeaders.BfbHeader.CharacterImageHeight+2) * 2); if(!cache) { goto c4; } memset(Table1,0,TABLE1_SIZE); memset(Table2,0,TABLE2_SIZE); memset(Table3,0xff,TABLE3_SIZE); if(DosSeek(FileHandle,FontHeaders.BfbHeader.DbcsOffset,DOSSEEK_START) != FontHeaders.BfbHeader.DbcsOffset) { goto c5; } #define SCRATCH_SIZE 18000 // exactly 1000 chars in typical case ScratchBuffer = malloc(SCRATCH_SIZE); if(!ScratchBuffer) { goto c5; } // // Build an offset table for sbcs chars. // There are a max of 255 SBCS chars (1-255). // BytesPerChar = (FontHeaders.BfbHeader.CharacterImageHeight)+1; if(DosSeek(FileHandle,FontHeaders.BfbHeader.SbcsOffset,DOSSEEK_START) != FontHeaders.BfbHeader.SbcsOffset) { free(ScratchBuffer); goto c5; } MaxChars = SCRATCH_SIZE / BytesPerChar; CharsLeft = FontHeaders.BfbHeader.NumSbcsChars; ordinal = 0; CacheOrd = 0; while(CharsLeft) { Count = CharsLeft; if(Count > MaxChars) { Count = MaxChars; } if(_dos_read(FileHandle,ScratchBuffer,Count*BytesPerChar,&i) || (i != (Count*BytesPerChar))) { free(ScratchBuffer); goto c5; } CharsLeft -= Count; for(p=ScratchBuffer,i=0; i= ' ') && (p[0] <= 'z')) { *(unsigned *)&cache[2*BytesPerChar*CacheOrd] = ordinal; memmove(cache+(2*BytesPerChar*CacheOrd)+2,&p[1],BytesPerChar-1); Table3[ordinal] = CacheOrd++; } } } nextslot = CacheOrd; BytesPerChar = (FontHeaders.BfbHeader.CharacterImageHeight*2)+2; MaxChars = SCRATCH_SIZE / BytesPerChar; CharsLeft = FontHeaders.BfbHeader.NumDbcsChars; ordinal = 0; while(CharsLeft) { Count = CharsLeft; if(Count > MaxChars) { Count = MaxChars; } if(_dos_read(FileHandle,ScratchBuffer,Count*BytesPerChar,&i) || (i != (Count*BytesPerChar))) { free(ScratchBuffer); goto c5; } CharsLeft -= Count; for(p=ScratchBuffer,i=0; i DBCS_LAST_LEAD) || (p[1] < DBCS_FIRST_TRAIL) || (p[1] > DBCS_LAST_TRAIL)) { // // Invalid DBCS value, skip this character // continue; } index = (unsigned)(p[0] - DBCS_FIRST_LEAD); index <<= 8; index |= p[1] - DBCS_FIRST_TRAIL; index -= (unsigned)(p[0] - DBCS_FIRST_LEAD) * (DBCS_FIRST_TRAIL + (255-DBCS_LAST_TRAIL)); Table1[index] = ordinal; // // Cache first n chars that fit in the cache // if(CacheOrd < FONT_CACHE_CAPACITY) { *(unsigned *)&cache[CacheOrd*BytesPerChar] = ordinal+FontHeaders.BfbHeader.NumSbcsChars; memmove(cache+(CacheOrd*BytesPerChar)+2,&p[2],BytesPerChar-2); Table3[ordinal+FontHeaders.BfbHeader.NumSbcsChars] = CacheOrd++; } } } free(ScratchBuffer); // // Everything looks good. Set up globals. // memset(LeadByteTable,0,sizeof(LeadByteTable)); for(Count=0; FontHeaders.BfbHeader.DbcsLeadTable[Count] && FontHeaders.BfbHeader.DbcsLeadTable[Count+1]; Count+=2) { for(i = FontHeaders.BfbHeader.DbcsLeadTable[Count]; i <= FontHeaders.BfbHeader.DbcsLeadTable[Count+1]; i++) { LeadByteTable[(i-128)/8] |= BitValue[(i-128)%8]; } } SbcsCharCount = FontHeaders.BfbHeader.NumSbcsChars; DbcsCharCount = FontHeaders.BfbHeader.NumDbcsChars; GlyphHeight = FontHeaders.BfbHeader.CharacterImageHeight; TopPad = FontHeaders.BfbHeader.CharacterTopPad; BottomPad = FontHeaders.BfbHeader.CharacterBottomPad; SbcsFileOffset = FontHeaders.BfbHeader.SbcsOffset; DbcsFileOffset = FontHeaders.BfbHeader.DbcsOffset; if(BootfontFileHandle != (unsigned)(-1)) { UnloadBootfontBin(); } DbcsCharOrdinalOffsetTable = Table1; SbcsCharOrdinalOffsetTable = Table2; FontCacheTable = Table3; FontCache = cache; NextCacheSlot = nextslot; BootfontFileHandle = FileHandle; if(FontCharMap) { free(FontCharMap); FontCharMap = NULL; } if(FontCharData) { free(FontCharData); FontCharData = NULL; } b = TRUE; c5: if(!b) { free(cache); } c4: if(!b) { free(Table3); } c3: if(!b) { free(Table2); } c2: if(!b) { free(Table1); } c1: if(!b) { _dos_close(FileHandle); } return(b); } VOID UnloadBootfontBin( VOID ) { _dos_close(BootfontFileHandle); BootfontFileHandle = (unsigned)(-1); PendingLeadByte = 0; free(DbcsCharOrdinalOffsetTable); free(SbcsCharOrdinalOffsetTable); free(FontCacheTable); free(FontCache); DbcsCharOrdinalOffsetTable = NULL; SbcsCharOrdinalOffsetTable = NULL; FontCacheTable = NULL; FontCache = NULL; } VOID _far FontGetInfo( OUT FPBYTE Width, OUT FPBYTE Height ) { *Width = FONT_WIDTH; *Height = GlyphHeight + TopPad + BottomPad; } VOID _far FontWriteChar( IN UCHAR c, IN USHORT x, IN USHORT y, IN BYTE ForegroundPixelValue, IN BYTE BackgroundPixelValue ) { BYTE PixelMap[2]; if(BootfontFileHandle != (unsigned)(-1)) { // // Use bootfont.bin method // FontWriteBfbChar(c,x,y,ForegroundPixelValue,BackgroundPixelValue); return; } PixelMap[0] = BackgroundPixelValue; PixelMap[1] = ForegroundPixelValue; if((c < FontFirstChar) || (c > FontLastChar)) { c = FontDefaultChar; } // // Pad if necessary by filling in background // if(BackgroundPixelValue < VGAPIX_TRANSPARENT) { if(TopPad) { VgaClearRegion(x,y,FONT_WIDTH,TopPad,BackgroundPixelValue); } if(BottomPad) { VgaClearRegion(x,y+TopPad+GlyphHeight,FONT_WIDTH,BottomPad,BackgroundPixelValue); } } VgaBitBlt( x, y + TopPad, FONT_WIDTH, GlyphHeight, 1, FALSE, PixelMap, FontCharData + (FontCharMap[c-FontFirstChar].Offset - FontDataBaseOffset) ); } VOID _far FontWriteString( IN UCHAR *String, IN USHORT x, IN USHORT y, IN BYTE ForegroundPixelValue, IN BYTE BackgroundPixelValue ) { for( ; *String; String++) { FontWriteChar(*String,x,y,ForegroundPixelValue,BackgroundPixelValue); x += FONT_WIDTH; } PendingLeadByte = 0; } VOID FontWriteBfbChar( IN UCHAR c, IN USHORT x, IN USHORT y, IN BYTE ForegroundPixelValue, IN BYTE BackgroundPixelValue ) { unsigned scale; unsigned index; unsigned Ordinal; unsigned i,read; ULONG FileOffset = 0; FPBYTE Glyph = NULL; BYTE PixelMap[2]; FPBYTE p; if(PendingLeadByte) { // // Got second half of DBCS character. Render now. // index = (unsigned)(PendingLeadByte - DBCS_FIRST_LEAD); index <<= 8; index |= c - DBCS_FIRST_TRAIL; index -= (unsigned)(PendingLeadByte - DBCS_FIRST_LEAD) * (DBCS_FIRST_TRAIL + (255-DBCS_LAST_TRAIL)); PendingLeadByte = 0; Ordinal = DbcsCharOrdinalOffsetTable[index]; // // Is this character cached? // if(FontCacheTable[Ordinal+SbcsCharCount] == (unsigned)(-1)) { // // No, need to cache it. // FileOffset = ((ULONG)Ordinal * ((2 * GlyphHeight) + 2)) + DbcsFileOffset + 2; } else { // // Yes, get glyph. // Glyph = FontCache + (((2 * GlyphHeight) + 2) * FontCacheTable[Ordinal+SbcsCharCount]) + 2; } Ordinal += SbcsCharCount; x -= FONT_WIDTH; scale = 2; } else { // // See if DBCS char or a lead byte // if((c >= DBCS_FIRST_LEAD) && (LeadByteTable[(c-128)/8] & BitValue[(c-128)%8])) { PendingLeadByte = c; return; } // // SBCS char. // Ordinal = SbcsCharOrdinalOffsetTable[c-1]; // // Is this character cached? // if(FontCacheTable[Ordinal] == (unsigned)(-1)) { // // No, need to cache it. // FileOffset = ((ULONG)Ordinal * (GlyphHeight + 1)) + SbcsFileOffset + 1; } else { // // Yes, get glyph // Glyph = FontCache + (((2 * GlyphHeight) + 2) * FontCacheTable[Ordinal]) + 2; } scale = 1; } if(FileOffset) { // // Pull the character in from the file. // Glyph = NULL; if(DosSeek(BootfontFileHandle,FileOffset,DOSSEEK_START) == FileOffset) { // // Point at the entry in the font cache where we're going // to stick the glyph. // p = FontCache + (NextCacheSlot * ((2 * GlyphHeight) + 2)); // // Invalidate the caching for the character currently // cached in the slot we're going to overwrite. If the read // fails halfway through, the glyph may be trashed anyway, // so we do it before we know if the read succeeds. // FontCacheTable[*(unsigned *)p] = (unsigned)(-1); i = _dos_read(BootfontFileHandle,p+2,scale*GlyphHeight,&read); if(!i && (read == (scale * GlyphHeight))) { *(unsigned *)p = Ordinal; Glyph = p+2; FontCacheTable[Ordinal] = NextCacheSlot++; if(NextCacheSlot == FONT_CACHE_CAPACITY) { NextCacheSlot = 0; } } } } if(Glyph) { // // Pad if necessary by filling in background // if(BackgroundPixelValue < VGAPIX_TRANSPARENT) { if(TopPad) { VgaClearRegion(x,y,scale*FONT_WIDTH,TopPad,BackgroundPixelValue); } if(BottomPad) { VgaClearRegion(x,y+TopPad+GlyphHeight,scale*FONT_WIDTH,BottomPad,BackgroundPixelValue); } } PixelMap[0] = BackgroundPixelValue; PixelMap[1] = ForegroundPixelValue; VgaBitBlt( x, y + TopPad, scale*FONT_WIDTH, GlyphHeight, scale, FALSE, PixelMap, Glyph ); } else { // // Put a block up there. // VgaClearRegion(x,y,scale*FONT_WIDTH,TopPad+BottomPad+GlyphHeight,ForegroundPixelValue); } }