/* * 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 "build-post.h" #if defined( __APPLE__) || defined(__linux__) #include #else #include "win_dirent.h" #endif #ifndef _WIN32 /* * Canonicalize `path_name' (UNIX version). * Convert a path name to an absolute path. */ EB_Error_Code eb_canonicalize_path_name(char *path_name) { char cwd[EB_MAX_PATH_LENGTH + 1]; char temporary_path_name[EB_MAX_PATH_LENGTH + 1]; char *last_slash; if (*path_name != '/') { /* * `path_name' is an relative path. Convert to an absolute * path. */ if (getcwd(cwd, EB_MAX_PATH_LENGTH + 1) == NULL) return EB_ERR_FAIL_GETCWD; if (EB_MAX_PATH_LENGTH < strlen(cwd) + 1 + strlen(path_name)) return EB_ERR_TOO_LONG_FILE_NAME; if (strcmp(path_name, ".") == 0) { strcpy(path_name, cwd); } else if (strncmp(path_name, "./", 2) == 0) { sprintf(temporary_path_name, "%s/%s", cwd, path_name + 2); strcpy(path_name, temporary_path_name); } else { sprintf(temporary_path_name, "%s/%s", cwd, path_name); strcpy(path_name, temporary_path_name); } } /* * Unless `path_name' is "/", eliminate `/' in the tail of the * path name. */ last_slash = strrchr(path_name, '/'); if (last_slash != path_name && *(last_slash + 1) == '\0') *last_slash = '\0'; return EB_SUCCESS; } #else /* DOS_FILE_PATH */ /* * Canonicalize `path_name' (DOS version). * Convert a path name to an absolute path with drive letter unless * that is an UNC path. * * Original version by KSK Jan/30/1998. * Current version by Motoyuki Kasahara. */ EB_Error_Code eb_canonicalize_path_name(char *path_name) { char cwd[EB_MAX_PATH_LENGTH + 1]; char temporary_path_name[EB_MAX_PATH_LENGTH + 1]; char *slash; char *last_backslash; /* * Replace `/' with `\\'. */ slash = path_name; for (;;) { slash = strchr(slash, '/'); if (slash == NULL) break; *slash++ = '\\'; } if (*path_name == '\\' && *(path_name + 1) == '\\') { /* * `path_name' is UNC path. Nothing to be done. */ } else if (ASCII_ISALPHA(*path_name) && *(path_name + 1) == ':') { /* * `path_name' has a drive letter. * Nothing to be done if it is an absolute path. */ if (*(path_name + 2) != '\\') { /* * `path_name' is a relative path. * Covert the path name to an absolute path. */ if (getdcwd(ASCII_TOUPPER(*path_name) - 'A' + 1, cwd, EB_MAX_PATH_LENGTH + 1) == NULL) { return EB_ERR_FAIL_GETCWD; } if (EB_MAX_PATH_LENGTH < strlen(cwd) + 1 + strlen(path_name + 2)) return EB_ERR_TOO_LONG_FILE_NAME; sprintf(temporary_path_name, "%s\\%s", cwd, path_name + 2); strcpy(path_name, temporary_path_name); } } else if (*path_name == '\\') { /* * `path_name' has no drive letter and is an absolute path. * Add a drive letter to the path name. */ if (getcwd(cwd, EB_MAX_PATH_LENGTH + 1) == NULL) return EB_ERR_FAIL_GETCWD; cwd[1] = '\0'; if (EB_MAX_PATH_LENGTH < strlen(cwd) + 1 + strlen(path_name)) return EB_ERR_TOO_LONG_FILE_NAME; sprintf(temporary_path_name, "%s:%s", cwd, path_name); strcpy(path_name, temporary_path_name); } else { /* * `path_name' has no drive letter and is a relative path. * Add a drive letter and convert it to an absolute path. */ if (getcwd(cwd, EB_MAX_PATH_LENGTH + 1) == NULL) return EB_ERR_FAIL_GETCWD; if (EB_MAX_PATH_LENGTH < strlen(cwd) + 1 + strlen(path_name)) return EB_ERR_TOO_LONG_FILE_NAME; sprintf(temporary_path_name, "%s\\%s", cwd, path_name); strcpy(path_name, temporary_path_name); } /* * Now `path_name' is `X:\...' or `\\...'. * Unless it is "X:\", eliminate `\' in the tail of the path name. */ last_backslash = strrchr(path_name, '\\'); if (ASCII_ISALPHA(*path_name)) { if (last_backslash != path_name + 2 && *(last_backslash + 1) == '\0') *last_backslash = '\0'; } else { if (last_backslash != path_name + 1 && *(last_backslash + 1) == '\0') *last_backslash = '\0'; } return EB_SUCCESS; } #endif /* DOS_FILE_PATH */ /* * Canonicalize file name. * - Suffix including dot is removed * - Version including semicolon is removed. * - Letters are converted to upper case. * * We minght fail to load a file after we fix the file name. * If loading the file is tried again, we need the original file name, * not fixed file name. Therefore, we get orignal file name from fixed * file name using this function. */ void eb_canonicalize_file_name(char *file_name) { char *p; for (p = file_name; *p != '\0' && *p != '.' && *p != ';'; p++) *p = ASCII_TOUPPER(*p); *p = '\0'; } /* * Rewrite `directory_name' to a real directory name in the `path' directory. * * If a directory matched to `directory_name' exists, then EB_SUCCESS is * returned, and `directory_name' is rewritten to that name. Otherwise * EB_ERR_BAD_DIR_NAME is returned. */ EB_Error_Code eb_fix_directory_name(const char *path, char *directory_name) { struct dirent *entry; DIR *dir; /* * Open the directory `path'. */ dir = opendir(path); if (dir == NULL) goto failed; for (;;) { /* * Read the directory entry. */ entry = readdir(dir); if (entry == NULL) goto failed; if (strcasecmp(entry->d_name, directory_name) == 0) break; } strcpy(directory_name, entry->d_name); closedir(dir); return EB_SUCCESS; /* * An error occurs... */ failed: if (dir != NULL) closedir(dir); return EB_ERR_BAD_DIR_NAME; } /* * Rewrite `sub_directory_name' to a real sub directory name in the * `path/directory_name' directory. * * If a directory matched to `sub_directory_name' exists, then EB_SUCCESS * is returned, and `directory_name' is rewritten to that name. Otherwise * EB_ERR_BAD_FILE_NAME is returned. */ EB_Error_Code eb_fix_directory_name2(const char *path, const char *directory_name, char *sub_directory_name) { char sub_path_name[EB_MAX_PATH_LENGTH + 1]; eb_compose_path_name(path, directory_name, sub_path_name); return eb_fix_directory_name(sub_path_name, sub_directory_name); } /* * Fix suffix of `path_name'. * * If `suffix' is an empty string, delete suffix from `path_name'. * Otherwise, add `suffix' to `path_name'. */ void eb_fix_path_name_suffix(char *path_name, const char *suffix) { char *base_name; char *dot; char *semicolon; #ifndef _WIN32 base_name = strrchr(path_name, '/'); #else if (is_ebnet_url(path_name)) base_name = strrchr(path_name, '/'); else base_name = strrchr(path_name, '\\'); #endif if (base_name == NULL) base_name = path_name; else base_name++; dot = strchr(base_name, '.'); semicolon = strchr(base_name, ';'); if (*suffix == '\0') { /* * Remove `.xxx' from `fixed_file_name': * foo.xxx --> foo * foo.xxx;1 --> foo;1 * foo. --> foo. (unchanged) * foo.;1 --> foo.;1 (unchanged) */ if (dot != NULL && *(dot + 1) != '\0' && *(dot + 1) != ';') { if (semicolon != NULL) sprintf(dot, ";%c", *(semicolon + 1)); else *dot = '\0'; } } else { /* * Add `.xxx' to `fixed_file_name': * foo --> foo.xxx * foo. --> foo.xxx * foo;1 --> foo.xxx;1 * foo.;1 --> foo.xxx;1 * foo.xxx --> foo.xxx (unchanged) */ if (dot != NULL) { if (semicolon != NULL) sprintf(dot, "%s;%c", suffix, *(semicolon + 1)); else strcpy(dot, suffix); } else { if (semicolon != NULL) sprintf(semicolon, "%s;%c", suffix, *(semicolon + 1)); else strcat(base_name, suffix); } } } #define FOUND_NONE 0 #define FOUND_EBZ 1 #define FOUND_BASENAME 2 #define FOUND_ORG 3 /* * Rewrite `found_file_name' to a real file name in the `path_name' * directory. * * If a file matched to `target_file_name' exists, then EB_SUCCESS * is returned, and `found_file_name' is rewritten to that name. * Otherwise EB_ERR_BAD_FILE_NAME is returned. * * Note that `target_file_name' must not contain `.' or excceed * EB_MAX_DIRECTORY_NAME_LENGTH characters. */ EB_Error_Code eb_find_file_name(const char *path_name, const char *target_file_name, char *found_file_name) { char ebz_target_file_name[EB_MAX_FILE_NAME_LENGTH + 1]; char org_target_file_name[EB_MAX_FILE_NAME_LENGTH + 1]; char candidate_file_name[EB_MAX_FILE_NAME_LENGTH + 1]; DIR *dir; struct dirent *entry; size_t d_namlen; int found = FOUND_NONE; strcpy(ebz_target_file_name, target_file_name); strcat(ebz_target_file_name, ".ebz"); strcpy(org_target_file_name, target_file_name); strcat(org_target_file_name, ".org"); candidate_file_name[0] = '\0'; /* * Open the directory `path_name'. */ dir = opendir(path_name); if (dir == NULL) goto failed; for (;;) { /* * Read the directory entry. */ entry = readdir(dir); if (entry == NULL) break; /* * Compare the given file names and the current entry name. * We consider they are matched when one of the followings * is true: * * == * +";1' == * +"." == * +".;1" == * +".ebz" == * +".ebz;1" == * +".org" == * +".org;1" == * * All the comparisons are done without case sensitivity. * We support version number ";1" only. */ d_namlen = strlen(entry->d_name); if (2 < d_namlen && *(entry->d_name + d_namlen - 2) == ';' && ASCII_ISDIGIT(*(entry->d_name + d_namlen - 1))) { d_namlen -= 2; } if (1 < d_namlen && *(entry->d_name + d_namlen - 1) == '.') d_namlen--; if (strcasecmp(entry->d_name, ebz_target_file_name) == 0 && *(ebz_target_file_name + d_namlen) == '\0' && found < FOUND_EBZ) { strcpy(candidate_file_name, entry->d_name); found = FOUND_EBZ; } if (strncasecmp(entry->d_name, target_file_name, d_namlen) == 0 && *(target_file_name + d_namlen) == '\0' && found < FOUND_BASENAME) { strcpy(candidate_file_name, entry->d_name); found = FOUND_BASENAME; } if (strcasecmp(entry->d_name, org_target_file_name) == 0 && *(org_target_file_name + d_namlen) == '\0' && found < FOUND_ORG) { strcpy(candidate_file_name, entry->d_name); found = FOUND_ORG; break; } } if (found == FOUND_NONE) goto failed; closedir(dir); strcpy(found_file_name, candidate_file_name); return EB_SUCCESS; /* * An error occurs... */ failed: if (dir != NULL) closedir(dir); return EB_ERR_BAD_FILE_NAME; } /* * Rewrite `file_name' to a real file name in the directory * `path_name/sub_directory_name'. * * If a file matched to `file_name' exists, then EB_SUCCESS is returned, * and `file_name' is rewritten to that name. Otherwise EB_ERR_BAD_FILE_NAME * is returned. */ EB_Error_Code eb_find_file_name2(const char *path_name, const char *sub_directory_name, const char *target_file_name, char *found_file_name) { char sub_path_name[EB_MAX_PATH_LENGTH + 1]; eb_compose_path_name(path_name, sub_directory_name, sub_path_name); return eb_find_file_name(sub_path_name, target_file_name, found_file_name); } EB_Error_Code eb_find_file_name3(const char *path_name, const char *sub_directory_name, const char *sub2_directory_name, const char *target_file_name, char *found_file_name) { char sub2_path_name[EB_MAX_PATH_LENGTH + 1]; eb_compose_path_name2(path_name, sub_directory_name, sub2_directory_name, sub2_path_name); return eb_find_file_name(sub2_path_name, target_file_name, found_file_name); } /* * Compose a file name * `path_name/file_name' * and copy it into `composed_path_name'. */ void eb_compose_path_name(const char *path_name, const char *file_name, char *composed_path_name) { #ifndef DOS_FILE_PATH if (strcmp(path_name, "/") == 0) sprintf(composed_path_name, "%s%s", path_name, file_name); else sprintf(composed_path_name, "%s/%s", path_name, file_name); #else if (is_ebnet_url(path_name)) sprintf(composed_path_name, "%s/%s", path_name, file_name); else if (ASCII_ISALPHA(*path_name) && strcmp(path_name + 1, ":\\") == 0) sprintf(composed_path_name, "%s%s", path_name, file_name); else sprintf(composed_path_name, "%s\\%s", path_name, file_name); #endif } /* * Compose a file name * `path_name/sub_directory/file_name' * and copy it into `composed_path_name'. */ void eb_compose_path_name2(const char *path_name, const char *sub_directory_name, const char *file_name, char *composed_path_name) { #ifndef _WIN32 if (strcmp(path_name, "/") == 0) { sprintf(composed_path_name, "%s%s/%s", path_name, sub_directory_name, file_name); } else { sprintf(composed_path_name, "%s/%s/%s", path_name, sub_directory_name, file_name); } #else if (is_ebnet_url(path_name)) { sprintf(composed_path_name, "%s/%s/%s", path_name, sub_directory_name, file_name); } else if (ASCII_ISALPHA(*path_name) && strcmp(path_name + 1, ":\\") == 0) { sprintf(composed_path_name, "%s%s\\%s", path_name, sub_directory_name, file_name); } else { sprintf(composed_path_name, "%s\\%s\\%s", path_name, sub_directory_name, file_name); } #endif } /* * Compose a file name * `path_name/sub_directory/sub2_directory/file_name' * and copy it into `composed_path_name'. */ void eb_compose_path_name3(const char *path_name, const char *sub_directory_name, const char *sub2_directory_name, const char *file_name, char *composed_path_name) { #ifndef DOS_FILE_PATH if (strcmp(path_name, "/") == 0) { sprintf(composed_path_name, "%s%s/%s/%s", path_name, sub_directory_name, sub2_directory_name, file_name); } else { sprintf(composed_path_name, "%s/%s/%s/%s", path_name, sub_directory_name, sub2_directory_name, file_name); } #else if (is_ebnet_url(path_name)) { sprintf(composed_path_name, "%s/%s/%s/%s", path_name, sub_directory_name, sub2_directory_name, file_name); } else if (ASCII_ISALPHA(*path_name) && strcmp(path_name + 1, ":\\") == 0) { sprintf(composed_path_name, "%s%s\\%s\\%s", path_name, sub_directory_name, sub2_directory_name, file_name); } else { sprintf(composed_path_name, "%s\\%s\\%s\\%s", path_name, sub_directory_name, sub2_directory_name, file_name); } #endif } /* * Compose movie file name from argv[], and copy the result to * `composed_file_name'. Note that upper letters are converted to lower * letters. * * If a file `composed_path_name' exists, then EB_SUCCESS is returned. * Otherwise EB_ERR_BAD_FILE_NAME is returned. */ EB_Error_Code eb_compose_movie_file_name(const unsigned int *argv, char *composed_file_name) { unsigned short jis_characters[EB_MAX_DIRECTORY_NAME_LENGTH]; const unsigned int *arg_p; char *composed_p; unsigned short c; int i; /* * Initialize `jis_characters[]'. */ for (i = 0, arg_p = argv; i + 1 < EB_MAX_DIRECTORY_NAME_LENGTH; i += 2, arg_p++) { jis_characters[i] = (*arg_p >> 16) & 0xffff; jis_characters[i + 1] = (*arg_p) & 0xffff; } if (i < EB_MAX_DIRECTORY_NAME_LENGTH) jis_characters[i] = (*arg_p >> 16) & 0xffff; /* * Compose file name. */ for (i = 0, composed_p = composed_file_name; i < EB_MAX_DIRECTORY_NAME_LENGTH; i++, composed_p++) { c = jis_characters[i]; if (c == 0x2121 || c == 0x0000) break; if ((0x2330 <= c && c <= 0x2339) || (0x2361 <= c && c <= 0x237a)) *composed_p = c & 0xff; else if (0x2341 <= c && c <= 0x235a) *composed_p = (c | 0x20) & 0xff; else return EB_ERR_BAD_FILE_NAME; } *composed_p = '\0'; return EB_SUCCESS; } /* * This function is similar to eb_compose_movie_file_name(), but it * returns full path of the movie file name. */ EB_Error_Code eb_compose_movie_path_name(EB_Book *book, const unsigned int *argv, char *composed_path_name) { EB_Subbook *subbook; EB_Error_Code error_code; char composed_file_name[EB_MAX_FILE_NAME_LENGTH + 1]; /* * Lock the book. */ eb_lock(&book->lock); LOG(("in: eb_compose_movie_path_name(book=%d, argv=%x)", (int)book->code, argv)); /* * Current subbook must have been set. */ if (book->subbook_current == NULL) { error_code = EB_ERR_NO_CUR_SUB; goto failed; } subbook = book->subbook_current; error_code = eb_compose_movie_file_name(argv, composed_file_name); if (error_code != EB_SUCCESS) goto failed; error_code = eb_find_file_name3(book->path, subbook->directory_name, subbook->movie_directory_name, composed_file_name, composed_file_name); if (error_code != EB_SUCCESS) goto failed; eb_compose_path_name3(book->path, subbook->directory_name, subbook->movie_directory_name, composed_file_name, composed_path_name); LOG(("out: eb_compse_movie_path_name() = %s", eb_error_string(EB_SUCCESS))); eb_unlock(&book->lock); return EB_SUCCESS; /* * An error occurs... */ failed: LOG(("out: eb_compse_movie_path_name() = %s", eb_error_string(error_code))); eb_unlock(&book->lock); return error_code; } /* * Decompose movie file name into argv[]. This is the reverse of * eb_compose_movie_file_name(). Note that lower letters are converted * to upper letters. * * EB_SUCCESS is returned upon success, EB_ERR_BAD_FILE_NAME otherwise. */ EB_Error_Code eb_decompose_movie_file_name(unsigned int *argv, const char *composed_file_name) { unsigned short jis_characters[EB_MAX_DIRECTORY_NAME_LENGTH]; unsigned int *arg_p; const char *composed_p; int i; /* * Initialize `jis_characters[]'. */ for (i = 0; i < EB_MAX_DIRECTORY_NAME_LENGTH; i++) jis_characters[i] = 0x0000; /* * Set jis_characters[]. */ for (i = 0, composed_p = composed_file_name; i < EB_MAX_DIRECTORY_NAME_LENGTH && *composed_p != '\0'; i++, composed_p++) { if ('0' <= *composed_p && *composed_p <= '9') jis_characters[i] = 0x2330 + (*composed_p - '0'); else if ('A' <= *composed_p && *composed_p <= 'Z') jis_characters[i] = 0x2341 + (*composed_p - 'A'); else if ('a' <= *composed_p && *composed_p <= 'z') jis_characters[i] = 0x2341 + (*composed_p - 'a'); else return EB_ERR_BAD_FILE_NAME; } if (*composed_p != '\0') return EB_ERR_BAD_FILE_NAME; /* * Decompose file name. */ for (i = 0, arg_p = argv; i + 1 < EB_MAX_DIRECTORY_NAME_LENGTH; i += 2, arg_p++) { *arg_p = (jis_characters[i] << 16) | jis_characters[i + 1]; } if (i < EB_MAX_DIRECTORY_NAME_LENGTH) { *arg_p++ = jis_characters[i] << 16; } *arg_p = '\0'; return EB_SUCCESS; } void eb_path_name_zio_code(const char *path_name, Zio_Code default_zio_code, Zio_Code *zio_code) { const char *base_name; const char *dot; #ifndef _WIN32 base_name = strrchr(path_name, '/'); #else if (is_ebnet_url(path_name)) base_name = strrchr(path_name, '/'); else base_name = strrchr(path_name, '\\'); #endif if (base_name != NULL) base_name++; else base_name = path_name; dot = strchr(base_name, '.'); if (dot != NULL && strncasecmp(dot, ".ebz", 4) == 0) *zio_code = ZIO_EBZIP1; else if (dot != NULL && strncasecmp(dot, ".org", 4) == 0) *zio_code = ZIO_PLAIN; else *zio_code = default_zio_code; }