/*++ 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 #include #include #include #include // #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 [-v] [-d]\n",argv[0]); fprintf(stderr,"\n" ); fprintf(stderr," Where is a bootfont.bin file to be translated\n"); fprintf(stderr," into the new format\n"); fprintf(stderr,"\n" ); fprintf(stderr," 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 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); }