static int task_database_iterate(
      db_handle_t *_db,
      database_state_handle_t *db_state,
      database_info_handle_t *db)
{
   const char *name = database_info_get_current_element_name(db);

   if (!name)
      return 0;

   if (database_info_get_type(db) == DATABASE_TYPE_ITERATE)
      if (path_contains_compressed_file(name))
         database_info_set_type(db, DATABASE_TYPE_ITERATE_ARCHIVE);

   switch (database_info_get_type(db))
   {
      case DATABASE_TYPE_ITERATE:
         return task_database_iterate_playlist(db_state, db, name);
      case DATABASE_TYPE_ITERATE_ARCHIVE:
         return task_database_iterate_playlist_archive(_db, db_state, db, name);
      case DATABASE_TYPE_ITERATE_LUTRO:
         return task_database_iterate_playlist_lutro(_db, db_state, db, name);
      case DATABASE_TYPE_SERIAL_LOOKUP:
         return task_database_iterate_serial_lookup(_db, db_state, db, name);
      case DATABASE_TYPE_CRC_LOOKUP:
         return task_database_iterate_crc_lookup(_db, db_state, db, name, NULL);
      case DATABASE_TYPE_NONE:
      default:
         break;
   }

   return 0;
}
Example #2
0
static bool content_file_init_extract(
      struct string_list *content,
      content_information_ctx_t *content_ctx,
      const struct retro_subsystem_info *special,
      union string_list_elem_attr *attr,
      char **error_string
      )
{
   unsigned i;

   for (i = 0; i < content->size; i++)
   {
      char temp_content[PATH_MAX_LENGTH];
      char new_path[PATH_MAX_LENGTH];
      bool block_extract                 = content->elems[i].attr.i & 1;
      const char *path                   = content->elems[i].data;
      const char *valid_ext              = special ?
                                           special->roms[i].valid_extensions :
                                           content_ctx->valid_extensions;
      bool contains_compressed           = path_contains_compressed_file(path);

      /* Block extract check. */
      if (block_extract)
         continue;

      /* just use the first file in the archive */
      if (!contains_compressed && !path_is_compressed_file(path))
         continue;

      temp_content[0] = new_path[0] = '\0';

      strlcpy(temp_content, path, sizeof(temp_content));

      if (!valid_ext || !file_archive_extract_file(
               temp_content,
               sizeof(temp_content),
               valid_ext,
               !string_is_empty(content_ctx->directory_cache) ?
               content_ctx->directory_cache : NULL,
               new_path,
               sizeof(new_path)))
      {
         char str[1024];

         snprintf(str, sizeof(str), "%s: %s.\n",
               msg_hash_to_str(
                  MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE),
               temp_content);
         return false;
      }

      string_list_set(content, i, new_path);

      if (!string_list_append(content_ctx->temporary_content,
               new_path, *attr))
         return false;
   }

   return true;
}
static int database_info_list_iterate_end_no_match(
      database_info_handle_t *db,
      database_state_handle_t *db_state,
      const char *path)
{
   /* Reached end of database list,
    * CRC match probably didn't succeed. */

   /* If this was a compressed file and no match in the database
    * list was found then expand the search list to include the
    * archive's contents. */
   if (path_is_compressed_file(path) && !path_contains_compressed_file(path))
   {
      struct string_list *archive_list =
         file_archive_get_file_list(path, NULL);

      if (archive_list && archive_list->size > 0)
      {
         unsigned i;

         for (i = 0; i < archive_list->size; i++)
         {
            char *new_path   = (char*)malloc(
               PATH_MAX_LENGTH * sizeof(char));
            size_t path_size = PATH_MAX_LENGTH * sizeof(char);
            size_t path_len  = strlen(path);

            new_path[0] = '\0';

            strlcpy(new_path, path, path_size);

            if (path_len + strlen(archive_list->elems[i].data)
                     + 1 < PATH_MAX_LENGTH)
            {
               new_path[path_len] = '#';
               strlcpy(new_path + path_len + 1,
                  archive_list->elems[i].data,
                  path_size - path_len);
            }

            string_list_append(db->list, new_path,
               archive_list->elems[i].attr);

            free(new_path);
         }

         string_list_free(archive_list);
      }
   }

   db_state->list_index  = 0;
   db_state->entry_index = 0;

   if (db_state->crc != 0)
      db_state->crc = 0;

   return 0;
}
Example #4
0
/**
 * content_file_read:
 * @path             : path to file.
 * @buf              : buffer to allocate and read the contents of the
 *                     file into. Needs to be freed manually.
 * @length           : Number of items read, -1 on error.
 *
 * Read the contents of a file into @buf. Will call content_file_compressed_read 
 * if path contains a compressed file, otherwise will call retro_read_file().
 *
 * Returns: 1 if file read, 0 on error.
 */
static int content_file_read(const char *path, void **buf, ssize_t *length)
{
#ifdef HAVE_COMPRESSION
   if (path_contains_compressed_file(path))
   {
      if (content_file_compressed_read(path, buf, NULL, length))
         return 1;
   }
#endif
   return retro_read_file(path, buf, length);
}
Example #5
0
/**
 * read_file:
 * @path             : path to file.
 * @buf              : buffer to allocate and read the contents of the
 *                     file into. Needs to be freed manually.
 * @length           : Number of items read, -1 on error.
 *
 * Read the contents of a file into @buf. Will call read_compressed_file
 * if path contains a compressed file, otherwise will call read_generic_file.
 *
 * Returns: 1 if file read, 0 on error.
 */
int read_file(const char *path, void **buf, ssize_t *length)
{
#ifdef HAVE_COMPRESSION
   if (path_contains_compressed_file(path))
   {
      if (read_compressed_file(path, buf, NULL, length))
         return 1;
   }
#endif
   return read_generic_file(path, buf, length);
}
Example #6
0
/* Generic file loader. */
long read_file(const char *path, void **buf)
{
   /* Here we check, whether the file, we are about to read is
    * inside an archive, or not.
    *
    * We determine, whether a file is inside a compressed archive,
    * by checking for the # inside the URL.
    *
    * For example: fullpath: /home/user/game.7z/mygame.rom
    * carchive_path: /home/user/game.7z
    * */
#ifdef HAVE_COMPRESSION
   if (path_contains_compressed_file(path))
      return read_compressed_file(path,buf,0);
#endif
   return read_generic_file(path,buf);
}
Example #7
0
static bool load_content_from_compressed_archive(
      struct string_list *temporary_content,
      struct retro_game_info *info, unsigned i,
      struct string_list* additional_path_allocs,
      bool need_fullpath, const char *path)
{
   union string_list_elem_attr attributes;
   ssize_t new_path_len;
   char new_path[PATH_MAX_LENGTH];
   char new_basedir[PATH_MAX_LENGTH];
   bool ret                          = false;
   settings_t *settings              = config_get_ptr();
   rarch_system_info_t      *sys_info= NULL;

   runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &sys_info);

   if (sys_info && sys_info->info.block_extract)
      return true;
   if (!need_fullpath || !path_contains_compressed_file(path))
      return true;

   RARCH_LOG("Compressed file in case of need_fullpath."
         " Now extracting to temporary directory.\n");

   strlcpy(new_basedir, settings->cache_directory,
         sizeof(new_basedir));

   if (string_is_empty(new_basedir) || !path_is_directory(new_basedir))
   {
      RARCH_WARN("Tried extracting to cache directory, but "
            "cache directory was not set or found. "
            "Setting cache directory to directory "
            "derived by basename...\n");
      fill_pathname_basedir(new_basedir, path,
            sizeof(new_basedir));
   }

   attributes.i = 0;
   fill_pathname_join(new_path, new_basedir,
         path_basename(path), sizeof(new_path));

   ret = content_file_compressed_read(path, NULL, new_path, &new_path_len);

   if (!ret || new_path_len < 0)
   {
      RARCH_ERR("%s \"%s\".\n",
            msg_hash_to_str(MSG_COULD_NOT_READ_CONTENT_FILE),
            path);
      return false;
   }

   RARCH_LOG("New path is: [%s]\n", new_path);

   string_list_append(additional_path_allocs, new_path, attributes);
   info[i].path = 
      additional_path_allocs->elems[additional_path_allocs->size -1 ].data;

   if (!string_list_append(temporary_content, new_path, attributes))
      return false;

   return true;
}
static int task_database_iterate_crc_lookup(
      db_handle_t *_db,
      database_state_handle_t *db_state,
      database_info_handle_t *db,
      const char *name,
      const char *archive_entry)
{

   if (!db_state->list ||
         (unsigned)db_state->list_index == (unsigned)db_state->list->size)
      return database_info_list_iterate_end_no_match(db, db_state, name);

   if (db_state->entry_index == 0)
   {
      char query[50];

      query[0] = '\0';

      /* don't scan files that can't be in this database */
      if (!(path_contains_compressed_file(name) &&
         core_info_database_match_archive_member(
         db_state->list->elems[db_state->list_index].data)) &&
          !core_info_database_supports_content_path(
         db_state->list->elems[db_state->list_index].data, name))
         return database_info_list_iterate_next(db_state);

      snprintf(query, sizeof(query),
            "{crc:or(b\"%08X\",b\"%08X\")}",
            db_state->crc, db_state->archive_crc);

      database_info_list_iterate_new(db_state, query);
   }

   if (db_state->info)
   {
      database_info_t *db_info_entry =
         &db_state->info->list[db_state->entry_index];

      if (db_info_entry && db_info_entry->crc32)
      {
#if 0
         RARCH_LOG("CRC32: 0x%08X , entry CRC32: 0x%08X (%s).\n",
               db_state->crc, db_info_entry->crc32, db_info_entry->name);
#endif
         if (db_state->archive_crc == db_info_entry->crc32)
            return database_info_list_iterate_found_match(
                  _db,
                  db_state, db, NULL);
         if (db_state->crc == db_info_entry->crc32)
            return database_info_list_iterate_found_match(
                  _db,
                  db_state, db, archive_entry);
      }
   }

   db_state->entry_index++;

   if (db_state->info)
   {
      if (db_state->entry_index >= db_state->info->count)
         return database_info_list_iterate_next(db_state);
   }

   /* If we haven't reached the end of the database list yet,
    * continue iterating. */
   if (db_state->list_index < db_state->list->size)
      return 1;

   database_info_list_free(db_state->info);

   if (db_state->info)
      free(db_state->info);

   return 0;
}
Example #9
0
static bool load_content(const struct retro_subsystem_info *special,
      const struct string_list *content)
{
   unsigned i;
   bool ret = true;

   struct string_list* additional_path_allocs = string_list_new();

   struct retro_game_info *info = (struct retro_game_info*)
      calloc(content->size, sizeof(*info));

   if (!info)
      return false;

   for (i = 0; i < content->size; i++)
   {
      const char *path = content->elems[i].data;
      int attr = content->elems[i].attr.i;

      bool need_fullpath = attr & 2;
      bool require_content = attr & 4;

      if (require_content && !*path)
      {
         RARCH_LOG("libretro core requires content, but nothing was provided.\n");
         ret = false;
         goto end;
      }

      info[i].path = *path ? path : NULL;
      if (!need_fullpath && *path)
      {
         /* Load the content into memory. */
         RARCH_LOG("Loading content file: %s.\n", path);

         /* First content file is significant, attempt to do patching,
          * CRC checking, etc. */
         long size = i == 0 ?
            read_content_file(path, (void**)&info[i].data) :
            read_file(path, (void**)&info[i].data);

         if (size < 0)
         {
            RARCH_ERR("Could not read content file \"%s\".\n", path);
            ret = false;
            goto end;
         }

         info[i].size = size;
      }
      else
      {
         RARCH_LOG("Content loading skipped. Implementation will"
               " load it on its own.\n");
         if (need_fullpath && path_contains_compressed_file(path))
         {
            RARCH_LOG("Compressed file in case of need_fullpath."
                  "Now extracting to temporary directory.\n");

            if ((!strcmp(g_settings.extraction_directory,"")) ||
                 !path_is_directory(g_settings.extraction_directory))
            {
               RARCH_ERR("Tried extracting to extraction directory, but "
                      "extraction directory was not set or found. Exiting.\n");
               rarch_assert(false);
            }

            char new_path[PATH_MAX];
            union string_list_elem_attr attr;
            attr.i = 0;
            fill_pathname_join(new_path,g_settings.extraction_directory,
                  path_basename(path),sizeof(new_path));
            read_compressed_file(path,NULL,new_path);
            string_list_append(additional_path_allocs,new_path,attr);
            info[i].path =
                  additional_path_allocs->elems
                     [additional_path_allocs->size -1 ].data;
         }
      }
   }

   if (special)
      ret = pretro_load_game_special(special->id, info, content->size);
   else
      ret = pretro_load_game(*content->elems[0].data ? info : NULL);

   if (!ret)
      RARCH_ERR("Failed to load game.\n");

end:
   for (i = 0; i < content->size; i++)
      free((void*)info[i].data);

   string_list_free(additional_path_allocs);
   free(info);
   return ret;
}
Example #10
0
database_info_handle_t *database_info_dir_init(const char *dir,
      enum database_type type)
{
   database_info_handle_t     *db  = (database_info_handle_t*)
      calloc(1, sizeof(*db));
   unsigned i = 0;

   if (!db)
      return NULL;

   db->list           = dir_list_new_special(dir, DIR_LIST_RECURSIVE, NULL);

   if (!db->list)
      goto error;

   db->list_ptr       = 0;
   db->status         = DATABASE_STATUS_ITERATE;
   db->type           = type;

   if (db->list->size > 0)
   {
      for (i = 0; i < db->list->size; i++)
      {
         const char *path = db->list->elems[i].data;

         if (path_is_compressed_file(path) && !path_contains_compressed_file(path))
         {
            struct string_list *archive_list = path_is_compressed_file(path) ?
                  file_archive_get_file_list(path, NULL) : NULL;

            if (archive_list && archive_list->size > 0)
            {
               unsigned i;

               for (i = 0; i < archive_list->size; i++)
               {
                  char new_path[PATH_MAX_LENGTH];
                  size_t path_len = strlen(path);

                  new_path[0] = '\0';

                  strlcpy(new_path, path, sizeof(new_path));

                  if (path_len + strlen(archive_list->elems[i].data)
                         + 1 < PATH_MAX_LENGTH)
                  {
                     new_path[path_len] = '#';
                     strlcpy(new_path + path_len + 1,
                                archive_list->elems[i].data,
                                sizeof(new_path) - path_len);
                  }

                  string_list_append(db->list, new_path,
                                        archive_list->elems[i].attr);
               }

               string_list_free(archive_list);
            }
         }
      }
   }

   return db;

error:
   if (db)
      free(db);
   return NULL;
}
Example #11
0
static bool load_content_need_fullpath(
      struct retro_game_info *info, unsigned i,
      struct string_list* additional_path_allocs,
      bool need_fullpath, const char *path)
{
#ifdef HAVE_COMPRESSION
   ssize_t len;
   union string_list_elem_attr attributes;
   char new_path[PATH_MAX_LENGTH]    = {0};
   char new_basedir[PATH_MAX_LENGTH] = {0};
   bool ret                          = false;
   settings_t *settings              = config_get_ptr();
   global_t   *global                = global_get_ptr();
   rarch_system_info_t      *sys_info= rarch_system_info_get_ptr();

   if (sys_info && sys_info->info.block_extract)
      return true;

   if (!need_fullpath)
      return true;

   if (!path_contains_compressed_file(path))
      return true;

   RARCH_LOG("Compressed file in case of need_fullpath."
         "Now extracting to temporary directory.\n");

   strlcpy(new_basedir, settings->extraction_directory,
         sizeof(new_basedir));

   if ((!strcmp(new_basedir, "")) ||
         !path_is_directory(new_basedir))
   {
      RARCH_WARN("Tried extracting to extraction directory, but "
            "extraction directory was not set or found. "
            "Setting extraction directory to directory "
            "derived by basename...\n");
      fill_pathname_basedir(new_basedir, path,
            sizeof(new_basedir));
   }

   attributes.i = 0;
   fill_pathname_join(new_path, new_basedir,
         path_basename(path), sizeof(new_path));

   ret = read_compressed_file(path,NULL,new_path, &len);

   if (!ret || len < 0)
   {
      RARCH_ERR("%s \"%s\".\n",
            msg_hash_to_str(MSG_COULD_NOT_READ_CONTENT_FILE),
            path);
      return false;
   }

   string_list_append(additional_path_allocs,new_path, attributes);
   info[i].path =
      additional_path_allocs->elems
      [additional_path_allocs->size -1 ].data;

   /* global->temporary_content is initialized in init_content_file
    * The following part takes care of cleanup of the unzipped files
    * after exit.
    */
   rarch_assert(global->temporary_content != NULL);
   string_list_append(global->temporary_content,
         new_path, attributes);

#endif
   return true;
}
Example #12
0
/**
 * content_file_load:
 * @special          : subsystem of content to be loaded. Can be NULL.
 * content           :
 *
 * Load content file (for libretro core).
 *
 * Returns : true if successful, otherwise false.
 **/
static bool content_file_load(
      struct retro_game_info *info,
      const struct string_list *content,
      content_information_ctx_t *content_ctx,
      char **error_string,
      const struct retro_subsystem_info *special
      )
{
   unsigned i;
   retro_ctx_load_content_info_t load_info;
   char msg[1024];
   struct string_list *additional_path_allocs = string_list_new();

   msg[0] = '\0';

   if (!additional_path_allocs)
      return false;

   for (i = 0; i < content->size; i++)
   {
      int         attr     = content->elems[i].attr.i;
      const char *path     = content->elems[i].data;
      bool need_fullpath   = attr & 2;
      bool require_content = attr & 4;

      if (require_content && string_is_empty(path))
      {
         snprintf(msg, sizeof(msg),
               "%s\n",
               msg_hash_to_str(MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT));
         *error_string = strdup(msg);
         goto error;
      }

      info[i].path = NULL;

      if (!string_is_empty(path))
         info[i].path = path;

      if (!need_fullpath && !string_is_empty(path))
      {
         /* Load the content into memory. */

         ssize_t len = 0;

         if (!load_content_into_memory(i, path, (void**)&info[i].data, &len))
         {
            snprintf(msg, sizeof(msg),
                  "%s \"%s\".\n",
                  msg_hash_to_str(MSG_COULD_NOT_READ_CONTENT_FILE),
                  path);
            *error_string = strdup(msg);
            goto error;
         }

         info[i].size = len;
      }
      else
      {
         RARCH_LOG("%s\n",
               msg_hash_to_str(
                  MSG_CONTENT_LOADING_SKIPPED_IMPLEMENTATION_WILL_DO_IT));

#ifdef HAVE_COMPRESSION
         if (     !content_ctx->block_extract
               && need_fullpath
               && path_contains_compressed_file(path)
               && !load_content_from_compressed_archive(
                  content_ctx,
                  &info[i], i,
                  additional_path_allocs, need_fullpath, path,
                  error_string))
            goto error;
#endif
      }
   }

   load_info.content = content;
   load_info.special = special;
   load_info.info    = info;

   if (!core_load_game(&load_info))
   {
      snprintf(msg, sizeof(msg),
            "%s.\n", msg_hash_to_str(MSG_FAILED_TO_LOAD_CONTENT));
      *error_string = strdup(msg);
      goto error;
   }

#ifdef HAVE_CHEEVOS
   if (!special)
   {
      const void *load_data = NULL;
      const char *path      = content->elems[0].data;

      cheevos_set_cheats();

      if (!string_is_empty(path))
         load_data = info;
      cheevos_load(load_data);
   }
#endif

   string_list_free(additional_path_allocs);

   return true;

error:
   if (additional_path_allocs)
      string_list_free(additional_path_allocs);
   
   return false;
}
Example #13
0
/**
 * file_archive_get_file_crc32:
 * @path                         : filename path of archive
 *
 * Returns: CRC32 of the specified file in the archive, otherwise 0.
 * If no path within the archive is specified, the first
 * file found inside is used.
 **/
uint32_t file_archive_get_file_crc32(const char *path)
{
   file_archive_transfer_t state;
   const struct file_archive_file_backend *backend = file_archive_get_file_backend(path);
   struct archive_extract_userdata userdata        = {{0}};
   bool returnerr                                  = false;
   bool contains_compressed                        = false;
   const char *archive_path                        = NULL;

   if (!backend)
      return 0;

   contains_compressed = path_contains_compressed_file(path);

   if (contains_compressed)
   {
      archive_path = path_get_archive_delim(path);

      /* move pointer right after the delimiter to give us the path */
      if (archive_path)
         archive_path += 1;
   }

   state.type          = ARCHIVE_TRANSFER_INIT;
   state.archive_size  = 0;
   state.handle        = NULL;
   state.stream        = NULL;
   state.footer        = NULL;
   state.directory     = NULL;
   state.data          = NULL;
   state.backend       = NULL;

   /* Initialize and open archive first.
      Sets next state type to ITERATE. */
   file_archive_parse_file_iterate(&state,
            &returnerr, path, NULL, NULL,
            &userdata);

   for (;;)
   {
      /* Now find the first file in the archive. */
      if (state.type == ARCHIVE_TRANSFER_ITERATE)
         file_archive_parse_file_iterate(&state,
                  &returnerr, path, NULL, NULL,
                  &userdata);

      /* If no path specified within archive, stop after
       * finding the first file.
       */
      if (!contains_compressed)
         break;

      /* Stop when the right file in the archive is found. */
      if (archive_path)
      {
         if (string_is_equal(userdata.extracted_file_path, archive_path))
            break;
      }
      else
         break;
   }

   file_archive_parse_file_iterate_stop(&state);

   if (userdata.crc)
      return userdata.crc;

   return 0;
}
Example #14
0
static bool init_content_file_extract(
      struct string_list *temporary_content,
      struct string_list *content,
      const struct retro_subsystem_info *special,
      union string_list_elem_attr *attr
      )
{
   unsigned i;
   settings_t *settings        = config_get_ptr();
   rarch_system_info_t *system = NULL;

   runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &system);

   for (i = 0; i < content->size; i++)
   {
      char temp_content[PATH_MAX_LENGTH];
      char new_path[PATH_MAX_LENGTH];
      bool contains_compressed           = NULL;
      bool block_extract                 = content->elems[i].attr.i & 1;
      const char *valid_ext              = system->info.valid_extensions;

      /* Block extract check. */
      if (block_extract)
         continue;

      contains_compressed   = path_contains_compressed_file(content->elems[i].data);

      if (special)
         valid_ext          = special->roms[i].valid_extensions;

      if (!contains_compressed)
      {
         /* just use the first file in the archive */
         if (!path_is_compressed_file(content->elems[i].data))
            continue;
      }

      temp_content[0] = new_path[0] = '\0';

      strlcpy(temp_content, content->elems[i].data,
            sizeof(temp_content));

      if (!valid_ext || !file_archive_extract_file(temp_content,
               sizeof(temp_content), valid_ext,
               *settings->directory.cache ?
               settings->directory.cache : NULL,
               new_path, sizeof(new_path)))
      {
         RARCH_ERR("%s: %s.\n",
               msg_hash_to_str(
                  MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE),
               temp_content);
         runloop_msg_queue_push(
               msg_hash_to_str(MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE)
               , 2, 180, true);
         return false;
      }

      string_list_set(content, i, new_path);
      if (!string_list_append(temporary_content,
               new_path, *attr))
         return false;
   }

   return true;
}