/* automatically generated from narwfont.c. */
/*
 * Copyright (c) 1997-2006  Motoyuki Kasahara
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "build-pre.h"
#include "eb.h"
#include "error.h"
#include "font.h"
#include "build-post.h"

/*
 * Unexported functions.
 */
static EB_Error_Code eb_wide_character_bitmap_jis(EB_Book *book,
    int character_number, char *bitmap);
static EB_Error_Code eb_wide_character_bitmap_latin(EB_Book *book,
    int character_number, char *bitmap);


/*
 * Open a font file.
 */
EB_Error_Code
eb_open_wide_font_file(EB_Book *book, EB_Font_Code font_code)
{
    EB_Error_Code error_code;
    EB_Subbook *subbook;
    EB_Font *wide_font;
    char font_path_name[EB_MAX_PATH_LENGTH + 1];
    Zio_Code zio_code;

    LOG(("in: eb_open_wide_font(book=%d, font_code=%d)",
	(int)book->code, (int)font_code));

    subbook = book->subbook_current;
    wide_font = subbook->wide_fonts + font_code;

    if (wide_font->font_code == EB_FONT_INVALID) {
	error_code = EB_ERR_FAIL_OPEN_FONT;
	goto failed;
    }
    if (0 <= zio_file(&wide_font->zio))
	goto succeeded;

    /*
     * If the book is EBWING, open the wide font file.
     * (In EB books, font data are stored in the `START' file.)
     */
    zio_code = ZIO_INVALID;

    if (book->disc_code == EB_DISC_EB) {
	if (wide_font->initialized) {
	    if (zio_mode(&wide_font->zio) != ZIO_INVALID)
		zio_code = ZIO_REOPEN;
	} else {
	    zio_code = zio_mode(&subbook->text_zio);
	}
	eb_compose_path_name2(book->path, subbook->directory_name,
	    subbook->text_file_name, font_path_name);

    } else {
	if (wide_font->initialized) {
	    if (zio_mode(&wide_font->zio) != ZIO_INVALID)
		zio_code = ZIO_REOPEN;
	    eb_compose_path_name3(book->path, subbook->directory_name,
		subbook->gaiji_directory_name, wide_font->file_name,
		font_path_name);
	} else {
	    eb_canonicalize_file_name(wide_font->file_name);
	    if (eb_find_file_name3(book->path, subbook->directory_name,
		subbook->gaiji_directory_name, wide_font->file_name,
		wide_font->file_name) != EB_SUCCESS) {
		error_code = EB_ERR_FAIL_OPEN_FONT;
		goto failed;
	    }

	    eb_compose_path_name3(book->path, subbook->directory_name,
		subbook->gaiji_directory_name, wide_font->file_name,
		font_path_name);
	    eb_path_name_zio_code(font_path_name, ZIO_PLAIN, &zio_code);
	}
    }

    if (zio_code != ZIO_INVALID
	&& zio_open(&wide_font->zio, font_path_name, zio_code) < 0) {
	error_code = EB_ERR_FAIL_OPEN_FONT;
	goto failed;
    }

  succeeded:
    LOG(("out: eb_open_wide_font_file(file=%d) = %s",
	zio_file(&wide_font->zio), eb_error_string(EB_SUCCESS)));
    return EB_SUCCESS;

    /*
     * An error occurs...
     */
  failed:
    LOG(("out: eb_open_wide_font_file() = %s", eb_error_string(error_code)));
    return error_code;
}


/*
 * Read font header.
 */
EB_Error_Code
eb_load_wide_font_header(EB_Book *book, EB_Font_Code font_code)
{
    EB_Error_Code error_code;
    EB_Subbook *subbook;
    EB_Font *wide_font;
    char buffer[16];
    int character_count;
    Zio *zio;

    LOG(("in: eb_load_wide_font_header(book=%d, font_code=%d)",
	(int)book->code, (int)font_code));

    subbook = book->subbook_current;
    wide_font = subbook->wide_fonts + font_code;
    zio = &wide_font->zio;

    if (wide_font->initialized)
	goto succeeded;

    /*
     * Read information from the text file.
     */
    if (zio_lseek(zio, (wide_font->page - 1) * EB_SIZE_PAGE, SEEK_SET) < 0) {
	error_code = EB_ERR_FAIL_SEEK_FONT;
	goto failed;
    }
    if (zio_read(zio, buffer, 16) != 16) {
	error_code = EB_ERR_FAIL_READ_FONT;
	goto failed;
    }

    /*
     * If the number of characters (`character_count') is 0, the font
     * is unavailable.  We return EB_ERR_NO_SUCH_FONT.
     */
    character_count = eb_uint2(buffer + 12);
    if (character_count == 0) {
	zio_close(zio);
	error_code = EB_ERR_NO_SUCH_FONT;
	goto failed;
    }

    /*
     * Set the information.
     */
    wide_font->start = eb_uint2(buffer + 10);
    if (book->character_code == EB_CHARCODE_ISO8859_1) {
	wide_font->end = wide_font->start
	    + ((character_count / 0xfe) << 8) + (character_count % 0xfe) - 1;
	if (0xfe < (wide_font->end & 0xff))
	    wide_font->end += 3;
    } else {
	wide_font->end = wide_font->start
	    + ((character_count / 0x5e) << 8) + (character_count % 0x5e) - 1;
	if (0x7e < (wide_font->end & 0xff))
	    wide_font->end += 0xa3;
    }

    if (book->character_code == EB_CHARCODE_ISO8859_1) {
	if ((wide_font->start & 0xff) < 0x01
	    || 0xfe < (wide_font->start & 0xff)
	    || wide_font->start < 0x0001
	    || 0x1efe < wide_font->end) {
	    error_code = EB_ERR_UNEXP_FONT;
	    goto failed;
	}
    } else {
	if ((wide_font->start & 0xff) < 0x21
	    || 0x7e < (wide_font->start & 0xff)
	    || wide_font->start < 0xa121
	    || 0xfe7e < wide_font->end) {
	    error_code = EB_ERR_UNEXP_FONT;
	    goto failed;
	}
    }

  succeeded:
    LOG(("out: eb_load_wide_font_header()", eb_error_string(EB_SUCCESS)));
    return EB_SUCCESS;

    /*
     * An error occurs...
     */
  failed:
    LOG(("out: eb_load_wide_font_header()", eb_error_string(error_code)));
    return error_code;
}


/*
 * Read font glyph data.
 */
EB_Error_Code
eb_load_wide_font_glyphs(EB_Book *book, EB_Font_Code font_code)
{
    EB_Error_Code error_code;
    EB_Subbook *subbook;
    EB_Font *wide_font;
    int character_count;
    size_t glyph_size;
    size_t total_glyph_size;
    Zio *zio;

    LOG(("in: eb_load_wide_font_glyphs(book=%d, font_code=%d)",
	(int)book->code, (int)font_code));

    subbook = book->subbook_current;
    wide_font = subbook->wide_fonts + font_code;
    zio = &wide_font->zio;

    if (wide_font->glyphs != NULL)
	goto succeeded;

    /*
     * Calculate size of glyph data (`total_glyph_size').
     *
     *    Set the number of local defined characters to `character_count'.
     *    Set the number of character glpyhs in a page to `page_glyph_count'.
     *    Set size of glyph data to `total_glyph_size'.
     */
    if (book->character_code == EB_CHARCODE_ISO8859_1) {
	character_count
	    = ((wide_font->end >> 8) - (wide_font->start >> 8)) * 0xfe
	    + ((wide_font->end & 0xff) - (wide_font->start & 0xff)) + 1;
    } else {
	character_count
	    = ((wide_font->end >> 8) - (wide_font->start >> 8)) * 0x5e
	    + ((wide_font->end & 0xff) - (wide_font->start & 0xff)) + 1;
    }

    eb_wide_font_size2(font_code, &glyph_size);
    total_glyph_size
	= (character_count / (1024 / glyph_size)) * 1024
	+ (character_count % (1024 / glyph_size)) * glyph_size;

    /*
     * Allocate memory for glyph data.
     */
    wide_font->glyphs = (char *) malloc(total_glyph_size);
    if (wide_font->glyphs == NULL) {
	error_code = EB_ERR_MEMORY_EXHAUSTED;
	goto failed;
    }

    /*
     * Read glyphs.
     */
    if (zio_lseek(zio, wide_font->page * EB_SIZE_PAGE, SEEK_SET) < 0) {
	error_code = EB_ERR_FAIL_SEEK_FONT;
	goto failed;
    }
    if (zio_read(zio, wide_font->glyphs, total_glyph_size)
	!= total_glyph_size) {
	error_code = EB_ERR_FAIL_READ_FONT;
	goto failed;
    }

  succeeded:
    LOG(("out: eb_load_wide_font_glyphs()", eb_error_string(EB_SUCCESS)));
    return EB_SUCCESS;

    /*
     * An error occurs...
     */
  failed:
    LOG(("out: eb_load_wide_font_glyphs()", eb_error_string(error_code)));
    if (wide_font->glyphs != NULL) {
	free(wide_font->glyphs);
	wide_font->glyphs = NULL;
    }
    return error_code;
}


/*
 * Examine whether the current subbook in `book' has a wide font.
 */
int
eb_have_wide_font(EB_Book *book)
{
    int i;

    eb_lock(&book->lock);
    LOG(("in: eb_have_wide_font(book=%d)", (int)book->code));

    /*
     * Current subbook must have been set.
     */
    if (book->subbook_current == NULL)
	goto failed;

    /*
     * If the wide font has already set, the subbook has wide fonts.
     */
    if (book->subbook_current->wide_current != NULL)
	goto succeeded;

    /*
     * Scan the font table.
     */
    for (i = 0; i < EB_MAX_FONTS; i++) {
	if (book->subbook_current->wide_fonts[i].font_code
	    != EB_FONT_INVALID)
	    break;
    }

    if (EB_MAX_FONTS <= i)
	goto failed;

  succeeded:
    LOG(("out: eb_have_wide_font() = %d", 1));
    eb_unlock(&book->lock);
    return 1;

    /*
     * An error occurs...
     */
  failed:
    LOG(("out: eb_have_wide_font() = %d", 0));
    eb_unlock(&book->lock);
    return 0;
}


/*
 * Get width of the font `font_code' in the current subbook of `book'.
 */
EB_Error_Code
eb_wide_font_width(EB_Book *book, int *width)
{
    EB_Error_Code error_code;
    EB_Font_Code font_code;

    eb_lock(&book->lock);
    LOG(("in: eb_wide_font_width(book=%d)", (int)book->code));

    /*
     * Current subbook must have been set.
     */
    if (book->subbook_current == NULL) {
	error_code = EB_ERR_NO_CUR_SUB;
	goto failed;
    }

    /*
     * The wide font must exist in the current subbook.
     */
    if (book->subbook_current->wide_current == NULL) {
	error_code = EB_ERR_NO_CUR_FONT;
	goto failed;
    }

    /*
     * Calculate width.
     */
    font_code = book->subbook_current->wide_current->font_code;
    error_code = eb_wide_font_width2(font_code, width);
    if (error_code != EB_SUCCESS)
	goto failed;

    LOG(("out: eb_wide_font_width(width=%d) = %s", (int)*width,
	eb_error_string(EB_SUCCESS)));
    eb_unlock(&book->lock);

    return EB_SUCCESS;

    /*
     * An error occurs...
     */
  failed:
    *width = 0;
    LOG(("out: eb_wide_font_width() = %s", eb_error_string(error_code)));
    eb_unlock(&book->lock);
    return error_code;
}


/*
 * Get width of the font `font_code'.
 */
EB_Error_Code
eb_wide_font_width2(EB_Font_Code font_code, int *width)
{
    EB_Error_Code error_code;

    LOG(("in: eb_wide_font_width2(font_code=%d)", (int)font_code));

    switch (font_code) {
    case EB_FONT_16:
	*width = EB_WIDTH_WIDE_FONT_16;
	break;
    case EB_FONT_24:
	*width = EB_WIDTH_WIDE_FONT_24;
	break;
    case EB_FONT_30:
	*width = EB_WIDTH_WIDE_FONT_30;
	break;
    case EB_FONT_48:
	*width = EB_WIDTH_WIDE_FONT_48;
	break;
    default:
	error_code = EB_ERR_NO_SUCH_FONT;
	goto failed;
    }

    LOG(("out: eb_wide_font_width2(width=%d) = %s", *width,
	eb_error_string(EB_SUCCESS)));

    return EB_SUCCESS;

    /*
     * An error occurs...
     */
  failed:
    *width = 0;
    LOG(("out: eb_wide_font_width2() = %s", eb_error_string(error_code)));
    return error_code;
}


/*
 * Get the bitmap size of the font `font_code' in the current subbook
 * of `book'.
 */
EB_Error_Code
eb_wide_font_size(EB_Book *book, size_t *size)
{
    EB_Error_Code error_code;
    EB_Font_Code font_code;
    int width;
    int height;

    eb_lock(&book->lock);
    LOG(("in: eb_wide_font_size(book=%d)", (int)book->code));

    /*
     * Current subbook must have been set.
     */
    if (book->subbook_current == NULL) {
	error_code = EB_ERR_NO_CUR_SUB;
	goto failed;
    }

    /*
     * The wide font must exist in the current subbook.
     */
    if (book->subbook_current->wide_current == NULL) {
	error_code = EB_ERR_NO_CUR_FONT;
	goto failed;
    }

    /*
     * Calculate size.
     */
    font_code = book->subbook_current->wide_current->font_code;
    error_code = eb_wide_font_width2(font_code, &width);
    if (error_code != EB_SUCCESS)
	goto failed;
    error_code = eb_font_height2(font_code, &height);
    if (error_code != EB_SUCCESS)
	goto failed;
    *size = (width / 8) * height;

    LOG(("out: eb_wide_font_size(size=%ld) = %s", (long)*size,
	eb_error_string(EB_SUCCESS)));
    eb_unlock(&book->lock);

    return EB_SUCCESS;

    /*
     * An error occurs...
     */
  failed:
    *size = 0;
    LOG(("out: eb_wide_font_size() = %s", eb_error_string(error_code)));
    eb_unlock(&book->lock);
    return error_code;
}


/*
 * Get the bitmap size of a character in `font_code' of the current
 * subbook.
 */
EB_Error_Code
eb_wide_font_size2(EB_Font_Code font_code, size_t *size)
{
    EB_Error_Code error_code;

    LOG(("in: eb_wide_font_size2(font_code=%d)", (int)font_code));

    switch (font_code) {
    case EB_FONT_16:
	*size = EB_SIZE_WIDE_FONT_16;
	break;
    case EB_FONT_24:
	*size = EB_SIZE_WIDE_FONT_24;
	break;
    case EB_FONT_30:
	*size = EB_SIZE_WIDE_FONT_30;
	break;
    case EB_FONT_48:
	*size = EB_SIZE_WIDE_FONT_48;
	break;
    default:
	error_code = EB_ERR_NO_SUCH_FONT;
	goto failed;
    }

    LOG(("out: eb_wide_font_size2(size=%ld) = %s", (long)*size,
	eb_error_string(EB_SUCCESS)));

    return EB_SUCCESS;

    /*
     * An error occurs...
     */
  failed:
    *size = 0;
    LOG(("out: eb_wide_font_size2() = %s", eb_error_string(error_code)));
    return error_code;
}


/*
 * Get the character number of the start of the wide font of the current
 * subbook in `book'.
 */
EB_Error_Code
eb_wide_font_start(EB_Book *book, int *start)
{
    EB_Error_Code error_code;

    eb_lock(&book->lock);
    LOG(("in: eb_wide_font_start(book=%d)", (int)book->code));

    /*
     * Current subbook must have been set.
     */
    if (book->subbook_current == NULL) {
	error_code = EB_ERR_NO_CUR_SUB;
	goto failed;
    }

    /*
     * The wide font must exist in the current subbook.
     */
    if (book->subbook_current->wide_current == NULL) {
	error_code = EB_ERR_NO_CUR_FONT;
	goto failed;
    }

    *start = book->subbook_current->wide_current->start;

    LOG(("out: eb_wide_font_start(start=%d) = %s", *start,
	eb_error_string(EB_SUCCESS)));
    eb_unlock(&book->lock);

    return EB_SUCCESS;

    /*
     * An error occurs...
     */
  failed:
    LOG(("out: eb_wide_font_start() = %s", eb_error_string(error_code)));
    eb_unlock(&book->lock);
    return error_code;
}


/*
 * Get the character number of the end of the wide font of the current
 * subbook in `book'.
 */
EB_Error_Code
eb_wide_font_end(EB_Book *book, int *end)
{
    EB_Error_Code error_code;

    eb_lock(&book->lock);
    LOG(("in: eb_wide_font_end(book=%d)", (int)book->code));

    /*
     * Current subbook must have been set.
     */
    if (book->subbook_current == NULL) {
	error_code = EB_ERR_NO_CUR_SUB;
	goto failed;
    }

    /*
     * The wide font must exist in the current subbook.
     */
    if (book->subbook_current->wide_current == NULL) {
	error_code = EB_ERR_NO_CUR_FONT;
	goto failed;
    }

    *end = book->subbook_current->wide_current->end;

    LOG(("out: eb_wide_font_end(end=%d) = %s", *end,
	eb_error_string(EB_SUCCESS)));
    eb_unlock(&book->lock);

    return EB_SUCCESS;

    /*
     * An error occurs...
     */
  failed:
    LOG(("out: eb_wide_font_end() = %s", eb_error_string(error_code)));
    eb_unlock(&book->lock);
    return error_code;
}


/*
 * Get bitmap data of the character with character number `character_number'
 * in the current wide font of the current subbook in `book'.
 */
EB_Error_Code
eb_wide_font_character_bitmap(EB_Book *book, int character_number,
    char *bitmap)
{
    EB_Error_Code error_code;

    eb_lock(&book->lock);
    LOG(("in: eb_wide_font_character_bitmap(book=%d, character_number=%d)",
	(int)book->code, character_number));

    /*
     * Current subbook must have been set.
     */
    if (book->subbook_current == NULL) {
	error_code = EB_ERR_NO_CUR_SUB;
	goto failed;
    }

    /*
     * The wide font must exist in the current subbook.
     */
    if (book->subbook_current->wide_current == NULL) {
	error_code = EB_ERR_NO_CUR_FONT;
	goto failed;
    }

    if (book->character_code == EB_CHARCODE_ISO8859_1) {
	error_code = eb_wide_character_bitmap_latin(book, character_number,
	    bitmap);
    } else {
	error_code = eb_wide_character_bitmap_jis(book, character_number,
	    bitmap);
    }
    if (error_code != EB_SUCCESS)
	goto failed;

    LOG(("out: eb_wide_font_character_bitmap() = %s",
	eb_error_string(EB_SUCCESS)));
    eb_unlock(&book->lock);

    return EB_SUCCESS;

    /*
     * An error occurs...
     */
  failed:
    *bitmap = '\0';
    LOG(("out: eb_wide_font_character_bitmap() = %s",
	eb_error_string(error_code)));
    eb_unlock(&book->lock);
    return error_code;
}


/*
 * Get bitmap data of the character with character number `character_number'
 * in the current wide font of the current subbook in `book'.
 */
static EB_Error_Code
eb_wide_character_bitmap_jis(EB_Book *book, int character_number,
    char *bitmap)
{
    EB_Error_Code error_code;
    EB_Font *wide_current;
    int start;
    int end;
    int character_index;
    off_t offset;
    size_t size;
    Zio *zio;

    LOG(("in: eb_wide_font_character_bitmap_jis(book=%d, \
character_number=%d)",
	(int)book->code, character_number));

    start = book->subbook_current->wide_current->start;
    end = book->subbook_current->wide_current->end;
    wide_current = book->subbook_current->wide_current;

    /*
     * Check for `character_number'.  Is it in a range of bitmaps?
     * This test works correctly even when the font doesn't exist in
     * the current subbook because `start' and `end' have set to -1
     * in the case.
     */
    if (character_number < start
	|| end < character_number
	|| (character_number & 0xff) < 0x21
	|| 0x7e < (character_number & 0xff)) {
	error_code = EB_ERR_NO_SUCH_CHAR_BMP;
	goto failed;
    }

    /*
     * Calculate the size and the location of bitmap data.
     */
    error_code = eb_wide_font_size(book, &size);
    if (error_code != EB_SUCCESS)
	goto failed;

    character_index = ((character_number >> 8) - (start >> 8)) * 0x5e
	+ ((character_number & 0xff) - (start & 0xff));
    offset
	= (character_index / (1024 / size)) * 1024
	+ (character_index % (1024 / size)) * size;

    /*
     * Read bitmap data.
     */
    if (wide_current->glyphs == NULL) {
	zio = &wide_current->zio;

	if (zio_lseek(zio, wide_current->page * EB_SIZE_PAGE + offset,
		SEEK_SET) < 0) {
	    error_code = EB_ERR_FAIL_SEEK_FONT;
	    goto failed;
	}
	if (zio_read(zio, bitmap, size) != size) {
	    error_code = EB_ERR_FAIL_READ_FONT;
	    goto failed;
	}
    } else {
	memcpy(bitmap, wide_current->glyphs + offset, size);
    }

    LOG(("out: eb_wide_font_character_bitmap_jis() = %s",
	eb_error_string(EB_SUCCESS)));

    return EB_SUCCESS;

    /*
     * An error occurs...
     */
  failed:
    *bitmap = '\0';
    LOG(("out: eb_wide_font_character_bitmap_jis() = %s",
	eb_error_string(error_code)));
    return error_code;
}


/*
 * Get bitmap data of the character with character number `character_number'
 * in the current wide font of the current subbook in `book'.
 */
static EB_Error_Code
eb_wide_character_bitmap_latin(EB_Book *book, int character_number,
    char *bitmap)
{
    EB_Error_Code error_code;
    EB_Font *wide_current;
    int start;
    int end;
    int character_index;
    off_t offset;
    size_t size;
    Zio *zio;

    LOG(("in: eb_wide_font_character_bitmap_latin(book=%d, \
character_number=%d)",
	(int)book->code, character_number));

    start = book->subbook_current->wide_current->start;
    end = book->subbook_current->wide_current->end;
    wide_current = book->subbook_current->wide_current;

    /*
     * Check for `ch'.  Is it in a range of bitmaps?
     * This test works correctly even when the font doesn't exist in
     * the current subbook because `start' and `end' have set to -1
     * in the case.
     */
    if (character_number < start
	|| end < character_number
	|| (character_number & 0xff) < 0x01
	|| 0xfe < (character_number & 0xff)) {
	error_code = EB_ERR_NO_SUCH_CHAR_BMP;
	goto failed;
    }

    /*
     * Calculate the size and the location of bitmap data.
     */
    error_code = eb_wide_font_size(book, &size);
    if (error_code != EB_SUCCESS)
	goto failed;

    character_index = ((character_number >> 8) - (start >> 8)) * 0xfe
	+ ((character_number & 0xff) - (start & 0xff));
    offset
	= (character_index / (1024 / size)) * 1024
	+ (character_index % (1024 / size)) * size;

    /*
     * Read bitmap data.
     */
    if (wide_current->glyphs == NULL) {
	zio = &wide_current->zio;

	if (zio_lseek(zio, wide_current->page * EB_SIZE_PAGE + offset,
		SEEK_SET) < 0) {
	    error_code = EB_ERR_FAIL_SEEK_FONT;
	    goto failed;
	}
	if (zio_read(zio, bitmap, size) != size) {
	    error_code = EB_ERR_FAIL_READ_FONT;
	    goto failed;
	}
    } else {
	memcpy(bitmap, wide_current->glyphs + offset, size);
    }

    LOG(("out: eb_wide_font_character_bitmap_latin() = %s",
	eb_error_string(EB_SUCCESS)));

    return EB_SUCCESS;

    /*
     * An error occurs...
     */
  failed:
    *bitmap = '\0';
    LOG(("out: eb_wide_font_character_bitmap_latin() = %s",
	eb_error_string(error_code)));
    return error_code;
}


/*
 * Return next `n'th character number from `character_number'.
 */
EB_Error_Code
eb_forward_wide_font_character(EB_Book *book, int n, int *character_number)
{
    EB_Error_Code error_code;
    int start;
    int end;
    int i;

    if (n < 0)
	return eb_backward_wide_font_character(book, -n, character_number);

    eb_lock(&book->lock);
    LOG(("in: eb_forward_wide_font_character(book=%d, n=%d, \
character_number=%d)",
	(int)book->code, n, *character_number));

    /*
     * Current subbook must have been set.
     */
    if (book->subbook_current == NULL) {
	error_code = EB_ERR_NO_CUR_SUB;
	goto failed;
    }

    /*
     * The wide font must exist in the current subbook.
     */
    if (book->subbook_current->wide_current == NULL) {
	error_code = EB_ERR_NO_CUR_FONT;
	goto failed;
    }

    start = book->subbook_current->wide_current->start;
    end = book->subbook_current->wide_current->end;

    if (book->character_code == EB_CHARCODE_ISO8859_1) {
	/*
	 * Check for `*character_number'. (ISO 8859 1)
	 */
	if (*character_number < start
	    || end < *character_number
	    || (*character_number & 0xff) < 0x01
	    || 0xfe < (*character_number & 0xff)) {
	    error_code = EB_ERR_NO_SUCH_CHAR_BMP;
	    goto failed;
	}

	/*
	 * Get character number. (ISO 8859 1)
	 */
	for (i = 0; i < n; i++) {
	    if (0xfe <= (*character_number & 0xff))
		*character_number += 3;
	    else
		*character_number += 1;
	    if (end < *character_number) {
		error_code = EB_ERR_NO_SUCH_CHAR_BMP;
		goto failed;
	    }
	}
    } else {
	/*
	 * Check for `*character_number'. (JIS X 0208)
	 */
	if (*character_number < start
	    || end < *character_number
	    || (*character_number & 0xff) < 0x21
	    || 0x7e < (*character_number & 0xff)) {
	    error_code = EB_ERR_NO_SUCH_CHAR_BMP;
	    goto failed;
	}

	/*
	 * Get character number. (JIS X 0208)
	 */
	for (i = 0; i < n; i++) {
	    if (0x7e <= (*character_number & 0xff))
		*character_number += 0xa3;
	    else
		*character_number += 1;
	    if (end < *character_number) {
		error_code = EB_ERR_NO_SUCH_CHAR_BMP;
		goto failed;
	    }
	}
    }

    LOG(("out: eb_forward_wide_font_character(character_number=%d) = %s",
	*character_number, eb_error_string(EB_SUCCESS)));
    eb_unlock(&book->lock);

    return EB_SUCCESS;

    /*
     * An error occurs...
     */
  failed:
    *character_number = -1;
    LOG(("out: eb_forward_wide_font_character() = %s",
	eb_error_string(error_code)));
    eb_unlock(&book->lock);
    return error_code;
}


/*
 * Return previous `n'th character number from `*character_number'.
 */
EB_Error_Code
eb_backward_wide_font_character(EB_Book *book, int n, int *character_number)
{
    EB_Error_Code error_code;
    int start;
    int end;
    int i;

    if (n < 0)
	return eb_forward_wide_font_character(book, -n, character_number);

    eb_lock(&book->lock);
    LOG(("in: eb_backward_wide_font_character(book=%d, n=%d, \
character_number=%d)",
	(int)book->code, n, *character_number));

    /*
     * Current subbook must have been set.
     */
    if (book->subbook_current == NULL) {
	error_code = EB_ERR_NO_CUR_SUB;
	goto failed;
    }

    /*
     * The wide font must exist in the current subbook.
     */
    if (book->subbook_current->wide_current == NULL) {
	error_code = EB_ERR_NO_CUR_FONT;
	goto failed;
    }

    start = book->subbook_current->wide_current->start;
    end = book->subbook_current->wide_current->end;

    if (book->character_code == EB_CHARCODE_ISO8859_1) {
	/*
	 * Check for `*character_number'. (ISO 8859 1)
	 */
	if (*character_number < start
	    || end < *character_number
	    || (*character_number & 0xff) < 0x01
	    || 0xfe < (*character_number & 0xff)) {
	    error_code = EB_ERR_NO_SUCH_CHAR_BMP;
	    goto failed;
	}

	/*
	 * Get character number. (ISO 8859 1)
	 */
	for (i = 0; i < n; i++) {
	    if ((*character_number & 0xff) <= 0x01)
		*character_number -= 3;
	    else
		*character_number -= 1;
	    if (*character_number < start) {
		error_code = EB_ERR_NO_SUCH_CHAR_BMP;
		goto failed;
	    }
	}
    } else {
	/*
	 * Check for `*character_number'. (JIS X 0208)
	 */
	if (*character_number < start
	    || end < *character_number
	    || (*character_number & 0xff) < 0x21
	    || 0x7e < (*character_number & 0xff)) {
	    error_code = EB_ERR_NO_SUCH_CHAR_BMP;
	    goto failed;
	}

	/*
	 * Get character number. (JIS X 0208)
	 */
	for (i = 0; i < n; i++) {
	    if ((*character_number & 0xff) <= 0x21)
		*character_number -= 0xa3;
	    else
		*character_number -= 1;
	    if (*character_number < start) {
		error_code = EB_ERR_NO_SUCH_CHAR_BMP;
		goto failed;
	    }
	}
    }

    LOG(("out: eb_backward_wide_font_character(character_number=%d) = %s",
	*character_number, eb_error_string(EB_SUCCESS)));
    eb_unlock(&book->lock);

    return EB_SUCCESS;

    /*
     * An error occurs...
     */
  failed:
    *character_number = -1;
    LOG(("out: eb_backward_wide_font_character() = %s",
	eb_error_string(error_code)));
    eb_unlock(&book->lock);
    return error_code;
}


