1036 lines
27 KiB
C
1036 lines
27 KiB
C
|
#include <dos.h>
|
||
|
#include <share.h>
|
||
|
#include <stddef.h>
|
||
|
#include <malloc.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include <mytypes.h>
|
||
|
#include <misclib.h>
|
||
|
#include <displib.h>
|
||
|
|
||
|
#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<Count; i++,p+=BytesPerChar,ordinal++) {
|
||
|
|
||
|
if(!p[0]) {
|
||
|
//
|
||
|
// Invalid value, skip this character
|
||
|
//
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
index = (unsigned)p[0] - 1;
|
||
|
|
||
|
Table2[index] = ordinal;
|
||
|
|
||
|
//
|
||
|
// Cache most chars in the ascii range.
|
||
|
//
|
||
|
if((p[0] >= ' ') && (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<Count; i++,p+=BytesPerChar,ordinal++) {
|
||
|
|
||
|
if((p[0] < DBCS_FIRST_LEAD) || (p[0] > 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);
|
||
|
}
|
||
|
}
|