1
zero-epwing-go/binary.c
2021-01-09 15:22:43 -08:00

1383 lines
37 KiB
C

/* -*- C -*-
* Copyright (c) 2001-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 "binary.h"
#include "build-post.h"
/*
* Unexported function.
*/
static EB_Error_Code eb_read_binary_generic(EB_Book *book,
size_t binary_max_length, char *binary, ssize_t *binary_length);
static EB_Error_Code eb_read_binary_wave(EB_Book *book,
size_t binary_max_length, char *binary, ssize_t *binary_length);
static EB_Error_Code eb_read_binary_mono_graphic(EB_Book *book,
size_t binary_max_length, char *binary, ssize_t *binary_length);
static EB_Error_Code eb_read_binary_gray_graphic(EB_Book *book,
size_t binary_max_length, char *binary, ssize_t *binary_length);
/*
* Initialize binary context of `book'.
*/
void
eb_initialize_binary_context(EB_Book *book)
{
LOG(("in: eb_initialize_binary_context(book=%d)", (int)book->code));
book->binary_context.code = EB_BINARY_INVALID;
book->binary_context.zio = NULL;
book->binary_context.location = -1;
book->binary_context.size = 0;
book->binary_context.cache_length = 0;
book->binary_context.cache_offset = 0;
book->binary_context.width = 0;
LOG(("out: eb_initialize_binary_context()"));
}
/*
* Finalize binary context of `book'.
*/
void
eb_finalize_binary_context(EB_Book *book)
{
LOG(("in+out: eb_finalize_binary_context(book=%d)", (int)book->code));
/* nothing to be done */
}
/*
* Reset binary context of `book'.
*/
void
eb_reset_binary_context(EB_Book *book)
{
LOG(("in: eb_reset_binary_context(book=%d)", (int)book->code));
eb_initialize_binary_context(book);
LOG(("out: eb_reset_binary_context()"));
}
/*
* Template of BMP preamble for 2 colors monochrome graphic.
*/
#define MONO_BMP_PREAMBLE_LENGTH 62
static const unsigned char mono_bmp_preamble[] = {
/* Type. */
'B', 'M',
/* File size. (set at run time) */
0x00, 0x00, 0x00, 0x00,
/* Reserved. */
0x00, 0x00, 0x00, 0x00,
/* Offset of bitmap bits part. */
0x3e, 0x00, 0x00, 0x00,
/* Size of bitmap info part. */
0x28, 0x00, 0x00, 0x00,
/* Width. (set at run time) */
0x00, 0x00, 0x00, 0x00,
/* Height. (set at run time) */
0x00, 0x00, 0x00, 0x00,
/* Planes. */
0x01, 0x00,
/* Bits per pixels. */
0x01, 0x00,
/* Compression mode. */
0x00, 0x00, 0x00, 0x00,
/* Size of bitmap bits part. (set at run time) */
0x00, 0x00, 0x00, 0x00,
/* X Pixels per meter. */
0x6d, 0x0b, 0x00, 0x00,
/* Y Pixels per meter. */
0x6d, 0x0b, 0x00, 0x00,
/* Colors */
0x02, 0x00, 0x00, 0x00,
/* Important colors */
0x02, 0x00, 0x00, 0x00,
/* RGB quad of color 0 RGB quad of color 1 */
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/*
* Set monochrome bitmap picture as the current binary data.
*/
EB_Error_Code
eb_set_binary_mono_graphic(EB_Book *book, const EB_Position *position,
int width, int height)
{
EB_Error_Code error_code;
EB_Binary_Context *context;
EB_Position real_position;
unsigned char *buffer_p;
size_t line_pad_length;
size_t data_size;
size_t file_size;
LOG(("in: eb_set_binary_mono_graphic(book=%d, position={%d,%d}, \
width=%d, height=%d)",
(int)book->code, position->page, position->offset, width, height));
eb_reset_binary_context(book);
/*
* Current subbook must have been set.
*/
if (book->subbook_current == NULL) {
error_code = EB_ERR_NO_CUR_SUB;
goto failed;
}
/*
* Current subbook must have a graphic file.
*/
if (zio_file(&book->subbook_current->text_zio) < 0) {
error_code = EB_ERR_NO_SUCH_BINARY;
goto failed;
}
/*
* If both width and height are 0,
* we get real width, height and position of the graphic data.
*/
if (position->page <= 0 || position->offset < 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
if (width == 0 && height == 0) {
char buffer[22];
if (zio_lseek(&book->subbook_current->text_zio,
((off_t) position->page - 1) * EB_SIZE_PAGE + position->offset,
SEEK_SET) < 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
if (zio_read(&book->subbook_current->text_zio, buffer, 22) != 22) {
error_code = EB_ERR_FAIL_READ_BINARY;
goto failed;
}
if (eb_uint2(buffer) != 0x1f45 || eb_uint2(buffer + 4) != 0x1f31) {
error_code = EB_ERR_UNEXP_BINARY;
goto failed;
}
width = eb_bcd2(buffer + 8);
height = eb_bcd2(buffer + 10);
if (eb_uint2(buffer + 12) == 0x1f51) {
real_position.page = eb_bcd4(buffer + 14);
real_position.offset = eb_bcd2(buffer + 18);
} else if (eb_uint2(buffer + 14) == 0x1f51) {
real_position.page = eb_bcd4(buffer + 16);
real_position.offset = eb_bcd2(buffer + 20);
} else {
error_code = EB_ERR_UNEXP_BINARY;
goto failed;
}
position = &real_position;
}
if (width <= 0 || height <= 0) {
error_code = EB_ERR_NO_SUCH_BINARY;
goto failed;
}
/*
* BMP requires that the number of bytes in a line must be multiple
* of 4. If not, 0x00 must be padded to end of each line.
* `line_pad_length' (0...3) is the number of bytes to be padded.
*
* In case of EB_BINARY_MONO_GRAPHIC, a pixel is represented with
* a bit.
*/
if (width % 32 == 0)
line_pad_length = 0;
else if (width % 32 <= 8)
line_pad_length = 3;
else if (width % 32 <= 16)
line_pad_length = 2;
else if (width % 32 <= 24)
line_pad_length = 1;
else
line_pad_length = 0;
data_size = (width / 8 + line_pad_length) * height;
file_size = data_size + MONO_BMP_PREAMBLE_LENGTH;
/*
* Set binary context.
*/
context = &book->binary_context;
context->code = EB_BINARY_MONO_GRAPHIC;
context->zio = &book->subbook_current->text_zio;
context->location = ((off_t) position->page - 1) * EB_SIZE_PAGE
+ position->offset + (width + 7) / 8 * (height - 1);
context->size = (width + 7) / 8 * height;
context->offset = 0;
context->cache_offset = 0;
context->width = width;
/*
* Set BMP preamble.
*/
context->cache_length = MONO_BMP_PREAMBLE_LENGTH;
memcpy(context->cache_buffer, mono_bmp_preamble, MONO_BMP_PREAMBLE_LENGTH);
buffer_p = (unsigned char *)context->cache_buffer + 2;
*buffer_p++ = file_size & 0xff;
*buffer_p++ = (file_size >> 8) & 0xff;
*buffer_p++ = (file_size >> 16) & 0xff;
*buffer_p++ = (file_size >> 24) & 0xff;
buffer_p = (unsigned char *)context->cache_buffer + 18;
*buffer_p++ = width & 0xff;
*buffer_p++ = (width >> 8) & 0xff;
*buffer_p++ = (width >> 16) & 0xff;
*buffer_p++ = (width >> 24) & 0xff;
*buffer_p++ = height & 0xff;
*buffer_p++ = (height >> 8) & 0xff;
*buffer_p++ = (height >> 16) & 0xff;
*buffer_p++ = (height >> 24) & 0xff;
buffer_p = (unsigned char *)context->cache_buffer + 34;
*buffer_p++ = data_size & 0xff;
*buffer_p++ = (data_size >> 8) & 0xff;
*buffer_p++ = (data_size >> 16) & 0xff;
*buffer_p++ = (data_size >> 24) & 0xff;
/*
* Seek graphic file.
*/
if (zio_lseek(context->zio, context->location, SEEK_SET) < 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
LOG(("out: eb_set_binary_mono_graphic() = %s",
eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
eb_reset_binary_context(book);
LOG(("out: eb_set_binary_mono_graphic() = %s",
eb_error_string(error_code)));
return error_code;
}
/*
* Template of BMP preamble for gray scale graphic.
*/
#define GRAY_BMP_PREAMBLE_LENGTH 118
static const unsigned char gray_bmp_preamble[] = {
/* Type. */
'B', 'M',
/* File size. (set at run time) */
0x00, 0x00, 0x00, 0x00,
/* Reserved. */
0x00, 0x00, 0x00, 0x00,
/* Offset of bitmap bits part. */
0x3e, 0x00, 0x00, 0x00,
/* Size of bitmap info part. */
0x28, 0x00, 0x00, 0x00,
/* Width. (set at run time) */
0x00, 0x00, 0x00, 0x00,
/* Height. (set at run time) */
0x00, 0x00, 0x00, 0x00,
/* Planes. */
0x01, 0x00,
/* Bits per pixels. */
0x04, 0x00,
/* Compression mode. */
0x00, 0x00, 0x00, 0x00,
/* Size of bitmap bits part. (set at run time) */
0x00, 0x00, 0x00, 0x00,
/* X Pixels per meter. */
0x6d, 0x0b, 0x00, 0x00,
/* Y Pixels per meter. */
0x6d, 0x0b, 0x00, 0x00,
/* Colors */
0x10, 0x00, 0x00, 0x00,
/* Important colors */
0x10, 0x00, 0x00, 0x00,
/* RGB quad of color 0x0 RGB quad of color 0x1 */
0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00,
/* RGB quad of color 0x2 RGB quad of color 0x3 */
0x22, 0x22, 0x22, 0x00, 0x33, 0x33, 0x33, 0x00,
/* RGB quad of color 0x4 RGB quad of color 0x5 */
0x44, 0x44, 0x44, 0x00, 0x55, 0x55, 0x55, 0x00,
/* RGB quad of color 0x6 RGB quad of color 0x7 */
0x66, 0x66, 0x66, 0x00, 0x77, 0x77, 0x77, 0x00,
/* RGB quad of color 0x8 RGB quad of color 0x9 */
0x88, 0x88, 0x88, 0x00, 0x99, 0x99, 0x99, 0x00,
/* RGB quad of color 0xa RGB quad of color 0xb */
0xaa, 0xaa, 0xaa, 0x00, 0xbb, 0xbb, 0xbb, 0x00,
/* RGB quad of color 0xc RGB quad of color 0xd */
0xcc, 0xcc, 0xcc, 0x00, 0xdd, 0xdd, 0xdd, 0x00,
/* RGB quad of color 0xe RGB quad of color 0xf */
0xee, 0xee, 0xee, 0x00, 0xff, 0xff, 0xff, 0x00,
};
/*
* Set monochrome bitmap picture as the current binary data.
*/
EB_Error_Code
eb_set_binary_gray_graphic(EB_Book *book, const EB_Position *position,
int width, int height)
{
EB_Error_Code error_code;
EB_Binary_Context *context;
EB_Position real_position;
unsigned char *buffer_p;
size_t line_pad_length;
size_t data_size;
size_t file_size;
LOG(("in: eb_set_binary_gray_graphic(book=%d, position={%d,%d}, \
width=%d, height=%d)",
(int)book->code, position->page, position->offset, width, height));
eb_reset_binary_context(book);
/*
* Current subbook must have been set.
*/
if (book->subbook_current == NULL) {
error_code = EB_ERR_NO_CUR_SUB;
goto failed;
}
/*
* Current subbook must have a graphic file.
*/
if (zio_file(&book->subbook_current->text_zio) < 0) {
error_code = EB_ERR_NO_SUCH_BINARY;
goto failed;
}
/*
* If both width and height are 0,
* we get real width, height and position of the graphic data.
*/
if (position->page <= 0 || position->offset < 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
if (width == 0 && height == 0) {
char buffer[22];
if (zio_lseek(&book->subbook_current->text_zio,
((off_t) position->page - 1) * EB_SIZE_PAGE + position->offset,
SEEK_SET) < 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
if (zio_read(&book->subbook_current->text_zio, buffer, 22) != 22) {
error_code = EB_ERR_FAIL_READ_BINARY;
goto failed;
}
if (eb_uint2(buffer) != 0x1f45
|| eb_uint2(buffer + 4) != 0x1f31
|| eb_uint2(buffer + 12) != 0x1f51
|| eb_uint2(buffer + 20) != 0x1f65) {
error_code = EB_ERR_UNEXP_BINARY;
goto failed;
}
width = eb_bcd2(buffer + 8);
height = eb_bcd2(buffer + 10);
real_position.page = eb_bcd4(buffer + 14);
real_position.offset = eb_bcd2(buffer + 18);
position = &real_position;
}
if (width <= 0 || height <= 0) {
error_code = EB_ERR_NO_SUCH_BINARY;
goto failed;
}
/*
* BMP requires that the number of bytes in a line must be multiple
* of 4. If not, 0x00 must be padded to end of each line.
* `line_pad_length' (0...3) is the number of bytes to be padded.
*
* In case of EB_BINARY_GRAY_GRAPHIC, a pixel is represented with
* 4 bits.
*/
if (width % 8 == 0)
line_pad_length = 0;
else if (width % 8 <= 2)
line_pad_length = 3;
else if (width % 8 <= 4)
line_pad_length = 2;
else if (width % 8 <= 6)
line_pad_length = 1;
else
line_pad_length = 0;
data_size = (width / 2 + line_pad_length) * height;
file_size = data_size + MONO_BMP_PREAMBLE_LENGTH;
/*
* Set binary context.
*/
context = &book->binary_context;
context->code = EB_BINARY_GRAY_GRAPHIC;
context->zio = &book->subbook_current->text_zio;
context->location = ((off_t) position->page - 1) * EB_SIZE_PAGE
+ position->offset + (width + 1) / 2 * (height - 1);
context->size = (width + 1) / 2 * height;
context->offset = 0;
context->cache_offset = 0;
context->width = width;
/*
* Set BMP preamble.
*/
context->cache_length = GRAY_BMP_PREAMBLE_LENGTH;
memcpy(context->cache_buffer, gray_bmp_preamble,
GRAY_BMP_PREAMBLE_LENGTH);
buffer_p = (unsigned char *)context->cache_buffer + 2;
*buffer_p++ = file_size & 0xff;
*buffer_p++ = (file_size >> 8) & 0xff;
*buffer_p++ = (file_size >> 16) & 0xff;
*buffer_p++ = (file_size >> 24) & 0xff;
buffer_p = (unsigned char *)context->cache_buffer + 18;
*buffer_p++ = width & 0xff;
*buffer_p++ = (width >> 8) & 0xff;
*buffer_p++ = (width >> 16) & 0xff;
*buffer_p++ = (width >> 24) & 0xff;
*buffer_p++ = height & 0xff;
*buffer_p++ = (height >> 8) & 0xff;
*buffer_p++ = (height >> 16) & 0xff;
*buffer_p++ = (height >> 24) & 0xff;
buffer_p = (unsigned char *)context->cache_buffer + 34;
*buffer_p++ = data_size & 0xff;
*buffer_p++ = (data_size >> 8) & 0xff;
*buffer_p++ = (data_size >> 16) & 0xff;
*buffer_p++ = (data_size >> 24) & 0xff;
/*
* Seek graphic file.
*/
if (zio_lseek(context->zio, context->location, SEEK_SET) < 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
LOG(("out: eb_set_binary_gray_graphic() = %s",
eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
eb_reset_binary_context(book);
LOG(("out: eb_set_binary_gray_graphic() = %s",
eb_error_string(error_code)));
return error_code;
}
/*
* Set WAVE sound as the current binary data.
*/
EB_Error_Code
eb_set_binary_wave(EB_Book *book, const EB_Position *start_position,
const EB_Position *end_position)
{
EB_Error_Code error_code;
EB_Binary_Context *context;
off_t start_location;
off_t end_location;
char temporary_buffer[4];
LOG(("in: eb_set_binary_wave(book=%d, start_position={%d,%d}, \
end_position={%d,%d})",
(int)book->code, start_position->page, start_position->offset,
end_position->page, end_position->offset));
eb_reset_binary_context(book);
/*
* Current subbook must have been set.
*/
if (book->subbook_current == NULL) {
error_code = EB_ERR_NO_CUR_SUB;
goto failed;
}
/*
* Current subbook must have a sound file.
*/
if (zio_file(&book->subbook_current->sound_zio) < 0) {
error_code = EB_ERR_NO_SUCH_BINARY;
goto failed;
}
/*
* Set binary context.
*/
if (start_position->page <= 0 || start_position->offset < 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
if (end_position->page <= 0 || end_position->offset < 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
start_location = ((off_t) start_position->page - 1) * EB_SIZE_PAGE
+ start_position->offset;
end_location = ((off_t) end_position->page - 1) * EB_SIZE_PAGE
+ end_position->offset;
context = &book->binary_context;
context->code = EB_BINARY_WAVE;
context->zio = &book->subbook_current->sound_zio;
context->location = start_location;
if (start_location < end_location)
context->size = end_location - start_location + 1;
else {
error_code = EB_ERR_UNEXP_BINARY;
goto failed;
}
context->offset = 0;
/*
* Read 4bytes from the sound file to check whether the sound
* data contains a header part or not.
*
* If the read data is "fmt ", the wave data has a header part.
* Otherwise, we must read a header in another location.
*
* The wave data consists of:
*
* "RIFF" wave-size(4bytes) "WAVE" header-fragment(28bytes)
* data-part-size(4bytes) data
*
* wave-size = "WAVE" + header-fragment + data-part-size + data
* = 4 + 28 + 4 + data
* = 36 + data
* data-part-size = length(data)
*/
if (zio_lseek(context->zio, context->location, SEEK_SET) < 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
if (zio_read(context->zio, temporary_buffer, 4) != 4) {
error_code = EB_ERR_FAIL_READ_BINARY;
goto failed;
}
if (memcmp(temporary_buffer, "fmt ", 4) == 0) {
memcpy(context->cache_buffer + 12, temporary_buffer, 4);
if (zio_read(context->zio, context->cache_buffer + 16, 28) != 28) {
error_code = EB_ERR_FAIL_READ_BINARY;
goto failed;
}
if (context->size >= 32)
context->size -= 32;
else
context->size = 0;
} else {
if (zio_lseek(context->zio,
((off_t) book->subbook_current->sound.start_page - 1)
* EB_SIZE_PAGE + 32, SEEK_SET) < 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
if (zio_read(context->zio, context->cache_buffer + 12, 28) != 28) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
*(unsigned char *)(context->cache_buffer + 40)
= (context->size) & 0xff;
*(unsigned char *)(context->cache_buffer + 41)
= (context->size >> 8) & 0xff;
*(unsigned char *)(context->cache_buffer + 42)
= (context->size >> 16) & 0xff;
*(unsigned char *)(context->cache_buffer + 43)
= (context->size >> 24) & 0xff;
/*
* Seek sound file, again.
*/
if (zio_lseek(context->zio, context->location, SEEK_SET) < 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
}
context->cache_length = 44;
/*
* Read and compose a WAVE header.
*/
memcpy(context->cache_buffer, "RIFF", 4);
*(unsigned char *)(context->cache_buffer + 4)
= (context->size + 36) & 0xff;
*(unsigned char *)(context->cache_buffer + 5)
= ((context->size + 36) >> 8) & 0xff;
*(unsigned char *)(context->cache_buffer + 6)
= ((context->size + 36) >> 16) & 0xff;
*(unsigned char *)(context->cache_buffer + 7)
= ((context->size + 36) >> 24) & 0xff;
memcpy(context->cache_buffer + 8, "WAVE", 4);
LOG(("out: eb_set_binary_wave() = %s", eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
eb_reset_binary_context(book);
LOG(("out: eb_set_binary_wave() = %s", eb_error_string(error_code)));
return error_code;
}
/*
* Length of the color graphic header.
*/
#define EB_COLOR_GRAPHIC_HEADER_LENGTH 8
/*
* Set color graphic (BMP or JPEG) as the current binary data.
*/
EB_Error_Code
eb_set_binary_color_graphic(EB_Book *book, const EB_Position *position)
{
EB_Error_Code error_code;
EB_Binary_Context *context;
char buffer[EB_COLOR_GRAPHIC_HEADER_LENGTH];
LOG(("in: eb_set_binary_color_graphic(book=%d, position={%d,%d})",
(int)book->code, position->page, position->offset));
eb_reset_binary_context(book);
/*
* Current subbook must have been set.
*/
if (book->subbook_current == NULL) {
error_code = EB_ERR_NO_CUR_SUB;
goto failed;
}
/*
* Current subbook must have a graphic file.
*/
if (zio_file(&book->subbook_current->graphic_zio) < 0) {
error_code = EB_ERR_NO_SUCH_BINARY;
goto failed;
}
/*
* Set binary context.
*/
if (position->page <= 0 || position->offset < 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
context = &book->binary_context;
context->code = EB_BINARY_COLOR_GRAPHIC;
context->zio = &book->subbook_current->graphic_zio;
context->location = ((off_t) position->page - 1) * EB_SIZE_PAGE
+ position->offset;
context->offset = 0;
context->cache_length = 0;
context->cache_offset = 0;
/*
* Seek graphic file.
*/
if (zio_lseek(context->zio, context->location, SEEK_SET) < 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
/*
* Read header of the graphic data.
* Note that EB* JPEG file lacks the header.
*/
if (zio_read(context->zio, buffer, EB_COLOR_GRAPHIC_HEADER_LENGTH)
!= EB_COLOR_GRAPHIC_HEADER_LENGTH) {
error_code = EB_ERR_FAIL_READ_BINARY;
goto failed;
}
if (memcmp(buffer, "data", 4) == 0) {
context->size = eb_uint4_le(buffer + 4);
context->location += EB_COLOR_GRAPHIC_HEADER_LENGTH;
} else {
context->size = 0;
if (zio_lseek(context->zio, context->location, SEEK_SET) < 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
}
LOG(("out: eb_set_binary_color_graphic() = %s",
eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
eb_reset_binary_context(book);
LOG(("out: eb_set_binary_color_graphic() = %s",
eb_error_string(error_code)));
return error_code;
}
/*
* Set MPEG movie as the current binary data.
*/
EB_Error_Code
eb_set_binary_mpeg(EB_Book *book, const unsigned int *argv)
{
/*
* `movie_file_name' is base name, and `movie_path_name' is absolute
* path of the movie.
*/
char movie_file_name[EB_MAX_FILE_NAME_LENGTH + 1];
char movie_path_name[EB_MAX_PATH_LENGTH + 1];
EB_Error_Code error_code;
EB_Subbook *subbook;
Zio_Code zio_code;
LOG(("in: eb_set_binary_mpeg(book=%d)", (int)book->code));
eb_reset_binary_context(book);
/*
* Current subbook must have been set.
*/
subbook = book->subbook_current;
if (subbook == NULL) {
error_code = EB_ERR_NO_CUR_SUB;
goto failed;
}
/*
* Open the movie file and set binary context.
*/
if (eb_compose_movie_file_name(argv, movie_file_name) != EB_SUCCESS) {
error_code = EB_ERR_NO_SUCH_BINARY;
goto failed;
}
LOG(("aux: eb_set_binary_mpeg(): movie_file_name=%s", movie_file_name));
if (eb_find_file_name3(book->path, subbook->directory_name,
subbook->movie_directory_name, movie_file_name, movie_file_name)
!= EB_SUCCESS) {
error_code = EB_ERR_NO_SUCH_BINARY;
goto failed;
}
eb_compose_path_name3(book->path, subbook->directory_name,
subbook->movie_directory_name, movie_file_name, movie_path_name);
eb_path_name_zio_code(movie_path_name, ZIO_PLAIN, &zio_code);
if (zio_open(&subbook->movie_zio, movie_path_name, zio_code) < 0) {
subbook = NULL;
error_code = EB_ERR_FAIL_OPEN_BINARY;
goto failed;
}
book->binary_context.code = EB_BINARY_MPEG;
book->binary_context.zio = &book->subbook_current->movie_zio;
book->binary_context.location = 0;
book->binary_context.size = 0;
book->binary_context.offset = 0;
book->binary_context.cache_length = 0;
book->binary_context.cache_offset = 0;
LOG(("out: eb_set_binary_mpeg() = %s", eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
eb_reset_binary_context(book);
LOG(("out: eb_set_binary_mpeg() = %s", eb_error_string(error_code)));
return error_code;
}
/*
* Read binary data.
*/
EB_Error_Code
eb_read_binary(book, binary_max_length, binary, binary_length)
EB_Book *book;
size_t binary_max_length;
char *binary;
ssize_t *binary_length;
{
EB_Error_Code error_code;
LOG(("in: eb_read_binary(book=%d, binary_max_length=%ld)",
(int)book->code, (long)binary_max_length));
/*
* Current subbook must have been set.
*/
if (book->subbook_current == NULL) {
error_code = EB_ERR_NO_CUR_SUB;
goto failed;
}
/*
* Return immediately if `binary_max_length' is 0.
*/
*binary_length = 0;
switch (book->binary_context.code) {
case EB_BINARY_COLOR_GRAPHIC:
case EB_BINARY_MPEG:
error_code = eb_read_binary_generic(book, binary_max_length, binary,
binary_length);
break;
case EB_BINARY_WAVE:
error_code = eb_read_binary_wave(book, binary_max_length,
binary, binary_length);
break;
case EB_BINARY_MONO_GRAPHIC:
error_code = eb_read_binary_mono_graphic(book, binary_max_length,
binary, binary_length);
break;
case EB_BINARY_GRAY_GRAPHIC:
error_code = eb_read_binary_gray_graphic(book, binary_max_length,
binary, binary_length);
break;
default:
error_code = EB_ERR_NO_CUR_BINARY;
goto failed;
}
if (error_code != EB_SUCCESS)
goto failed;
LOG(("out: eb_read_binary(binary_length=%ld) = %s", (long)*binary_length,
eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
*binary_length = -1;
eb_reset_binary_context(book);
LOG(("out: eb_read_binary() = %s", eb_error_string(EB_SUCCESS)));
return error_code;
}
/*
* Read generic binary data.
* This function is used for reading JPEG or BMP picture, and data part
* of WAVE sound.
*/
static EB_Error_Code
eb_read_binary_generic(EB_Book *book, size_t binary_max_length,
char *binary, ssize_t *binary_length)
{
EB_Error_Code error_code;
EB_Binary_Context *context;
char *binary_p = binary;
size_t read_length = 0;
ssize_t read_result;
LOG(("in: eb_read_binary_generic(book=%d, binary_max_length=%ld)",
(int)book->code, (long)binary_max_length));
*binary_length = 0;
context = &book->binary_context;
/*
* Return immediately if `binary_max_length' is 0.
*/
if (binary_max_length == 0)
goto succeeded;
/*
* Read binary data if it is remained.
* If context->size is 0, the binary data size is unknown.
*/
if (0 < context->size && context->size <= context->offset)
goto succeeded;
if (context->size == 0)
read_length = binary_max_length - *binary_length;
else if (binary_max_length - *binary_length
< context->size - context->offset)
read_length = binary_max_length - *binary_length;
else
read_length = context->size - context->offset;
read_result = zio_read(context->zio, binary_p, read_length);
if ((0 < context->size && read_result != read_length) || read_result < 0) {
error_code = EB_ERR_FAIL_READ_BINARY;
goto failed;
}
*binary_length += read_result;
context->offset += read_result;
succeeded:
LOG(("out: eb_read_binary_generic(binary_length=%ld) = %s",
(long)*binary_length, eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
LOG(("out: eb_read_binary_generic() = %s", eb_error_string(error_code)));
return error_code;
}
/*
* Read WAVE sound data.
*/
static EB_Error_Code
eb_read_binary_wave(EB_Book *book, size_t binary_max_length, char *binary,
ssize_t *binary_length)
{
EB_Error_Code error_code;
EB_Binary_Context *context;
char *binary_p = binary;
size_t copy_length = 0;
LOG(("in: eb_read_binary_wave(book=%d, binary_max_length=%ld)",
(int)book->code, (long)binary_max_length));
*binary_length = 0;
context = &book->binary_context;
/*
* Return immediately if `binary_max_length' is 0.
*/
if (binary_max_length == 0)
goto succeeded;
/*
* Copy cached data (header part) to `binary' if exists.
*/
if (0 < context->cache_length) {
if (binary_max_length < context->cache_length - context->cache_offset)
copy_length = binary_max_length;
else
copy_length = context->cache_length - context->cache_offset;
memcpy(binary_p, context->cache_buffer + context->cache_offset,
copy_length);
binary_p += copy_length;
context->cache_offset += copy_length;
if (context->cache_length <= context->cache_offset)
context->cache_length = 0;
if (binary_max_length <= *binary_length)
goto succeeded;
}
error_code = eb_read_binary_generic(book, binary_max_length - copy_length,
binary_p, binary_length);
if (error_code !=EB_SUCCESS)
goto failed;
*binary_length += copy_length;
succeeded:
LOG(("out: eb_read_binary_wave(binary_length=%ld) = %s",
(long)*binary_length, eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
LOG(("out: eb_read_binary_wave() = %s", eb_error_string(error_code)));
return error_code;
}
/*
* Read monochrome graphic data.
* The function also convert the graphic data to BMP.
*/
static EB_Error_Code
eb_read_binary_mono_graphic(EB_Book *book, size_t binary_max_length,
char *binary, ssize_t *binary_length)
{
EB_Error_Code error_code;
EB_Binary_Context *context;
unsigned char *binary_p = (unsigned char *)binary;
size_t copy_length = 0;
size_t read_length = 0;
size_t line_length;
size_t line_pad_length;
LOG(("in: eb_read_binary_mono_graphic(book=%d, binary_max_length=%ld)",
(int)book->code, (long)binary_max_length));
*binary_length = 0;
context = &book->binary_context;
line_length = (context->width + 7) / 8;
if (context->width % 32 == 0)
line_pad_length = 0;
else if (context->width % 32 <= 8)
line_pad_length = 3;
else if (context->width % 32 <= 16)
line_pad_length = 2;
else if (context->width % 32 <= 24)
line_pad_length = 1;
else
line_pad_length = 0;
/*
* Return immediately if `binary_max_length' is 0.
*/
if (binary_max_length == 0)
goto succeeded;
for (;;) {
/*
* Copy cached data to `binary' if exists.
*/
if (0 < context->cache_length) {
if (binary_max_length - *binary_length
< context->cache_length - context->cache_offset)
copy_length = binary_max_length - *binary_length;
else
copy_length = context->cache_length - context->cache_offset;
memcpy(binary_p, context->cache_buffer + context->cache_offset,
copy_length);
binary_p += copy_length;
*binary_length += copy_length;
context->cache_offset += copy_length;
if (context->cache_length <= context->cache_offset)
context->cache_length = 0;
if (binary_max_length <= *binary_length)
goto succeeded;
}
/*
* Read binary data if it is remained.
* If padding is needed, read each line.
*/
read_length = line_length - context->offset % line_length;
if (context->size - context->offset < read_length)
read_length = context->size - context->offset;
if (binary_max_length - *binary_length < read_length)
read_length = binary_max_length - *binary_length;
if (read_length == 0)
goto succeeded;
/*
* Read binary data.
*/
if (context->offset != 0
&& context->offset % line_length == 0
&& zio_lseek(context->zio, (off_t) line_length * -2, SEEK_CUR)
< 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
if (zio_read(context->zio, (char *)binary_p, read_length)
!= read_length) {
error_code = EB_ERR_FAIL_READ_BINARY;
goto failed;
}
*binary_length += read_length;
context->offset += read_length;
binary_p += read_length;
/*
* Pad 0x00 to BMP if needed.
*/
if (context->offset % line_length == 0) {
if (0 < line_pad_length) {
if (binary_max_length - *binary_length < line_pad_length) {
memset(context->cache_buffer, 0, line_pad_length);
context->cache_length = line_pad_length;
context->cache_offset = 0;
} else {
memset(binary_p, 0, line_pad_length);
binary_p += line_pad_length;
*binary_length += line_pad_length;
}
}
}
}
succeeded:
LOG(("out: eb_read_binary_mono_graphic(binary_length=%ld) = %s",
(long)*binary_length, eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
LOG(("out: eb_read_binary_mono_graphic() = %s",
eb_error_string(error_code)));
return error_code;
}
/*
* Read gray scale graphic data.
* The function also convert the graphic data to BMP.
*/
static EB_Error_Code
eb_read_binary_gray_graphic(EB_Book *book, size_t binary_max_length,
char *binary, ssize_t *binary_length)
{
EB_Error_Code error_code;
EB_Binary_Context *context;
unsigned char *binary_p = (unsigned char *)binary;
size_t copy_length = 0;
size_t read_length = 0;
size_t line_length;
size_t line_pad_length;
LOG(("in: eb_read_binary_gray_graphic(book=%d, binary_max_length=%ld)",
(int)book->code, (long)binary_max_length));
*binary_length = 0;
context = &book->binary_context;
line_length = (context->width + 1) / 2;
if (context->width % 8 == 0)
line_pad_length = 0;
else if (context->width % 8 <= 2)
line_pad_length = 3;
else if (context->width % 8 <= 4)
line_pad_length = 2;
else if (context->width % 8 <= 6)
line_pad_length = 1;
else
line_pad_length = 0;
/*
* Return immediately if `binary_max_length' is 0.
*/
if (binary_max_length == 0)
goto succeeded;
for (;;) {
/*
* Copy cached data to `binary' if exists.
*/
if (0 < context->cache_length) {
if (binary_max_length - *binary_length
< context->cache_length - context->cache_offset)
copy_length = binary_max_length - *binary_length;
else
copy_length = context->cache_length - context->cache_offset;
memcpy(binary_p, context->cache_buffer + context->cache_offset,
copy_length);
binary_p += copy_length;
*binary_length += copy_length;
context->cache_offset += copy_length;
if (context->cache_length <= context->cache_offset)
context->cache_length = 0;
if (binary_max_length <= *binary_length)
goto succeeded;
}
/*
* Read binary data if it is remained.
* If padding is needed, read each line.
*/
read_length = line_length - context->offset % line_length;
if (context->size - context->offset < read_length)
read_length = context->size - context->offset;
if (binary_max_length - *binary_length < read_length)
read_length = binary_max_length - *binary_length;
if (read_length == 0)
goto succeeded;
/*
* Read binary data.
*/
if (context->offset != 0
&& context->offset % line_length == 0
&& zio_lseek(context->zio, (off_t) line_length * -2, SEEK_CUR)
< 0) {
error_code = EB_ERR_FAIL_SEEK_BINARY;
goto failed;
}
if (zio_read(context->zio, (char *)binary_p, read_length)
!= read_length) {
error_code = EB_ERR_FAIL_READ_BINARY;
goto failed;
}
*binary_length += read_length;
context->offset += read_length;
binary_p += read_length;
/*
* Pad 0x00 to BMP if needed.
*/
if (context->offset % line_length == 0) {
if (0 < line_pad_length) {
if (binary_max_length - *binary_length < line_pad_length) {
memset(context->cache_buffer, 0, line_pad_length);
context->cache_length = line_pad_length;
context->cache_offset = 0;
} else {
memset(binary_p, 0, line_pad_length);
binary_p += line_pad_length;
*binary_length += line_pad_length;
}
}
}
}
succeeded:
LOG(("out: eb_read_binary_gray_graphic(binary_length=%ld) = %s",
(long)*binary_length, eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
LOG(("out: eb_read_binary_gray_graphic() = %s",
eb_error_string(error_code)));
return error_code;
}
/*
* Unset current binary.
*/
void
eb_unset_binary(EB_Book *book)
{
LOG(("in: eb_unset_binary(book=%d)", (int)book->code));
eb_reset_binary_context(book);
LOG(("out: eb_unset_binary()"));
}