Exemplo n.º 1
0
cop_font * parse_font( FILE * in_file, char const * in_name )
{

    /* The cop_font instance. */

    cop_font *          out_font          = NULL;

    /* Used to acquire string attributes. */

    uint8_t             length;
    char *              string_ptr          = NULL;

    /* Used to acquire numeric attributes. */

    uint16_t            designator;

    /* Used to acquire the CharacterDescriptionBlock. */

    uint8_t *           byte_ptr            = NULL;
    uint8_t             data_count;
    uint16_t            i;
    uint8_t             intrans_flag;
    uint8_t *           outtrans_data       = NULL;
    uint8_t             outtrans_data_size;
    uint8_t             outtrans_flag;
    outtrans_block *    outtrans_ptr        = NULL;
    translation *       translation_ptr     = NULL;
    uint8_t *           translation_start   = NULL;
    uint8_t             uint8_array[0x100];
    uint16_t            uint16_array[0x100];
    uint8_t             width_data_size;
    uint8_t             width_flag;
    uint32_t *          width_ptr;

    /* Used for count and other values. */

    uint8_t             count8;

    /* Ensure in_name contains a value. */

    length = strnlen_s( in_name, TYPE_MAX );
    if( (in_name == NULL) || (length == 0) ) {
        out_msg( "Defined name missing for desired font\n" );
        err_count++;
        g_suicide();
    }

    /* Initialize the out_font. */

    out_font = (cop_font *) mem_alloc( START_SIZE );

    out_font->next_font = NULL;
    out_font->allocated_size = START_SIZE;
    out_font->next_offset = sizeof( cop_font );

    /* Note: The various pointers must be entered, initially, as offsets
     * and then converted to pointers before returning because out_font
     * may be reallocated at any point and that invalidates actual pointers.
     */

    /* Incorporate the defined name. */

    length++;
    if( out_font->allocated_size < (out_font->next_offset + length) ) {
        out_font = resize_cop_font( out_font, length );
    }

    string_ptr = (char *) out_font + out_font->next_offset;
    strcpy_s( string_ptr, length, in_name );

    out_font->defined_name = (char *) out_font->next_offset;
    out_font->next_offset += length;


    /* Get the font_out_name1. */

    fread( &length, sizeof( length ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    if( length > 0 ) {

        if( out_font->allocated_size < (out_font->next_offset + length) ) {
            out_font = resize_cop_font( out_font, length );
        }

        string_ptr = (char *) out_font + out_font->next_offset;

        fread( string_ptr, length, 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            mem_free( out_font );
            out_font = NULL;
            return( out_font );
        }
        out_font->font_out_name1 = (char *) out_font->next_offset;
        out_font->next_offset += length;
        string_ptr[length] = '\0';
        ++out_font->next_offset;
    } else {
        out_font->font_out_name1 = NULL;
    }

    /* Get the font_out_name2. */

    fread( &length, sizeof( length ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    if( length > 0 ) {
        if( out_font->allocated_size < (out_font->next_offset + length) ) {
            out_font = resize_cop_font( out_font, length );
        }

        string_ptr = (char *) out_font + out_font->next_offset;

        fread( string_ptr, length, 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            mem_free( out_font );
            out_font = NULL;
            return( out_font );
        }

        out_font->font_out_name2 = (char *) out_font->next_offset;
        out_font->next_offset += length;
        string_ptr[length] = '\0';
        ++out_font->next_offset;
    } else {
        out_font->font_out_name2 = NULL;
    }

    /* Get the designator and ensure it is 0x1D00. */

    fread( &designator, sizeof( designator ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    if( designator != 0x1D00 ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the line_height. */

    fread( &out_font->line_height, sizeof( out_font->line_height), 1, \
        in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the line_space. */

    fread( &out_font->line_space, sizeof( out_font->line_space ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the scale_basis. */

    fread( &out_font->scale_basis, sizeof( out_font->scale_basis ), 1, \
        in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the scale_min. */

    fread( &out_font->scale_min, sizeof( out_font->scale_min ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the scale_max. */

    fread( &out_font->scale_max, sizeof( out_font->scale_max ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the char_width. */

    fread( &out_font->char_width, sizeof( out_font->char_width ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the CharacterDescriptionBlock. */

    /* Get the size_flag, which is not needed. */

    fread( &count8, sizeof( count8 ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the data_count and the flags. */

    fread( &width_flag, sizeof( width_flag ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    fread( &data_count, sizeof( data_count ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    fread( &outtrans_flag, sizeof( outtrans_flag ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    fread( &intrans_flag, sizeof( intrans_flag ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the IntransBlock, if present. */

    if( intrans_flag == 0 ) {
        out_font->intrans = NULL;
    } else {

        /* Get the designator and verify it contains 0x81. */

        fread( &count8, sizeof( count8 ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
           mem_free( out_font );
           out_font = NULL;
           return( out_font );
        }

        if( count8 != 0x81 ) {
           mem_free( out_font );
           out_font = NULL;
           return( out_font );
        }

        /* Get the count and verify that it contains 0x00. */

        fread( &count8, sizeof( count8 ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
           mem_free( out_font );
           out_font = NULL;
           return( out_font );
        }

        if( count8 != 0x00 ) {
            mem_free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* Get the data into the array. */

        if( out_font->allocated_size < (out_font->next_offset + \
                                        sizeof( out_font->intrans->table )) ) {
            out_font = resize_cop_font( out_font, \
                                        sizeof( out_font->intrans->table ) );
        }

        byte_ptr = (uint8_t *) out_font + out_font->next_offset;

        fread( byte_ptr, sizeof( out_font->intrans->table ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
           mem_free( out_font );
           out_font = NULL;
           return( out_font );
        }

        out_font->intrans = (intrans_block *) out_font->next_offset;
        out_font->next_offset += sizeof( out_font->intrans->table );
    }

    /* Get the OuttransBlock, if present. */

    if( outtrans_flag == 0 ) {
        out_font->outtrans = NULL;
    } else {

        /* Get the next byte, which indicates the OuttransBlock data size. */
        /* The name of the variable does not match the Wiki. */

        fread( &outtrans_data_size, sizeof( outtrans_data_size ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
           mem_free( out_font );
           out_font = NULL;
           return( out_font );
        }

        /* Read the count. */

        fread( &count8, sizeof( count8 ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            mem_free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* The file is positioned at the start of the data. */

        /* Note: each translation is added individually; however, taken
         * together, they constitute the field "translations" in the Wiki.
         */

        switch( outtrans_data_size) {
        case 0x81:

            /* The count should be 0x00. */

            if( count8 != 0x00 ) {
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Get the data into the local buffer. */

            fread( &uint8_array, sizeof( uint8_array ), 1, in_file );
            if( ferror( in_file ) || feof( in_file ) ) {
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Reserve space for the outtrans_block. */

            if( out_font->allocated_size < (out_font->next_offset + \
                                        sizeof( out_font->outtrans->table )) ) {
                out_font = resize_cop_font( out_font, \
                                        sizeof( out_font->outtrans->table ) );
            }

            out_font->outtrans = (outtrans_block *) out_font->next_offset;
            out_font->next_offset += sizeof( out_font->outtrans->table );

            outtrans_ptr = (outtrans_block *) ((char *) out_font + \
                (size_t) out_font->outtrans);

            /* Build the actual table, which requires actual pointers in
             * place of the offsets recorded in *out_font:
             *      outtrans_ptr is the pointer version of out_font->outtrans.
             *      for each iteration:
             *          translation_ptr is the pointer version of
             *              outtrans->ptr->table[i].
             *          byte_ptr is the pointer version of
             *              translation_ptr->ptr.data.
             */

            for( i = 0; i < 0x100; i++ ) {

                /* If the first byte matches the index, there is no translation. */

                if( uint8_array[i] == i) {
                    outtrans_ptr->table[i] = NULL;
                } else {

                    /* Reserve space for the translation. */

                    if( out_font->allocated_size < (out_font->next_offset + \
                                                        sizeof( translation )) ) {
                        out_font = resize_cop_font( out_font, \
                                                        sizeof( translation ) );
                        outtrans_ptr = (outtrans_block *) ((uint8_t *) out_font \
                                                + (size_t) out_font->outtrans);
                    }

                    outtrans_ptr->table[i] = (translation *) \
                                                            out_font->next_offset;
                    out_font->next_offset += sizeof( translation );

                    /* Get the translation for the current character. */

                    translation_ptr = (translation *) ((char *) out_font + \
                                                (size_t) outtrans_ptr->table[i] );

                    /* The translation always contains exactly one character. */

                    translation_ptr->count = 1;

                    if( out_font->allocated_size < (out_font->next_offset + \
                                                    translation_ptr->count ) ) {
                        out_font = resize_cop_font( out_font, \
                                                        translation_ptr->count  );
                        outtrans_ptr = (outtrans_block *) ((uint8_t *) \
                                        out_font + (size_t) out_font->outtrans);
                        translation_ptr = (translation *) ((uint8_t *) out_font \
                                            + (size_t) outtrans_ptr->table[i] );
                    }

                    translation_ptr->data = (uint8_t *) out_font->next_offset;
                    out_font->next_offset += translation_ptr->count;

                    byte_ptr = (uint8_t *) out_font + (size_t) \
                                                            translation_ptr->data;

                    /* The translation character is the value in the input array. */

                    *byte_ptr = uint8_array[i];
                }
            }
            break;

        case 0x82:

            /* The count should be equal to the data_count. */

            if( count8 != data_count ) {
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Get the outtrans array into the local array. */

            fread( &uint16_array, sizeof( uint16_array ), 1, in_file );
            if( ferror( in_file ) || feof( in_file ) ) {
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Allocate a buffer and read the translation characters into it. */

            outtrans_data = (uint8_t *) mem_alloc( data_count );

            fread( outtrans_data, sizeof( *outtrans_data ), data_count, \
                in_file );
            if( ferror( in_file ) || feof( in_file ) ) {
                mem_free( outtrans_data );
                outtrans_data = NULL;
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Initialize outtrans_ptr and the outtrans pointer in out_font. */

            if( out_font->allocated_size < (out_font->next_offset + \
                                        sizeof( out_font->outtrans->table )) ) {
                out_font = resize_cop_font( out_font, \
                                            sizeof( out_font->outtrans->table ) );
            }

            out_font->outtrans = (outtrans_block *) out_font->next_offset;
            out_font->next_offset += sizeof( out_font->outtrans->table );

            outtrans_ptr = (outtrans_block *) ((char *) out_font + \
                                                    (size_t) out_font->outtrans);

            /* Convert the data in uint16_array to our format, which requires
             * actual pointers in place of the offsets recorded in *out_font:
             *      outtrans_ptr is the pointer version of out_font->outtrans.
             *      for each iteration:
             *          translation_ptr is the pointer version of
             *              outtrans->ptr->table[i].
             *          byte_ptr is the pointer version of
             *              translation_ptr->ptr.data.
             */

            for( i = 0; i < 0x100; i++ ) {

                /* If the first byte matches the index, there is no translation. */

                if( uint16_array[i] == i) {
                    outtrans_ptr->table[i] = NULL;
                } else {

                    /* Reserve space for the translation. */

                    if( out_font->allocated_size < (out_font->next_offset + \
                                                    sizeof( translation )) ) {
                        out_font = resize_cop_font( out_font, \
                                                    sizeof( translation ) );
                        outtrans_ptr = (outtrans_block *) ((uint8_t *) out_font \
                                                + (size_t) out_font->outtrans);
                    }

                    outtrans_ptr->table[i] = (translation *) \
                                                            out_font->next_offset;
                    out_font->next_offset += sizeof( translation );

                    /* Get the translation for the current character. */

                    translation_ptr = (translation *) ((char *) out_font + \
                                                (size_t) outtrans_ptr->table[i] );

                    /* If the first byte at uint16_array[i] is 00, then the
                     * second byte is the one-byte translation. Otherwise, the
                     * second byte is an offset. For little-endian computers,
                     * at least!
                     */

                    /* Set the count correctly. */

                    if( (uint16_array[i] & 0xff00) == 0x00 ) {
                        translation_ptr->count = 1;
                    } else {
                        translation_start = outtrans_data + \
                                                    (uint16_array[i] & 0x00ff);
                        translation_ptr->count = *translation_start;
                    }

                    /* Allocate space and perform other common operations. */

                    if( out_font->allocated_size < (out_font->next_offset + \
                                                    translation_ptr->count ) ) {
                        out_font = resize_cop_font( out_font, \
                                                        translation_ptr->count );
                        outtrans_ptr = (outtrans_block *) ((uint8_t *) out_font \
                                                + (size_t) out_font->outtrans);
                        translation_ptr = (translation *) ((uint8_t *) out_font \
                                            + (size_t) outtrans_ptr->table[i] );
                    }

                    translation_ptr->data = (uint8_t *) out_font->next_offset;
                    out_font->next_offset += translation_ptr->count;

                    byte_ptr = (uint8_t *) out_font + (size_t) \
                                                        translation_ptr->data;

                    /* Put the data into the buffer. */

                    if( (uint16_array[i] & 0xff00) == 0x00 ) {
                        *byte_ptr = (uint16_array[i] & 0x00ff);
                    } else {
                        ++translation_start;
                        memcpy_s( byte_ptr, translation_ptr->count, \
                                    translation_start, translation_ptr->count );
                    }
                }
            }
            mem_free( outtrans_data );
            outtrans_data = NULL;
            break;

        default:
           mem_free( out_font );
           out_font = NULL;
           return( out_font );
        }
    }

    /* Get the WidthBlock, if present. */

    if( width_flag != 0 ) {
        out_font->width = NULL;
    } else {

        /* Reserve the space for width. */

        if( out_font->allocated_size < (out_font->next_offset + \
                                        sizeof( out_font->width->table )) ) {
            out_font = resize_cop_font( out_font, \
                                        sizeof( out_font->width->table ) );
        }

        width_ptr = (uint32_t *) ((uint8_t *) out_font + out_font->next_offset);

        out_font->width = (width_block *) out_font->next_offset;
        out_font->next_offset += sizeof( out_font->width->table );

        /* Get the designator, which indicates the WidthBlock data size. */
        /* The variable name does not match the field name in the Wiki. */

        fread( &width_data_size, sizeof( width_data_size ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            mem_free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* This byte's value is checked below. */

        fread( &count8, sizeof( count8 ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            mem_free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* The file is now positioned at the start of the data. */

        switch ( width_data_size ) {
        case 0x81:

            /* The WidthBlock has one-byte elements. */

            /* The count should be 0x00. */

            if( count8 != 0x00 ) {
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Get the width data array into an array of bytes.
             * It cannot be read in directly because the field is
             * an array of uint32_t entries.
             */

            fread( &uint8_array, sizeof( uint8_array ), 1, in_file );
            if( ferror( in_file ) || feof( in_file ) ) {
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Copy the data into the cop_font instance. */

            for( i = 0; i < 0x100; i++ ) {
                width_ptr[i] = uint8_array[i];
            }

            break;

        case 0x84:

            /* The WidthBlock has four-byte elements. */

            /* The count should be 0x01. */

            if( count8 != 0x01 ) {
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Get the width data array directly into the cop_font instance. */

            fread( width_ptr, sizeof( out_font->width->table ), 1, in_file );
            if( ferror( in_file ) || feof( in_file ) ) {
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }
            break;

        default:
            mem_free( out_font );
            out_font = NULL;
            return( out_font );
        }
    }

    /* Convert non-NULL offsets to pointers. */

    if( out_font->defined_name != NULL ) {
        string_ptr = (char *) out_font + (size_t) out_font->defined_name;
        out_font->defined_name = string_ptr;
    }

    if( out_font->font_out_name1 != NULL ) {
        string_ptr = (char *) out_font + (size_t) out_font->font_out_name1;
        out_font->font_out_name1 = string_ptr;
    }

    if( out_font->font_out_name2 != NULL ) {
        string_ptr = (char *) out_font + (size_t) out_font->font_out_name2;
        out_font->font_out_name2 = string_ptr;
    }

    if( out_font->intrans != NULL ) {
        byte_ptr = (uint8_t *) out_font + (size_t) out_font->intrans;
        out_font->intrans = (intrans_block *) byte_ptr;
    }

    if( out_font->outtrans != NULL ) {
        byte_ptr = (uint8_t *) out_font + (size_t) out_font->outtrans;
        out_font->outtrans = (outtrans_block *) byte_ptr;

        for( i = 0; i < sizeof( outtrans_block ) / sizeof( translation * ); \
                                                                        i++ ) {
            if( out_font->outtrans->table[i] != NULL ) {
                byte_ptr = (uint8_t *) out_font + \
                                            (size_t) out_font->outtrans->table[i];
                out_font->outtrans->table[i] = (translation *) byte_ptr;
                if( out_font->outtrans->table[i]->data != NULL ) {
                    byte_ptr = (uint8_t *) out_font + (size_t) \
                                            out_font->outtrans->table[i]->data;
                    out_font->outtrans->table[i]->data = byte_ptr;
                }
            }
        }
    }

    if( out_font->width != NULL ) {
        byte_ptr = (uint8_t *) out_font + (size_t) out_font->width;
        out_font->width = (width_block *) byte_ptr;
    }

    return( out_font );
}
Exemplo n.º 2
0
cop_font * parse_font( FILE * in_file )
{

    /* The cop_font instance. */
  
    cop_font *          out_font          = NULL;

    /* Used to acquire string attributes. */

    uint8_t             length;
    char *              string_ptr          = NULL;

    /* Used to acquire numeric attributes. */

    uint16_t            designator;
    uint16_t            numeric_16;

    /* Used to acquire the CharacterDescriptionBlock. */

    uint8_t *           byte_ptr            = NULL;
    uint8_t             data_count;
    uint16_t            i;
    uint8_t             intrans_flag;
    uint8_t *           outtrans_data       = NULL;
    uint8_t             outtrans_data_size;
    uint8_t             outtrans_flag;
    outtrans_block *    outtrans_ptr        = NULL;
    translation *       translation_ptr     = NULL;
    uint8_t *           translation_start   = NULL;
    uint8_t             uint8_array[0x100];
    uint16_t            uint16_array[0x100];    
    uint8_t             width_data_size;
    uint8_t             width_flag;
    uint32_t *          width_ptr;

    /* Used for count and other values. */

    uint8_t             count8;

    size_t              size;

    /* Initialize the out_font. */
        
    out_font = malloc( START_SIZE );
    if( out_font == NULL )
        return( out_font );

    out_font->allocated_size = START_SIZE;
    out_font->next_offset = sizeof( cop_font );

    /* Note: The various pointers must be entered, initially, as offsets
     * and then converted to pointers before returning because out_font
     * may be reallocated at any point and that invalidates actual pointers.
     */

    /* Get the font_out_name1. */

    fread( &length, sizeof( length ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        free( out_font );
        out_font = NULL;
        return( out_font );
    }

    if( length > 0 ) {

        if( out_font->allocated_size < (out_font->next_offset + length) ) {
            out_font = resize_cop_font( out_font, length );
            if( out_font == NULL ) {
                return( out_font );
            }
        }

        string_ptr = OUT_FONT_MAP_OFF();

        fread( string_ptr, length, 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }
        out_font->font_out_name1 = OUT_FONT_GET_OFF();
        string_ptr[length] = '\0';
        OUT_FONT_ADD_OFF( length + 1 );
    } else {
        out_font->font_out_name1 = NULL;
    }

    /* Get the font_out_name2. */

    fread( &length, sizeof( length ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        free( out_font );
        out_font = NULL;
        return( out_font );
    }

    if( length > 0 ) {
        if( out_font->allocated_size < (out_font->next_offset + length) ) {
            out_font = resize_cop_font( out_font, length );
            if( out_font == NULL ) {
                return( out_font );
            }
        }

        string_ptr = OUT_FONT_MAP_OFF();

        fread( string_ptr, length, 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }
    
        out_font->font_out_name2 = OUT_FONT_GET_OFF();
        string_ptr[length] = '\0';
        OUT_FONT_ADD_OFF( length + 1 );
    } else {
        out_font->font_out_name2 = NULL;
    }

    /* Get the numeric attributes. */

    /* Get the designator. */

    fread( &designator, sizeof( designator ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        free( out_font );
        out_font = NULL;
        return( out_font );
    }
    
    switch( designator ) {
    case 0x1700:

        /* Get the 16-bit line_height. */

        fread( &numeric_16, sizeof(numeric_16), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        out_font->line_height = numeric_16;

        /* Get the 16-bit line_space. */

        fread( &numeric_16, sizeof( numeric_16 ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        out_font->line_space = numeric_16;

        /* Get the 32-bit scale_basis. */

        fread( &out_font->scale_basis, sizeof( out_font->scale_basis ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* Get the 32-bit scale_min. */

        fread( &out_font->scale_min, sizeof( out_font->scale_min ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* Get the 32-bit scale_max. */

        fread( &out_font->scale_max, sizeof( out_font->scale_max ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* Get the 16-bit char_width. */

        fread( &numeric_16, sizeof( numeric_16 ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        out_font->char_width = numeric_16;

        break;
    case 0x1D00:

        /* Get the 32-bit line_height. */

        fread( &out_font->line_height, sizeof( out_font->line_height), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* Get the 32-bit line_space. */

        fread( &out_font->line_space, sizeof( out_font->line_space ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* Get the 32-bit scale_basis. */

        fread( &out_font->scale_basis, sizeof( out_font->scale_basis ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* Get the 32-bit scale_min. */

        fread( &out_font->scale_min, sizeof( out_font->scale_min ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* Get the 32-bit scale_max. */

        fread( &out_font->scale_max, sizeof( out_font->scale_max ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* Get the 32-bit char_width. */

        fread( &out_font->char_width, sizeof( out_font->char_width ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        break;
    default:
        printf_s( "Bad numeric parameters designator: %i\n", designator );
        free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the CharacterDescriptionBlock. */

    /* Get the size_flag, which is not needed. */

    fread( &count8, sizeof( count8 ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        free( out_font );
        out_font = NULL;
        return( out_font );
    }
  
    /* Get the data_count and the flags. */

    fread( &width_flag, sizeof( width_flag ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        free( out_font );
        out_font = NULL;
        return( out_font );
    }
  
    fread( &data_count, sizeof( data_count ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        free( out_font );
        out_font = NULL;
        return( out_font );
    }

    fread( &outtrans_flag, sizeof( outtrans_flag ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        free( out_font );
        out_font = NULL;
        return( out_font );
    }

    fread( &intrans_flag, sizeof( intrans_flag ), 1, in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the IntransBlock, if present. */

    if( intrans_flag == 0 ) {
        out_font->intrans = NULL;
    } else {

        /* Get the designator and verify it contains 0x81. */

        fread( &count8, sizeof( count8 ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
           free( out_font );
           out_font = NULL;
           return( out_font );
        }

        if( count8 != 0x81 ) {
           printf_s( "Incorrect IntransBlock designator: %i\n", count8 );
           free( out_font );
           out_font = NULL;
           return( out_font );
        }

        /* Get the count and verify that it contains 0x00. */
      
        fread( &count8, sizeof( count8 ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
           free( out_font );
           out_font = NULL;
           return( out_font );
        }

        if( count8 != 0x00 ) {
            printf_s( "Incorrect IntransBlock count: %i\n", count8 );
            free( out_font );
            out_font = NULL;
            return( out_font );
        }
  
        /* Get the data into the array. */

        if( out_font->allocated_size < (out_font->next_offset + sizeof( out_font->intrans->table )) ) {
            out_font = resize_cop_font( out_font, sizeof( out_font->intrans->table ) );
            if( out_font == NULL ) {
                return( out_font );
            }
        }

        byte_ptr = OUT_FONT_MAP_OFF();
        
        fread( byte_ptr, sizeof( out_font->intrans->table ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
           free( out_font );
           out_font = NULL;
           return( out_font );
        }

        out_font->intrans = OUT_FONT_GET_OFF();
        OUT_FONT_ADD_OFF( sizeof( out_font->intrans->table ) );
    }  

    /* Get the OuttransBlock, if present. */

    if( outtrans_flag == 0 ) {
        out_font->outtrans = NULL;
    } else {

        /* Get the next byte, which indicates the OuttransBlock data size. */
        /* The name of the variable does not match the Wiki. */

        fread( &outtrans_data_size, sizeof( outtrans_data_size ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
           free( out_font );
           out_font = NULL;
           return( out_font );
        }

        /* Read the count. */

        fread( &count8, sizeof( count8 ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* The file is positioned at the start of the data. */

        /* Note: each translation is added individually; however, taken 
         * together, they constitute the field "translations" in the Wiki.
         */

        switch( outtrans_data_size) {
        case 0x81:

            /* The count should be 0x00. */

            if( count8 != 0x00 ) {
                printf_s( "Incorrect byte-width OuttransBlock count: %i\n", count8 );
                free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Get the data into the local buffer. */

            fread( &uint8_array, sizeof( uint8_array ), 1, in_file );
            if( ferror( in_file ) || feof( in_file ) ) {
                free( out_font );
                out_font = NULL;
                return( out_font );
            }
            
            /* Reserve space for the outtrans_block struct instance. */

            if( out_font->allocated_size < (out_font->next_offset + sizeof( out_font->outtrans->table )) ) {
                out_font = resize_cop_font( out_font, sizeof( out_font->outtrans->table ) );
                if( out_font == NULL ) {
                    return( out_font );
                }
            }

            out_font->outtrans = OUT_FONT_GET_OFF();
            OUT_FONT_ADD_OFF( sizeof( out_font->outtrans->table ) );

            outtrans_ptr = OUT_FONT_MAP( out_font->outtrans );

            /* Build the actual table, which requires actual pointers in
             * place of the offsets recorded in *out_font:
             *   outtrans_ptr is the pointer version of out_font->outtrans.
             *   for each iteration,
             *     translation_ptr is the pointer version of
             *       outtrans->ptr->table[i].
             *     byte_ptr is the pointer version of translation->ptr.data.
             */

            for( i = 0; i < 0x100; i++ ) {

                /* If the first byte matches the index, there is no translation. */

                if( uint8_array[i] == i) {
                    outtrans_ptr->table[i] = NULL;
                } else {

                    /* Reserve space for the translation. */

                    if( out_font->allocated_size < (out_font->next_offset + sizeof( translation )) ) {
                        out_font = resize_cop_font( out_font, sizeof( translation ) );
                        if( out_font == NULL )
                            return( out_font );
                        outtrans_ptr = OUT_FONT_MAP( out_font->outtrans );
                    }

                    outtrans_ptr->table[i] = OUT_FONT_GET_OFF();
                    OUT_FONT_ADD_OFF( sizeof( translation ) );

                    /* Get the translation for the current character. */

                    translation_ptr = OUT_FONT_MAP( outtrans_ptr->table[i] );

                    /* The translation always contains exactly one character. */
                    
                    size = translation_ptr->count = 1;

                    if( out_font->allocated_size < (out_font->next_offset + size ) ) {
                        out_font = resize_cop_font( out_font, size );
                        if( out_font == NULL )
                            return( out_font );
                        outtrans_ptr = OUT_FONT_MAP( out_font->outtrans );
                        translation_ptr = OUT_FONT_MAP( outtrans_ptr->table[i] );
                    }

                    translation_ptr->data = OUT_FONT_GET_OFF();
                    OUT_FONT_ADD_OFF( size );

                    byte_ptr = OUT_FONT_MAP( translation_ptr->data );

                    /* The translation character is the value in the input array. */
                    
                    *byte_ptr = uint8_array[i];
                }
            }
            break;

        case 0x82:

            /* The count should be equal to the data_count. */
        
            if( count8 != data_count ) {
                printf_s( "Incorrect OuttransBlock data_count: %i instead of %i\n", data_count, count8 );
                free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Get the outtrans array into the local array. */

            fread( &uint16_array, sizeof( uint16_array ), 1, in_file );
            if( ferror( in_file ) || feof( in_file ) ) {
                free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Allocate a buffer and read the translation characters into it. */

            outtrans_data = malloc( data_count );

            fread( outtrans_data, sizeof( *outtrans_data ), data_count, in_file );
            if( ferror( in_file ) || feof( in_file ) ) {
                free( outtrans_data );
                outtrans_data = NULL;
                free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Initialize outtrans_ptr and the outtrans pointer in out_font. */

            if( out_font->allocated_size < (out_font->next_offset + sizeof( out_font->outtrans->table )) ) {
                out_font = resize_cop_font( out_font, sizeof( out_font->outtrans->table ) );
                if( out_font == NULL ) {
                    free( outtrans_data );
                    outtrans_data = NULL;
                    return( out_font );
                }
            }

            out_font->outtrans = OUT_FONT_GET_OFF();
            OUT_FONT_ADD_OFF( sizeof( out_font->outtrans->table ) );

            outtrans_ptr = OUT_FONT_MAP( out_font->outtrans );

            /* Convert the data in uint16_array to our format, which requires
             * actual pointers in place of the offsets recorded in *out_font:
             *   outtrans_ptr is the pointer version of out_font->outtrans.
             *   for each iteration,
             *     translation_ptr is the pointer version of
             *       outtrans->ptr->table[i].
             *     byte_ptr is the pointer version of translation->ptr.data.
             */

            for( i = 0; i < 0x100; i++ ) {

                /* If the first byte matches the index, there is no translation. */

                if( uint16_array[i] == i) {
                    outtrans_ptr->table[i] = NULL;
                } else {

                    /* Reserve space for the translation. */

                    if( out_font->allocated_size < (out_font->next_offset + sizeof( translation )) ) {
                        out_font = resize_cop_font( out_font, sizeof( translation ) );
                        if( out_font == NULL ) {
                            free( outtrans_data );
                            outtrans_data = NULL;
                            return( out_font );
                        }
                        outtrans_ptr = OUT_FONT_MAP( out_font->outtrans );
                    }

                    outtrans_ptr->table[i] = OUT_FONT_GET_OFF();
                    OUT_FONT_ADD_OFF( sizeof( translation ) );

                    /* Get the translation for the current character. */

                    translation_ptr = OUT_FONT_MAP( outtrans_ptr->table[i] );

                    /* If the first byte at uint16_array[i] is 00, then the
                     * second byte is the one-byte translation. Otherwise, the
                     * second byte is an offset. For little-endian computers,
                     * at least!
                     */

                    /* Set the count correctly. */

                    if( (uint16_array[i] & 0xff00) == 0x00 ) {
                        size = 1;
                    } else {
                        translation_start = outtrans_data + (uint16_array[i] & 0x00ff);
                        size = *translation_start;
                    }
                    translation_ptr->count = size;

                    /* Allocate space and perform other common operations. */

                    if( out_font->allocated_size < (out_font->next_offset + size ) ) {
                        out_font = resize_cop_font( out_font, size  );
                        if( out_font == NULL ) {
                            free( outtrans_data );
                            outtrans_data = NULL;
                            return( out_font );
                        }
                        outtrans_ptr = OUT_FONT_MAP( out_font->outtrans );
                        translation_ptr = OUT_FONT_MAP( outtrans_ptr->table[i] );
                    }

                    translation_ptr->data = OUT_FONT_GET_OFF();
                    OUT_FONT_ADD_OFF( size );

                    byte_ptr = OUT_FONT_MAP( translation_ptr->data );

                    /* Put the data into the buffer. */

                    if( (uint16_array[i] & 0xff00) == 0x00 ) {
                        *byte_ptr = (uint16_array[i] & 0x00ff);
                    } else {
                        ++translation_start;
                        memcpy_s( byte_ptr, size, translation_start, size );
                    }
                }
            }
            free( outtrans_data );
            outtrans_data = NULL;
            break;

        default:
           printf_s( "Incorrect OuttransBlock designator: %i\n", count8 );
           free( out_font );
           out_font = NULL;
           return( out_font );
        }
    }  

    /* Get the WidthBlock, if present. */

    if( width_flag != 0 ) {
        out_font->width = NULL;
    } else {

        /* Reserve the space for width. */

        if( out_font->allocated_size < (out_font->next_offset + sizeof( out_font->width->table )) ) {
            out_font = resize_cop_font( out_font, sizeof( out_font->width->table ) );
            if( out_font == NULL ) {
                return( out_font );
            }
        }

        width_ptr = OUT_FONT_MAP_OFF();
        
        out_font->width = OUT_FONT_GET_OFF();
        OUT_FONT_ADD_OFF( sizeof( out_font->width->table ) );

        /* Get the designator, which indicates the WidthBlock data size. */
        /* The variable name does not match the field name in the Wiki. */

        fread( &width_data_size, sizeof( width_data_size ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* Get the count, which is checked below. */

        fread( &count8, sizeof( count8 ), 1, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* The file is now positioned at the start of the data. */

        switch ( width_data_size ) {
        case 0x81:

            /* The WidthBlock has one-byte elements. */

            /* The count should be 0x00. */
            
            if( count8 != 0x00 ) {
                printf_s( "Incorrect WidthBlock count: %i\n", count8 );
                free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Get the width data array into an array of bytes. */

            fread( &uint8_array, sizeof( uint8_array ), 1, in_file );
            if( ferror( in_file ) || feof( in_file ) ) {
                free( out_font );
               out_font = NULL;
               return( out_font );
            }

            /* Copy the data into the cop_font instance. */

            for( i = 0; i < 0x100; i++ ) {
                width_ptr[i] = uint8_array[i];
            }

            break;

        case 0x82:

            /* The WidthBlock has two-byte elements. */

            /* The count should be 0x00. */
            
            if( count8 != 0x00 ) {
                printf_s( "Incorrect WidthBlock count: %i\n", count8 );
                free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Get the width data array into an array of two-byte entries. */

            fread( &uint16_array, sizeof( uint16_array ), 1, in_file );
            if( ferror( in_file ) || feof( in_file ) ) {
                free( out_font );
               out_font = NULL;
               return( out_font );
            }

            /* Copy the data into the cop_font instance. */

            for( i = 0; i < 0x100; i++ ) {
                width_ptr[i] = uint16_array[i];
            }

            break;

        case 0x84:

            /* The WidthBlock has four-byte elements. */

            /* The count should be 0x01. */
            
            if( count8 != 0x01 ) {
                printf_s( "Incorrect WidthBlock count: %i\n", count8 );
                free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Get the width data array directly into the cop_font instance. */

            fread( width_ptr, sizeof( out_font->width->table ), 1, in_file );
            if( ferror( in_file ) || feof( in_file ) ) {
                free( out_font );
               out_font = NULL;
               return( out_font );
            }
            break;

        default:
            printf_s( "Bad size indicator for Width Block: %i\n", count8 );
            free( out_font );
            out_font = NULL;
            return( out_font );
        }
    }

    /* Convert non-NULL offsets to pointers. */

    if( out_font->font_out_name1 != NULL ) {
        OUT_FONT_REMAP( font_out_name1 );
    }

    if( out_font->font_out_name2 != NULL ) {
        OUT_FONT_REMAP( font_out_name2 );
    }

    if( out_font->intrans != NULL ) {
        OUT_FONT_REMAP( intrans );
    }
    
    if( out_font->outtrans != NULL ) {
        OUT_FONT_REMAP( outtrans );
        for( i = 0; i < sizeof( outtrans_block ) / sizeof( translation * ); i++ ) {
            if( out_font->outtrans->table[i] != NULL ) {
                OUT_FONT_REMAP( outtrans->table[i] );
                if( out_font->outtrans->table[i]->data != NULL ) {
                    OUT_FONT_REMAP( outtrans->table[i]->data );
                }
            }
        }
    }

    if( out_font->width != NULL ) {
        OUT_FONT_REMAP( width );
    }
    
    return( out_font );
}
Exemplo n.º 3
0
cop_font * parse_font( FILE * in_file, char const * in_name )
{

    /* The cop_font instance. */

    cop_font *          out_font          = NULL;

    /* Used to acquire string attributes. */

    uint8_t             length;
    char *              string_ptr          = NULL;

    /* Used to acquire numeric attributes. */

    uint16_t            designator;

    /* Used to acquire the CharacterDescriptionBlock. */

    uint8_t *           byte_ptr            = NULL;
    uint8_t             data_count;
    uint16_t            i;
    uint8_t             intrans_flag;
    uint8_t *           outtrans_data       = NULL;
    uint8_t             outtrans_data_size;
    uint8_t             outtrans_flag;
    outtrans_block *    outtrans_ptr        = NULL;
    translation *       translation_ptr     = NULL;
    uint8_t *           translation_start   = NULL;
    uint8_t             uint8_array[0x100];
    uint16_t            uint16_array[0x100];
    uint8_t             width_data_size;
    uint8_t             width_flag;
    uint32_t *          width_ptr;

    size_t              size;

    /* Used for count and other values. */

    uint8_t             count8;

    /* Ensure in_name contains a value. */

    if( in_name == NULL || (length = strlen( in_name )) == 0 )
        return( out_font );

    /* Initialize the out_font. */

    out_font = mem_alloc( START_SIZE );

    out_font->next_font = NULL;
    out_font->allocated_size = START_SIZE;
    out_font->next_offset = sizeof( cop_font );

    /* Note: The various pointers must be entered, initially, as offsets
     * and then converted to pointers before returning because out_font
     * may be reallocated at any point and that invalidates actual pointers.
     */

    /* Incorporate the defined name. */

    length++;
    if( OUT_FONT_EXPAND_CHK( length ) ) {
        out_font = resize_cop_font( out_font, length );
    }
    out_font->defined_name = OUT_FONT_CUR_OFF();

    string_ptr = OUT_FONT_CUR_PTR();
    strcpy( string_ptr, in_name );
    OUT_FONT_ADD_OFF( length );

    /* Get the font_out_name1. */

    length = fread_u8( in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    if( length > 0 ) {
        if( OUT_FONT_EXPAND_CHK( length + 1 ) ) {
            out_font = resize_cop_font( out_font, length + 1 );
        }
        out_font->font_out_name1 = OUT_FONT_CUR_OFF();

        string_ptr = OUT_FONT_CUR_PTR();
        fread_buff( string_ptr, length, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            mem_free( out_font );
            out_font = NULL;
            return( out_font );
        }
        string_ptr[length] = '\0';
        OUT_FONT_ADD_OFF( length + 1 );
    } else {
        out_font->font_out_name1 = NULL;
    }

    /* Get the font_out_name2. */

    length = fread_u8( in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    if( length > 0 ) {
        if( OUT_FONT_EXPAND_CHK( length + 1 ) ) {
            out_font = resize_cop_font( out_font, length + 1 );
        }
        out_font->font_out_name2 = OUT_FONT_CUR_OFF();

        string_ptr = OUT_FONT_CUR_PTR();
        fread_buff( string_ptr, length, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            mem_free( out_font );
            out_font = NULL;
            return( out_font );
        }
        string_ptr[length] = '\0';
        OUT_FONT_ADD_OFF( length + 1 );
    } else {
        out_font->font_out_name2 = NULL;
    }

    /* Get the designator and ensure it is 0x1D00. */

    designator = fread_u16( in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    if( designator != 0x1D00 ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the line_height. */

    out_font->line_height = fread_u32( in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the line_space. */

    out_font->line_space = fread_u32( in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the scale_basis. */

    out_font->scale_basis = fread_u32( in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the scale_min. */

    out_font->scale_min = fread_u32( in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the scale_max. */

    out_font->scale_max = fread_u32( in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the char_width. */

    out_font->char_width = fread_u32( in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the CharacterDescriptionBlock. */

    /* Get the size_flag, which is not needed. */

    count8 = fread_u8( in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the data_count and the flags. */

    width_flag = fread_u8( in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    data_count = fread_u8( in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    outtrans_flag = fread_u8( in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    intrans_flag = fread_u8( in_file );
    if( ferror( in_file ) || feof( in_file ) ) {
        mem_free( out_font );
        out_font = NULL;
        return( out_font );
    }

    /* Get the IntransBlock, if present. */

    if( intrans_flag == 0 ) {
        out_font->intrans = NULL;
    } else {

        /* Get the designator and verify it contains 0x81. */

        count8 = fread_u8( in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
           mem_free( out_font );
           out_font = NULL;
           return( out_font );
        }

        if( count8 != 0x81 ) {
           mem_free( out_font );
           out_font = NULL;
           return( out_font );
        }

        /* Get the count and verify that it contains 0x00. */

        count8 = fread_u8( in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
           mem_free( out_font );
           out_font = NULL;
           return( out_font );
        }

        if( count8 != 0x00 ) {
            mem_free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* Get the data into the array. */

        if( OUT_FONT_EXPAND_CHK( sizeof( out_font->intrans->table ) ) ) {
            out_font = resize_cop_font( out_font, sizeof( out_font->intrans->table ) );
        }
        out_font->intrans = OUT_FONT_CUR_OFF();

        byte_ptr = OUT_FONT_CUR_PTR();
        fread_buff( byte_ptr, 0x100, in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
           mem_free( out_font );
           out_font = NULL;
           return( out_font );
        }
        OUT_FONT_ADD_OFF( sizeof( out_font->intrans->table ) );
    }

    /* Get the OuttransBlock, if present. */

    if( outtrans_flag == 0 ) {
        out_font->outtrans = NULL;
    } else {

        /* Get the next byte, which indicates the OuttransBlock data size. */
        /* The name of the variable does not match the Wiki. */

        outtrans_data_size = fread_u8( in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
           mem_free( out_font );
           out_font = NULL;
           return( out_font );
        }

        /* Read the count. */

        count8 = fread_u8( in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            mem_free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* The file is positioned at the start of the data. */

        /* Note: each translation is added individually; however, taken
         * together, they constitute the field "translations" in the Wiki.
         */

        switch( outtrans_data_size) {
        case 0x81:

            /* The count should be 0x00. */

            if( count8 != 0x00 ) {
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Get the data into the local buffer. */

            fread_buff( uint8_array, 0x100, in_file );
            if( ferror( in_file ) || feof( in_file ) ) {
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Reserve space for the outtrans_block. */

            if( OUT_FONT_EXPAND_CHK( sizeof( out_font->outtrans->table ) ) ) {
                out_font = resize_cop_font( out_font, sizeof( out_font->outtrans->table ) );
            }
            out_font->outtrans = OUT_FONT_CUR_OFF();

            outtrans_ptr = OUT_FONT_CUR_PTR();
            OUT_FONT_ADD_OFF( sizeof( out_font->outtrans->table ) );

            /* Build the actual table, which requires actual pointers in
             * place of the offsets recorded in *out_font:
             *      outtrans_ptr is the pointer version of out_font->outtrans.
             *      for each iteration:
             *          translation_ptr is the pointer version of
             *              outtrans->ptr->table[i].
             *          byte_ptr is the pointer version of
             *              translation_ptr->ptr.data.
             */

            for( i = 0; i < 0x100; i++ ) {

                /* If the first byte matches the index, there is no translation. */

                if( uint8_array[i] == i) {
                    outtrans_ptr->table[i] = NULL;
                } else {

                    /* Reserve space for the translation. */

                    if( OUT_FONT_EXPAND_CHK( sizeof( translation ) ) ) {
                        out_font = resize_cop_font( out_font, sizeof( translation ) );
                        outtrans_ptr = OUT_FONT_MAP_OFF( out_font->outtrans );
                    }
                    outtrans_ptr->table[i] = OUT_FONT_CUR_OFF();

                    /* Get the translation for the current character. */

                    translation_ptr = OUT_FONT_CUR_PTR();
                    OUT_FONT_ADD_OFF( sizeof( translation ) );

                    /* The translation always contains exactly one character. */

                    size = 1;

                    if( OUT_FONT_EXPAND_CHK( size ) ) {
                        out_font = resize_cop_font( out_font, size );
                        outtrans_ptr = OUT_FONT_MAP_OFF( out_font->outtrans );
                        translation_ptr = OUT_FONT_MAP_OFF( outtrans_ptr->table[i] );
                    }
                    translation_ptr->count = size;
                    translation_ptr->data = OUT_FONT_CUR_OFF();

                    byte_ptr = OUT_FONT_CUR_PTR();
                    OUT_FONT_ADD_OFF( size );

                    /* The translation character is the value in the input array. */

                    *byte_ptr = uint8_array[i];
                }
            }
            break;

        case 0x82:

            /* The count should be equal to the data_count. */

            if( count8 != data_count ) {
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Get the outtrans array into the local array. */

            for( i = 0; i < 0x100; i++ ) {
                uint16_array[i] = fread_u16( in_file );
                if( ferror( in_file ) || feof( in_file ) ) {
                    mem_free( out_font );
                    out_font = NULL;
                    return( out_font );
                }
            }

            /* Allocate a buffer and read the translation characters into it. */

            outtrans_data = mem_alloc( data_count );

            fread_buff( outtrans_data, data_count, in_file );
            if( ferror( in_file ) || feof( in_file ) ) {
                mem_free( outtrans_data );
                outtrans_data = NULL;
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Initialize outtrans_ptr and the outtrans pointer in out_font. */

            if( OUT_FONT_EXPAND_CHK( sizeof( out_font->outtrans->table ) ) ) {
                out_font = resize_cop_font( out_font, sizeof( out_font->outtrans->table ) );
            }
            out_font->outtrans = OUT_FONT_CUR_OFF();

            outtrans_ptr = OUT_FONT_CUR_PTR();
            OUT_FONT_ADD_OFF( sizeof( out_font->outtrans->table ) );

            translation_start = NULL;

            /* Convert the data in uint16_array to our format, which requires
             * actual pointers in place of the offsets recorded in *out_font:
             *      outtrans_ptr is the pointer version of out_font->outtrans.
             *      for each iteration:
             *          translation_ptr is the pointer version of
             *              outtrans->ptr->table[i].
             *          byte_ptr is the pointer version of
             *              translation_ptr->ptr.data.
             */

            for( i = 0; i < 0x100; i++ ) {

                /* If the first byte matches the index, there is no translation. */

                if( uint16_array[i] == i) {
                    outtrans_ptr->table[i] = NULL;
                } else {

                    /* Reserve space for the translation. */

                    if( OUT_FONT_EXPAND_CHK( sizeof( translation ) ) ) {
                        out_font = resize_cop_font( out_font, sizeof( translation ) );
                        outtrans_ptr = OUT_FONT_MAP_OFF( out_font->outtrans );
                    }
                    outtrans_ptr->table[i] = OUT_FONT_CUR_OFF();

                    /* Get the translation for the current character. */

                    translation_ptr = OUT_FONT_CUR_PTR();
                    OUT_FONT_ADD_OFF( sizeof( translation ) );

                    /* If the first byte at uint16_array[i] is 00, then the
                     * second byte is the one-byte translation. Otherwise, the
                     * second byte is an offset. For little-endian computers,
                     * at least!
                     */

                    /* Set the count correctly. */

                    if( (uint16_array[i] & 0xff00) == 0 ) {
                        size = 1;
                    } else {
                        translation_start = outtrans_data + (uint16_array[i] & 0x00ff);
                        size = *translation_start++;
                    }

                    /* Allocate space and perform other common operations. */

                    if( OUT_FONT_EXPAND_CHK( size ) ) {
                        out_font = resize_cop_font( out_font, size );
                        outtrans_ptr = OUT_FONT_MAP_OFF( out_font->outtrans );
                        translation_ptr = OUT_FONT_MAP_OFF( outtrans_ptr->table[i] );
                    }
                    translation_ptr->count = size;
                    translation_ptr->data = OUT_FONT_CUR_OFF();

                    byte_ptr = OUT_FONT_CUR_PTR();
                    OUT_FONT_ADD_OFF( size );

                    /* Put the data into the buffer. */

                    if( (uint16_array[i] & 0xff00) == 0x00 ) {
                        *byte_ptr = (uint16_array[i] & 0x00ff);
                    } else {
                        memcpy( byte_ptr, translation_start, size );
                    }
                }
            }
            mem_free( outtrans_data );
            outtrans_data = NULL;
            break;

        default:
           mem_free( out_font );
           out_font = NULL;
           return( out_font );
        }
    }

    /* Get the WidthBlock, if present. */

    if( width_flag != 0 ) {
        out_font->width = NULL;
    } else {

        /* Reserve the space for width. */

        if( OUT_FONT_EXPAND_CHK( sizeof( out_font->width->table ) ) ) {
            out_font = resize_cop_font( out_font, sizeof( out_font->width->table ) );
        }
        out_font->width = OUT_FONT_CUR_OFF();

        width_ptr = OUT_FONT_CUR_PTR();
        OUT_FONT_ADD_OFF( sizeof( out_font->width->table ) );

        /* Get the designator, which indicates the WidthBlock data size. */
        /* The variable name does not match the field name in the Wiki. */

        width_data_size = fread_u8( in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            mem_free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* This byte's value is checked below. */

        count8 = fread_u8( in_file );
        if( ferror( in_file ) || feof( in_file ) ) {
            mem_free( out_font );
            out_font = NULL;
            return( out_font );
        }

        /* The file is now positioned at the start of the data. */

        switch ( width_data_size ) {
        case 0x81:

            /* The WidthBlock has one-byte elements. */

            /* The count should be 0x00. */

            if( count8 != 0x00 ) {
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Get the width data array into an array of bytes.
             * It cannot be read in directly because the field is
             * an array of uint32_t entries.
             */

            fread_buff( uint8_array, 0x100, in_file );
            if( ferror( in_file ) || feof( in_file ) ) {
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Copy the data into the cop_font instance. */

            for( i = 0; i < 0x100; i++ ) {
                width_ptr[i] = uint8_array[i];
            }

            break;

        case 0x84:

            /* The WidthBlock has four-byte elements. */

            /* The count should be 0x01. */

            if( count8 != 0x01 ) {
                mem_free( out_font );
                out_font = NULL;
                return( out_font );
            }

            /* Get the width data array directly into the cop_font instance. */

            for( i = 0; i < 0x100; i++ ) {
                width_ptr[i] = fread_u32( in_file );
                if( ferror( in_file ) || feof( in_file ) ) {
                    mem_free( out_font );
                    out_font = NULL;
                    return( out_font );
                }
            }
            break;

        default:
            mem_free( out_font );
            out_font = NULL;
            return( out_font );
        }
    }

    /* Convert non-NULL offsets to pointers. */

    if( out_font->defined_name != NULL ) {
        OUT_FONT_REMAP_MBR( defined_name );
    }

    if( out_font->font_out_name1 != NULL ) {
        OUT_FONT_REMAP_MBR( font_out_name1 );
    }

    if( out_font->font_out_name2 != NULL ) {
        OUT_FONT_REMAP_MBR( font_out_name2 );
    }

    if( out_font->intrans != NULL ) {
        OUT_FONT_REMAP_MBR( intrans );
    }

    if( out_font->outtrans != NULL ) {
        OUT_FONT_REMAP_MBR( outtrans );
        for( i = 0; i < sizeof( outtrans_block ) / sizeof( translation * ); i++ ) {
            if( out_font->outtrans->table[i] != NULL ) {
                OUT_FONT_REMAP_MBR( outtrans->table[i] );
                if( out_font->outtrans->table[i]->data != NULL ) {
                    OUT_FONT_REMAP_MBR( outtrans->table[i]->data );
                }
            }
        }
    }

    if( out_font->width != NULL ) {
        OUT_FONT_REMAP_MBR( width );
    }

    return( out_font );
}