/*
 * 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"
#ifdef ENABLE_EBNET
#include "ebnet.h"
#endif
#include "build-post.h"

#if defined(DOS_FILE_PATH) && defined(HAVE_MBSTRING_H)
/* a path may contain double-byte chars in SJIS. */
#include <mbstring.h>
#define strchr    _mbschr
#define strrchr    _mbsrchr
#endif


#ifndef DOS_FILE_PATH

/*
 * 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;

#ifdef ENABLE_EBNET
  if (is_ebnet_url(path))
    return ebnet_fix_directory_name(path, directory_name);
#endif

  /*
   * 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 DOS_FILE_PATH
  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;

#ifdef ENABLE_EBNET
  if (is_ebnet_url(path_name)) {
    return ebnet_find_file_name(path_name, target_file_name,
      found_file_name);
  }
#endif

  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:
     *
     *   <target name>      == <entry name>
     *   <target name>+";1'   == <entry name>
     *   <target name>+"."    == <entry name>
     *   <target name>+".;1"  == <entry name>
     *   <target name>+".ebz"   == <entry name>
     *   <target name>+".ebz;1" == <entry name>
     *   <target name>+".org"   == <entry name>
     *   <target name>+".org;1" == <entry name>
     *
     * 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 DOS_FILE_PATH
  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 DOS_FILE_PATH
  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;
}
