|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
convfont.c
Abstract:
This module contains the code that implements a bootfont.bin conversion program. This tool converts a bootfont.bin that is circa windows 2000 \ nt4 and converts it into the windows whistler format. The new format includes a column of information on unicode translation of MBCS characters.
Author:
Matt Holle (MattH) 8-March-2001
Revision History:
--*/
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <locale.h>
// #include "..\..\lib\i386\bootfont.h"
// #include "fonttable.h"
#define BYTES_PER_SBCS_CHARACTER (17)
#define BYTES_PER_DBCS_CHARACTER (34)
//
// Define maximum number of dbcs lead byte ranges we support.
//
#define MAX_DBCS_RANGE 5
//
// Define signature value.
//
#define BOOTFONTBIN_SIGNATURE 0x5465644d
//
// Define structure used as a header for the bootfont.bin file.
//
typedef struct _BOOTFONTBIN_HEADER {
//
// Signature. Must be BOOTFONTBIN_SIGNATURE.
//
ULONG Signature;
//
// Language id of the language supported by this font.
// This should match the language id of resources in msgs.xxx.
//
ULONG LanguageId;
//
// Number of sbcs characters and dbcs characters contained in the file.
//
unsigned NumSbcsChars; unsigned NumDbcsChars;
//
// Offsets within the file to the images.
//
unsigned SbcsOffset; unsigned DbcsOffset;
//
// Total sizes of the images.
//
unsigned SbcsEntriesTotalSize; unsigned DbcsEntriesTotalSize;
//
// Dbcs lead byte table. Must contain a pair of 0's to indicate the end.
//
UCHAR DbcsLeadTable[(MAX_DBCS_RANGE+1)*2];
//
// Height values for the font.
// CharacterImageHeight is the height in scan lines/pixels of the
// font image. Each character is drawn with additional 'padding'
// lines on the top and bottom, whose sizes are also contained here.
//
UCHAR CharacterImageHeight; UCHAR CharacterTopPad; UCHAR CharacterBottomPad;
//
// Width values for the font. These values contain the width in pixels
// of a single byte character and double byte character.
//
// NOTE: CURRENTLY THE SINGLE BYTE WIDTH *MUST* BE 8 AND THE DOUBLE BYTE
// WIDTH *MUST* BE 16!!!
//
UCHAR CharacterImageSbcsWidth; UCHAR CharacterImageDbcsWidth;
} BOOTFONTBIN_HEADER, *PBOOTFONTBIN_HEADER;
int __cdecl main( IN int argc, IN char *argv[] ) { HANDLE hInputFile = INVALID_HANDLE_VALUE; HANDLE hOutputFile = INVALID_HANDLE_VALUE; DWORD BytesWritten = 0; BOOL b; BOOL Verbose = FALSE; BOOTFONTBIN_HEADER *pHeader; ULONG u = 0; ULONG i = 0; UCHAR *SBCSFontImage; UCHAR *DBCSFontImage; UCHAR *Operator; WCHAR UnicodeValue; UCHAR *ExistingFileBuffer = NULL; BOOLEAN DumpIt = FALSE;
if( !strcmp(argv[argc-1], "-v") ) { Verbose = TRUE; } else { if( !strcmp(argv[argc-1], "-d") ) { DumpIt = TRUE; Verbose = TRUE; } } if( !DumpIt && (argc < 3)) { fprintf(stderr,"Usage: %s <inputfile> <outputfile> [-v] [-d]\n",argv[0]); fprintf(stderr,"\n" ); fprintf(stderr," Where <inputfile> is a bootfont.bin file to be translated\n"); fprintf(stderr," into the new format\n"); fprintf(stderr,"\n" ); fprintf(stderr," <outputfile> is the destination file.\n" ); fprintf(stderr,"\n" ); fprintf(stderr," -v operate in a verbose manner.\n" ); fprintf(stderr,"\n" ); fprintf(stderr," -d dump the contents of <inputfile> in a readable format.\n" ); fprintf(stderr," Here, no outputfile need be specified.\n" ); fprintf(stderr,"\n" ); fprintf(stderr," NOTE: You must have the proper locale files installed and configured on your\n" ); fprintf(stderr," machine. To do this, start up intl.cpl, go to the Advanced tab and select.\n" ); fprintf(stderr," the Language setting to correspond to the language of the bootfont.bin file.\n" ); fprintf(stderr," Make sure you check the 'Apply all settings to the current...' tab too.\n" ); fprintf(stderr,"\n" ); goto Cleanup; }
if( Verbose && !DumpIt ) { //
// spew input.
//
printf( "Running in Verbose Mode\n" ); printf( "InputFile: %s\n", argv[1] ); printf( "OutputFile: %s\n", argv[2] ); } //
// Open the input file.
//
hInputFile = CreateFile( argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
if(hInputFile == INVALID_HANDLE_VALUE) { fprintf( stderr, "\nUnable to open input file %s (%u)\n", argv[1], GetLastError()); goto Cleanup; }
if( !DumpIt ) { //
// Create the output file.
//
hOutputFile = CreateFile( argv[2], FILE_GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL ); if(hOutputFile == INVALID_HANDLE_VALUE) { fprintf( stderr, "\nUnable to create output file %s (%u)\n", argv[2], GetLastError()); goto Cleanup; } }
//
// Figure out how big the existing file is.
//
BytesWritten = GetFileSize( hInputFile, NULL );
if( BytesWritten == (DWORD)(-1) ) { fprintf( stderr, "\nAn error occured getting the file size.\n" ); goto Cleanup; }
//
// Allocate a buffer for the file.
//
ExistingFileBuffer = malloc(BytesWritten + 3);
b = ReadFile( hInputFile, ExistingFileBuffer, BytesWritten, &i, NULL );
CloseHandle( hInputFile ); hInputFile = INVALID_HANDLE_VALUE;
if( !b ) { fprintf( stderr, "\nError reading input file %s\n", argv[1] ); goto Cleanup; }
//
// Read in the header.
//
pHeader = (BOOTFONTBIN_HEADER *)ExistingFileBuffer;
// Tell the user about the bootfont.bin file that we read.
if( Verbose ) { printf( "Size of BOOTFONTBIN_HEADER: %d\n", sizeof(BOOTFONTBIN_HEADER) ); printf( "\nRead Header Data:\n" ); printf( "=================\n" ); printf( "Header.Signature: 0x%08lx\n", pHeader->Signature ); printf( "Header.LanguageId: 0x%08lx\n", pHeader->LanguageId ); printf( "Header.NumSbcsChars: 0x%08lx\n", pHeader->NumSbcsChars ); printf( "Header.NumDbcsChars: 0x%08lx\n", pHeader->NumDbcsChars ); printf( "Header.SbcsOffset: 0x%08lx\n", pHeader->SbcsOffset ); printf( "Header.DbcsOffset: 0x%08lx\n", pHeader->DbcsOffset ); printf( "Header.SbcsEntriesTotalSize: 0x%08lx\n", pHeader->SbcsEntriesTotalSize ); printf( "Header.DbcsEntriesTotalSize: 0x%08lx\n", pHeader->DbcsEntriesTotalSize ); printf( "Header.CharacterImageHeight: 0x%02lx\n", pHeader->CharacterImageHeight ); printf( "Header.CharacterTopPad: 0x%02lx\n", pHeader->CharacterTopPad ); printf( "Header.CharacterBottomPad: 0x%02lx\n", pHeader->CharacterBottomPad ); printf( "Header.CharacterImageSbcsWidth: 0x%02lx\n", pHeader->CharacterImageSbcsWidth ); printf( "Header.CharacterImageDbcsWidth: 0x%02lx\n", pHeader->CharacterImageDbcsWidth ); printf( "\n" ); }
if( DumpIt ) { ULONG j; //
// Just Dump the contents of the bootfont.bin file in
// a more readable format.
//
SBCSFontImage = ExistingFileBuffer + pHeader->SbcsOffset; DBCSFontImage = ExistingFileBuffer + pHeader->DbcsOffset;
i = pHeader->SbcsEntriesTotalSize / pHeader->NumSbcsChars;
if( i == BYTES_PER_SBCS_CHARACTER+2 ) { printf( "Dumping contents of newstyled file %s\n", argv[1] );
printf( "\nSBCS Values:\n" ); printf( "============\n" ); for( u=0; u < pHeader->NumSbcsChars; u++ ) {
// jump to the u-th element. Each element contains BYTES_PER_SBCS_CHARACTER
// bytes, plus another 2 bytes for the UNICODE value sitting at the end
// of the entry.
Operator = SBCSFontImage + (u * (BYTES_PER_SBCS_CHARACTER+2)); printf( "SBCS Char Code: 0x%02lx\n", *Operator ); printf( " Unicode Code: 0x%04lx\n", *(WCHAR *)(Operator + BYTES_PER_SBCS_CHARACTER) ); printf( " Glyph: " ); Operator += 1; for( j = 1; j < BYTES_PER_SBCS_CHARACTER; j++ ) { printf( "0x%02x ", *Operator ); Operator++; } printf( "\n\n" );
}
printf( "\nDBCS Values:\n" ); printf( "============\n" ); for( u=0; u < pHeader->NumDbcsChars; u++ ) {
// jump to the u-th element. Each element contains BYTES_PER_DBCS_CHARACTER
// bytes, plus another 2 bytes for the UNICODE value sitting at the end
// of the entry.
Operator = DBCSFontImage + (u * (BYTES_PER_DBCS_CHARACTER+2)); printf( "DBCS Char Code: 0x%04lx\n", *Operator ); printf( " Unicode Code: 0x%04lx\n", *(WCHAR *)(Operator + BYTES_PER_DBCS_CHARACTER) ); printf( " Glyph: " ); Operator += 2; for( j = 1; j < BYTES_PER_DBCS_CHARACTER; j++ ) { printf( "0x%02x ", *Operator ); Operator++; } printf( "\n\n" );
}
printf( "\n\n" ); goto Cleanup;
} else { printf( "Dumping contents of oldstyle file %s\n", argv[1] );
printf( "\nSBCS Values:\n" ); printf( "============\n" ); for( u=0; u < pHeader->NumSbcsChars; u++ ) {
// jump to the u-th element. Each element contains BYTES_PER_SBCS_CHARACTER
// bytes.
Operator = SBCSFontImage + (u * (BYTES_PER_SBCS_CHARACTER)); printf( "SBCS Char Code: 0x%02lx\n", *Operator ); printf( " Glyph: " ); Operator += 1; for( j = 1; j < BYTES_PER_SBCS_CHARACTER; j++ ) { printf( "0x%02x ", *Operator ); Operator++; } printf( "\n\n" );
}
printf( "\nDBCS Values:\n" ); printf( "============\n" ); for( u=0; u < pHeader->NumDbcsChars; u++ ) {
// jump to the u-th element. Each element contains BYTES_PER_DBCS_CHARACTER
// bytes.
Operator = DBCSFontImage + (u * (BYTES_PER_DBCS_CHARACTER)); printf( "DBCS Char Code: 0x%04lx\n", *Operator ); printf( " Glyph: " ); Operator += 2; for( j = 1; j < BYTES_PER_DBCS_CHARACTER; j++ ) { printf( "0x%02x ", *Operator ); Operator++; } printf( "\n\n" );
}
printf( "\n\n" ); goto Cleanup; }
}
//
// Verify the header's signature.
//
if( pHeader->Signature != BOOTFONTBIN_SIGNATURE ) { fprintf( stderr, "\nInputfile %s does not have a valid signature\n", argv[1] ); goto Cleanup; }
//
// Verify that this isn't already in the new format. We can test this by
// looking at how many SBCS characters are stored in here. Then looking at
// how big the header says the SBCS data section is.
//
// We know that for each SBCS character, we would have:
// 1 byte for the SBCS character
// 16 bytes for the glyph
//
// If it's an old-style bootfont.bin, the total size of the SBCS data block
// should be 17 times bigger than the number of SBCS characters. However, if
// it's a new-style bootfont.bin, it will be 19 times bigger because we've
// added 2 bytes onto the end of each SBCS entry (for a total of 19 bytes).
//
i = pHeader->SbcsEntriesTotalSize / pHeader->NumSbcsChars; if( i != BYTES_PER_SBCS_CHARACTER ) {
if( i == (BYTES_PER_SBCS_CHARACTER+2) ) { fprintf( stderr, "\nThis input file is already in the new format.\n" ); } else { fprintf( stderr, "\nThis input file has an abnormal number of bytes per SBCS character (%d)\n", i ); }
goto Cleanup; }
//
// Now check the number of bytes per DBCS character.
//
i = pHeader->DbcsEntriesTotalSize / pHeader->NumDbcsChars; if( i != BYTES_PER_DBCS_CHARACTER ) {
if( i == (BYTES_PER_DBCS_CHARACTER+2) ) { fprintf( stderr, "\nThis input file is already in the new format.\n" ); } else { fprintf( stderr, "\nThis input file has an abnormal number of bytes per DBCS character (%d)\n", i ); } goto Cleanup; }
//
// Looking good.
//
printf( "Processing %s...\n", argv[1] );
//
// Before updating and writing out the header, we need to examine
// the header and remember where the SBCS and DBCS data blocks are
// in our image.
//
SBCSFontImage = ExistingFileBuffer + pHeader->SbcsOffset; DBCSFontImage = ExistingFileBuffer + pHeader->DbcsOffset;
//
// Fixup the Header, then write it out.
//
// Add 2 bytes for each entry for our unicode appendage
pHeader->SbcsEntriesTotalSize += (pHeader->NumSbcsChars * 2); pHeader->DbcsEntriesTotalSize += (pHeader->NumDbcsChars * 2);
// The offset to the DBCS data block will have changed now too.
pHeader->DbcsOffset = pHeader->SbcsOffset + pHeader->SbcsEntriesTotalSize;
// Tell the user about the bootfont.bin file that we read.
if( Verbose ) { printf( "\nUpdated Header Data:\n" ); printf( "======================\n" ); printf( "Header.Signature: 0x%08lx\n", pHeader->Signature ); printf( "Header.LanguageId: 0x%08lx\n", pHeader->LanguageId ); printf( "Header.NumSbcsChars: 0x%08lx\n", pHeader->NumSbcsChars ); printf( "Header.NumDbcsChars: 0x%08lx\n", pHeader->NumDbcsChars ); printf( "Header.SbcsOffset: 0x%08lx\n", pHeader->SbcsOffset ); printf( "Header.DbcsOffset: 0x%08lx\n", pHeader->DbcsOffset ); printf( "Header.SbcsEntriesTotalSize: 0x%08lx\n", pHeader->SbcsEntriesTotalSize ); printf( "Header.DbcsEntriesTotalSize: 0x%08lx\n", pHeader->DbcsEntriesTotalSize ); printf( "\n" ); }
//
// Write the header.
//
b = WriteFile( hOutputFile, pHeader, sizeof(BOOTFONTBIN_HEADER), &BytesWritten, NULL ); if(!b) { fprintf( stderr, "\nError writing output file %s (%u)\n", argv[2], GetLastError()); goto Cleanup; }
//
// Write the sbcs images.
//
if( !Verbose ) { printf( "Operating on SBCS character code: 0x00" ); }
for( u=0; u < pHeader->NumSbcsChars; u++ ) {
// jump to the u-th element. 1 byte for the SBCS character, 16 for the
// glyph.
Operator = SBCSFontImage + (u * BYTES_PER_SBCS_CHARACTER);
b = WriteFile( hOutputFile, Operator, BYTES_PER_SBCS_CHARACTER, &BytesWritten, NULL );
if( !b ) { fprintf( stderr, "\nFailed to write SBCS character data.\n" ); goto Cleanup; }
//
// We must use MultiByteToWideChar to convert from SBCS to unicode.
//
// MultiByteToWideChar doesn't seem to work when converting
// from DBCS to unicode, so there we use mbtowc.
//
#if 0
if( !mbtowc( (WCHAR *)&UnicodeValue, Operator, 1 ) ) {
#else
if( !MultiByteToWideChar( CP_OEMCP, MB_ERR_INVALID_CHARS, Operator, 1, (WCHAR *)&UnicodeValue, sizeof(WCHAR) ) ) { #endif
UnicodeValue = 0x3F;
if( Verbose ) { fprintf( stderr, "\nFailed to convert SBCS character 0x%02lx to a unicode value. Using '?' character.\n", *Operator ); } }
if( Verbose ) { printf( "Converting SBCS character code: 0x%02lx to a unicode value: 0x%04lx\n", *Operator, UnicodeValue ); } else { printf( "\b\b\b\b0x%02lx", *Operator ); }
b = WriteFile( hOutputFile, &UnicodeValue, sizeof(USHORT), &BytesWritten, NULL );
if( !b ) { fprintf( stderr, "\nFailed to write SBCS encoded UNICODE value.\n" ); goto Cleanup; }
}
printf( "\nCompleted processing %d SBCS characters.\n\n", pHeader->NumSbcsChars );
//
// Write the dbcs images.
//
if( !Verbose ) { printf( "Operating on DBCS character code: 0x0000" ); }
for( u=0; u < pHeader->NumDbcsChars; u++ ) {
// jump to the u-th element. 1 byte for the SBCS character, 16 for the
// glyph.
Operator = DBCSFontImage + (u * BYTES_PER_DBCS_CHARACTER); b = WriteFile( hOutputFile, Operator, BYTES_PER_DBCS_CHARACTER, &BytesWritten, NULL );
if( !b || (BytesWritten != BYTES_PER_DBCS_CHARACTER) ) {
fprintf( stderr, "\nFailed to write DBCS character data.\n" ); goto Cleanup; }
//
// We must use mbtowc to convert from DBCS to unicode.
//
// Whereas, mbtowc doesn't seem to work when converting
// from SBCS to unicode, so there we use MultiByteToWideChar.
//
#if 0
if( !mbtowc( (WCHAR *)&UnicodeValue, Operator, 2 ) ) { #else
if( !MultiByteToWideChar( CP_OEMCP, MB_ERR_INVALID_CHARS, Operator, 2, (WCHAR *)&UnicodeValue, sizeof(WCHAR) ) ) { #endif
UnicodeValue = 0x3F;
if( Verbose ) { fprintf( stderr, "\nFailed to convert DBCS character 0x%04lx to a unicode value. Using '?' character.\n", *(WCHAR *)Operator ); } } if( Verbose ) { printf( "Converting DBCS character code: 0x%04lx to Unicode value: 0x%04lx\n", *(WCHAR *)Operator, UnicodeValue ); } else { printf( "\b\b\b\b\b\b0x%04lx", *(WCHAR *)Operator ); }
b = WriteFile( hOutputFile, &UnicodeValue, sizeof(WCHAR), &BytesWritten, NULL ); if( !b || (BytesWritten != sizeof(WCHAR)) ) {
fprintf( stderr, "\nFailed to write DBCS encoded UNICODE value.\n" ); goto Cleanup; }
}
printf( "\nCompleted processing %d DBCS characters.\n", pHeader->NumDbcsChars );
printf( "\nSuccessfully Processed file %s to %s.\n", argv[1], argv[2] );
//
// Done.
//
Cleanup: if( hInputFile != INVALID_HANDLE_VALUE ) { CloseHandle( hInputFile ); } if( hOutputFile != INVALID_HANDLE_VALUE ) { CloseHandle( hOutputFile ); } if( ExistingFileBuffer != NULL ) { free( ExistingFileBuffer ); } return(0); }
|