/* * 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 "appendix.h" #include "build-post.h" /* * Appendix ID counter. */ static EB_Book_Code appendix_counter = 0; /* * Mutex for `appendix_counter'. */ #ifdef ENABLE_PTHREAD static pthread_mutex_t appendix_counter_mutex = PTHREAD_MUTEX_INITIALIZER; #endif /* * Unexported functions. */ static EB_Error_Code eb_load_appendix_catalog(EB_Appendix *appendix); /* * Initialize alternation text cache in `appendix'. */ void eb_initialize_alt_caches(EB_Appendix *appendix) { EB_Alternation_Cache *p; int i; LOG(("in: eb_initialize_alt_caches(appendix=%d)", (int)appendix->code)); for (i = 0, p = appendix->narrow_cache; i < EB_MAX_ALTERNATION_CACHE; i++, p++) p->character_number = -1; for (i = 0, p = appendix->wide_cache; i < EB_MAX_ALTERNATION_CACHE; i++, p++) p->character_number = -1; LOG(("out: eb_initialize_alt_caches()")); } /* * Finalize alternation text cache in `appendix'. */ void eb_finalize_alt_caches(EB_Appendix *appendix) { LOG(("in+out: eb_finalize_alt_caches(appendix=%d)", (int)appendix->code)); /* nothing to be done */ } /* * Initialize `appendix'. */ void eb_initialize_appendix(EB_Appendix *appendix) { LOG(("in: eb_initialize_appendix()")); appendix->code = EB_BOOK_NONE; appendix->path = NULL; appendix->path_length = 0; appendix->disc_code = EB_DISC_INVALID; appendix->subbook_count = 0; appendix->subbooks = NULL; appendix->subbook_current = NULL; eb_initialize_lock(&appendix->lock); eb_initialize_alt_caches(appendix); LOG(("out: eb_initialize_appendix()")); } /* * Finalize `appendix'. */ void eb_finalize_appendix(EB_Appendix *appendix) { LOG(("in: eb_finalize_appendix(appendix=%d)", (int)appendix->code)); appendix->code = EB_BOOK_NONE; if (appendix->path != NULL) { free(appendix->path); appendix->path = NULL; } appendix->path_length = 0; appendix->disc_code = EB_DISC_INVALID; if (appendix->subbooks != NULL) { eb_finalize_appendix_subbooks(appendix); free(appendix->subbooks); appendix->subbooks = NULL; appendix->subbook_count = 0; } appendix->subbook_current = NULL; eb_finalize_lock(&appendix->lock); eb_finalize_alt_caches(appendix); LOG(("out: eb_finalize_appendix()")); } /* * Bind `appendix' to `path'. */ EB_Error_Code eb_bind_appendix(EB_Appendix *appendix, const char *path) { EB_Error_Code error_code; char temporary_path[EB_MAX_PATH_LENGTH + 1]; int is_ebnet; eb_lock(&appendix->lock); LOG(("in: eb_bind_appendix(path=%s)", path)); /* * Reset structure members in the appendix. */ if (appendix->path != NULL) { eb_finalize_appendix(appendix); eb_initialize_appendix(appendix); } /* * Assign a book code. */ pthread_mutex_lock(&appendix_counter_mutex); appendix->code = appendix_counter++; pthread_mutex_unlock(&appendix_counter_mutex); /* * Check whether `path' is URL. */ is_ebnet = is_ebnet_url(path); if (is_ebnet) { error_code = EB_ERR_EBNET_UNSUPPORTED; goto failed; } /* * Set path of the appendix. * The length of the file name "path/subdir/subsubdir/file.;1" must * be EB_MAX_PATH_LENGTH maximum. */ if (EB_MAX_PATH_LENGTH < strlen(path)) { error_code = EB_ERR_TOO_LONG_FILE_NAME; goto failed; } strcpy(temporary_path, path); error_code = eb_canonicalize_path_name(temporary_path); if (error_code != EB_SUCCESS) goto failed; appendix->path_length = strlen(temporary_path); if (EB_MAX_PATH_LENGTH < appendix->path_length + 1 + EB_MAX_RELATIVE_PATH_LENGTH) { error_code = EB_ERR_TOO_LONG_FILE_NAME; goto failed; } appendix->path = (char *)malloc(appendix->path_length + 1); if (appendix->path == NULL) { error_code = EB_ERR_MEMORY_EXHAUSTED; goto failed; } strcpy(appendix->path, temporary_path); /* * Read information from the catalog file. */ error_code = eb_load_appendix_catalog(appendix); if (error_code != EB_SUCCESS) goto failed; LOG(("out: eb_bind_appendix(appendix=%d) = %s", (int)appendix->code, eb_error_string(EB_SUCCESS))); eb_unlock(&appendix->lock); return EB_SUCCESS; /* * An error occurs... */ failed: eb_finalize_appendix(appendix); LOG(("out: eb_bind_appendix() = %s", eb_error_string(error_code))); eb_unlock(&appendix->lock); return error_code; } /* * Read information from the `CATALOG(S)' file in `appendix'. * Return EB_SUCCESS, if it succeeds, error-code ohtherwise. */ static EB_Error_Code eb_load_appendix_catalog(EB_Appendix *appendix) { EB_Error_Code error_code; char buffer[EB_SIZE_PAGE]; char catalog_file_name[EB_MAX_FILE_NAME_LENGTH + 1]; char catalog_path_name[EB_MAX_PATH_LENGTH + 1]; char *space; EB_Appendix_Subbook *subbook; size_t catalog_size; size_t title_size; Zio zio; Zio_Code zio_code; int i; LOG(("in: eb_load_appendix_catalog(appendix=%d)", (int)appendix->code)); zio_initialize(&zio); /* * Find a catalog file. */ if (eb_find_file_name(appendix->path, "catalog", catalog_file_name) == EB_SUCCESS) { appendix->disc_code = EB_DISC_EB; catalog_size = EB_SIZE_EB_CATALOG; title_size = EB_MAX_EB_TITLE_LENGTH; } else if (eb_find_file_name(appendix->path, "catalogs", catalog_file_name) == EB_SUCCESS) { appendix->disc_code = EB_DISC_EPWING; catalog_size = EB_SIZE_EPWING_CATALOG; title_size = EB_MAX_EPWING_TITLE_LENGTH; } else { error_code = EB_ERR_FAIL_OPEN_CATAPP; goto failed; } eb_compose_path_name(appendix->path, catalog_file_name, catalog_path_name); eb_path_name_zio_code(catalog_path_name, ZIO_PLAIN, &zio_code); /* * Open the catalog file. */ if (zio_open(&zio, catalog_path_name, zio_code) < 0) { error_code = EB_ERR_FAIL_OPEN_CATAPP; goto failed; } /* * Get the number of subbooks in the appendix. */ if (zio_read(&zio, buffer, 16) != 16) { error_code = EB_ERR_FAIL_READ_CATAPP; goto failed; } appendix->subbook_count = eb_uint2(buffer); if (EB_MAX_SUBBOOKS < appendix->subbook_count) appendix->subbook_count = EB_MAX_SUBBOOKS; if (appendix->subbook_count == 0) { error_code = EB_ERR_UNEXP_CATAPP; goto failed; } /* * Allocate memories for subbook entries. */ appendix->subbooks = (EB_Appendix_Subbook *) malloc(sizeof(EB_Appendix_Subbook) * appendix->subbook_count); if (appendix->subbooks == NULL) { error_code = EB_ERR_MEMORY_EXHAUSTED; goto failed; } eb_initialize_appendix_subbooks(appendix); /* * Read subbook information. */ for (i = 0, subbook = appendix->subbooks; i < appendix->subbook_count; i++, subbook++) { /* * Read data from the catalog file. */ if (zio_read(&zio, buffer, catalog_size) != catalog_size) { error_code = EB_ERR_FAIL_READ_CAT; goto failed; } /* * Set a directory name of the subbook. */ strncpy(subbook->directory_name, buffer + 2 + title_size, EB_MAX_DIRECTORY_NAME_LENGTH); subbook->directory_name[EB_MAX_DIRECTORY_NAME_LENGTH] = '\0'; space = strchr(subbook->directory_name, ' '); if (space != NULL) *space = '\0'; eb_fix_directory_name(appendix->path, subbook->directory_name); } /* * Close the catalog file. */ zio_close(&zio); zio_finalize(&zio); LOG(("out: eb_load_appendix_catalog() = %s", eb_error_string(EB_SUCCESS))); return EB_SUCCESS; /* * An error occurs... */ failed: zio_close(&zio); zio_finalize(&zio); if (appendix->subbooks != NULL) { free(appendix->subbooks); appendix->subbooks = NULL; } LOG(("out: eb_load_appendix_catalog() = %s", eb_error_string(error_code))); return error_code; } /* * Examine whether `appendix' is bound or not. */ int eb_is_appendix_bound(EB_Appendix *appendix) { int is_bound; eb_lock(&appendix->lock); LOG(("in: eb_is_appendix_bound(appendix=%d)", (int)appendix->code)); is_bound = (appendix->path != NULL); LOG(("out: eb_is_appendix_bound() = %d", is_bound)); eb_unlock(&appendix->lock); return is_bound; } /* * Get the bound path of `appendix'. */ EB_Error_Code eb_appendix_path(EB_Appendix *appendix, char *path) { EB_Error_Code error_code; eb_lock(&appendix->lock); LOG(("in: eb_appendix_path(appendix=%d)", (int)appendix->code)); /* * Check for the current status. */ if (appendix->path == NULL) { error_code = EB_ERR_UNBOUND_APP; goto failed; } /* * Copy the path to `path'. */ strcpy(path, appendix->path); LOG(("out: eb_appendix_path(path=%s) = %s", path, eb_error_string(EB_SUCCESS))); eb_unlock(&appendix->lock); return EB_SUCCESS; /* * An error occurs... */ failed: *path = '\0'; LOG(("out: eb_appendix_path() = %s", eb_error_string(error_code))); eb_unlock(&appendix->lock); return error_code; }