コード例 #1
0
ファイル: file_extract.c プロジェクト: hbfelizzola/RetroArch
/**
 * zlib_inflate_data_to_file:
 * @path                        : filename path of archive.
 * @valid_exts                  : Valid extensions of archive to be parsed. 
 *                                If NULL, allow all.
 * @cdata                       : input data.
 * @csize                       : size of input data.
 * @size                        : output file size
 * @checksum                    : CRC32 checksum from input data.
 *
 * Decompress data to file.
 *
 * Returns: true (1) on success, otherwise false (0).
 **/
int zlib_inflate_data_to_file(zlib_file_handle_t *handle,
      int ret, const char *path, const char *valid_exts,
      const uint8_t *cdata, uint32_t csize, uint32_t size, uint32_t checksum)
{
   if (handle)
   {
      zlib_stream_free(handle->stream);
      free(handle->stream);
   }

   if (!handle || ret == -1)
   {
      ret = 0;
      goto end;
   }

   handle->real_checksum = zlib_crc32_calculate(handle->data, size);

#if 0
   if (handle->real_checksum != checksum)
   {
      /* File CRC difers from ZIP CRC. */
      printf("File CRC differs from ZIP CRC. File: 0x%x, ZIP: 0x%x.\n",
            (unsigned)handle->real_checksum, (unsigned)checksum);
   }
#endif

   if (!zlib_write_file(path, handle->data, size))
      GOTO_END_ERROR();

end:
   if (handle->data)
      free(handle->data);
   return ret;
}
コード例 #2
0
ファイル: file_extract.c プロジェクト: hbfelizzola/RetroArch
/**
 * zlib_extract_first_content_file:
 * @zip_path                    : filename path to ZIP archive.
 * @zip_path_size               : size of ZIP archive.
 * @valid_exts                  : valid extensions for a content file.
 * @extraction_directory        : the directory to extract temporary
 *                                unzipped content to.
 *
 * Extract first content file from archive.
 *
 * Returns : true (1) on success, otherwise false (0).
 **/
bool zlib_extract_first_content_file(char *zip_path, size_t zip_path_size,
      const char *valid_exts, const char *extraction_directory)
{
   struct string_list *list;
   bool ret = true;
   struct zip_extract_userdata userdata = {0};

   if (!valid_exts)
   {
      /* Libretro implementation does not have any valid extensions.
       * Cannot unzip without knowing this. */
      return false;
   }

   list = string_split(valid_exts, "|");
   if (!list)
      GOTO_END_ERROR();

   userdata.zip_path             = zip_path;
   userdata.zip_path_size        = zip_path_size;
   userdata.extraction_directory = extraction_directory;
   userdata.ext                  = list;

   if (!zlib_parse_file(zip_path, valid_exts, zip_extract_cb, &userdata))
   {
      /* Parsing ZIP failed. */
      GOTO_END_ERROR();
   }

   if (!userdata.found_content)
   {
      /* Didn't find any content that matched valid extensions
       * for libretro implementation. */
      GOTO_END_ERROR();
   }

end:
   if (list)
      string_list_free(list);
   return ret;
}
コード例 #3
0
ファイル: file_extract.c プロジェクト: AbelFlos/RetroArch
bool zlib_extract_first_rom(char *zip_path, size_t zip_path_size, const char *valid_exts)
{
   bool ret;
   struct zip_extract_userdata userdata = {0};
   struct string_list *list;

   if (!valid_exts)
   {
      RARCH_ERR("Libretro implementation does not have any valid extensions. Cannot unzip without knowing this.\n");
      return false;
   }

   ret = true;
   list = string_split(valid_exts, "|");
   if (!list)
      GOTO_END_ERROR();

   userdata.zip_path = zip_path;
   userdata.zip_path_size = zip_path_size;
   userdata.ext = list;

   if (!zlib_parse_file(zip_path, zip_extract_cb, &userdata))
   {
      RARCH_ERR("Parsing ZIP failed.\n");
      GOTO_END_ERROR();
   }

   if (!userdata.found_rom)
   {
      RARCH_ERR("Didn't find any ROMS that matched valid extensions for libretro implementation.\n");
      GOTO_END_ERROR();
   }

end:
   if (list)
      string_list_free(list);
   return ret;
}
コード例 #4
0
ファイル: file_extract.c プロジェクト: AbelFlos/RetroArch
bool zlib_inflate_data_to_file(const char *path, const uint8_t *cdata,
      uint32_t csize, uint32_t size, uint32_t crc32)
{
   bool ret = true;
   uint8_t *out_data = (uint8_t*)malloc(size);
   if (!out_data)
      return false;

   uint32_t real_crc32 = 0;
   z_stream stream = {0};

   if (inflateInit2(&stream, -MAX_WBITS) != Z_OK)
      GOTO_END_ERROR();

   stream.next_in = (uint8_t*)cdata;
   stream.avail_in = csize;
   stream.next_out = out_data;
   stream.avail_out = size;

   if (inflate(&stream, Z_FINISH) != Z_STREAM_END)
   {
      inflateEnd(&stream);
      GOTO_END_ERROR();
   }
   inflateEnd(&stream);

   real_crc32 = crc32_calculate(out_data, size);
   if (real_crc32 != crc32)
      RARCH_WARN("File CRC differs from ZIP CRC. File: 0x%x, ZIP: 0x%x.\n",
            (unsigned)real_crc32, (unsigned)crc32);

   if (!write_file(path, out_data, size))
      GOTO_END_ERROR();

end:
   free(out_data);
   return ret;
}
コード例 #5
0
ファイル: rpng_decode.c プロジェクト: AirBrowse/RetroArch
bool png_process_ihdr(struct png_ihdr *ihdr)
{
   unsigned i;
   bool ret = true;

   switch (ihdr->color_type)
   {
      case PNG_IHDR_COLOR_RGB:
      case PNG_IHDR_COLOR_GRAY_ALPHA:
      case PNG_IHDR_COLOR_RGBA:
         if (ihdr->depth != 8 && ihdr->depth != 16)
            GOTO_END_ERROR();
         break;
      case PNG_IHDR_COLOR_GRAY:
         {
            static const unsigned valid_bpp[] = { 1, 2, 4, 8, 16 };
            bool correct_bpp = false;

            for (i = 0; i < ARRAY_SIZE(valid_bpp); i++)
            {
               if (valid_bpp[i] == ihdr->depth)
               {
                  correct_bpp = true;
                  break;
               }
            }

            if (!correct_bpp)
               GOTO_END_ERROR();
         }
         break;
      case PNG_IHDR_COLOR_PLT:
         {
            static const unsigned valid_bpp[] = { 1, 2, 4, 8 };
            bool correct_bpp = false;

            for (i = 0; i < ARRAY_SIZE(valid_bpp); i++)
            {
               if (valid_bpp[i] == ihdr->depth)
               {
                  correct_bpp = true;
                  break;
               }
            }

            if (!correct_bpp)
               GOTO_END_ERROR();
         }
         break;
      default:
         GOTO_END_ERROR();
   }

#ifdef RPNG_TEST
   fprintf(stderr, "IHDR: (%u x %u), bpc = %u, palette = %s, color = %s, alpha = %s, adam7 = %s.\n",
         ihdr->width, ihdr->height,
         ihdr->depth, ihdr->color_type == PNG_IHDR_COLOR_PLT ? "yes" : "no",
         ihdr->color_type & PNG_IHDR_COLOR_RGB ? "yes" : "no",
         ihdr->color_type & PNG_IHDR_COLOR_GRAY_ALPHA ? "yes" : "no",
         ihdr->interlace == 1 ? "yes" : "no");
#endif

   if (ihdr->compression != 0)
      GOTO_END_ERROR();

end:
   return ret;
}
コード例 #6
0
ファイル: file_extract.c プロジェクト: AbelFlos/RetroArch
bool zlib_parse_file(const char *file, zlib_file_cb file_cb, void *userdata)
{
   const uint8_t *footer = NULL;
   const uint8_t *directory = NULL;

   bool ret = true;
   const uint8_t *data = NULL;

   const struct zlib_file_backend *backend = zlib_get_default_file_backend();
   if (!backend)
      return NULL;

   ssize_t zip_size = 0;
   void *handle = backend->open(file);
   if (!handle)
      GOTO_END_ERROR();

   zip_size = backend->size(handle);
   if (zip_size < 22)
      GOTO_END_ERROR();

   data = backend->data(handle);

   footer = data + zip_size - 22;
   for (;; footer--)
   {
      if (footer <= data + 22)
         GOTO_END_ERROR();
      if (read_le(footer, 4) == 0x06054b50)
      {
         unsigned comment_len = read_le(footer + 20, 2);
         if (footer + 22 + comment_len == data + zip_size)
            break;
      }
   }

   directory = data + read_le(footer + 16, 4);

   for (;;)
   {
      uint32_t signature = read_le(directory + 0, 4);
      if (signature != 0x02014b50)
         break;

      unsigned cmode = read_le(directory + 10, 2);
      uint32_t crc32 = read_le(directory + 16, 4);
      uint32_t csize = read_le(directory + 20, 4);
      uint32_t size  = read_le(directory + 24, 4);

      unsigned namelength    = read_le(directory + 28, 2);
      unsigned extralength   = read_le(directory + 30, 2);
      unsigned commentlength = read_le(directory + 32, 2);

      char filename[PATH_MAX] = {0};
      if (namelength >= PATH_MAX)
         GOTO_END_ERROR();

      memcpy(filename, directory + 46, namelength);

      uint32_t offset   = read_le(directory + 42, 4);
      unsigned offsetNL = read_le(data + offset + 26, 2);
      unsigned offsetEL = read_le(data + offset + 28, 2);

      const uint8_t *cdata = data + offset + 30 + offsetNL + offsetEL;

      //RARCH_LOG("OFFSET: %u, CSIZE: %u, SIZE: %u.\n", offset + 30 + offsetNL + offsetEL, csize, size);

      if (!file_cb(filename, cdata, cmode, csize, size, crc32, userdata))
         break;

      directory += 46 + namelength + extralength + commentlength;
   }

end:
   if (handle)
      backend->free(handle);
   return ret;
}
コード例 #7
0
ファイル: rpng.c プロジェクト: Hydro5/RetroArch
bool rpng_load_image_argb(const char *path, uint32_t **data, unsigned *width, unsigned *height)
{
   long pos;
   *data   = NULL;
   *width  = 0;
   *height = 0;

   bool ret = true;
   FILE *file = fopen(path, "rb");
   if (!file)
      return false;

   fseek(file, 0, SEEK_END);
   long file_len = ftell(file);
   rewind(file);

   bool has_ihdr = false;
   bool has_idat = false;
   bool has_iend = false;
   bool has_plte = false;
   uint8_t *inflate_buf = NULL;
   size_t inflate_buf_size = 0;
   z_stream stream = {0};

   struct idat_buffer idat_buf = {0};
   struct png_ihdr ihdr = {0};
   uint32_t palette[256] = {0};

   char header[8];
   if (fread(header, 1, sizeof(header), file) != sizeof(header))
      GOTO_END_ERROR();

   if (memcmp(header, png_magic, sizeof(png_magic)) != 0)
      GOTO_END_ERROR();

   // feof() apparently isn't triggered after a seek (IEND).
   for (pos = ftell(file); pos < file_len && pos >= 0; pos = ftell(file))
   {
      struct png_chunk chunk = {0};
      if (!read_chunk_header(file, &chunk))
         GOTO_END_ERROR();

      switch (png_chunk_type(&chunk))
      {
         case PNG_CHUNK_NOOP:
         default:
            if (fseek(file, chunk.size + sizeof(uint32_t), SEEK_CUR) < 0)
               GOTO_END_ERROR();
            break;

         case PNG_CHUNK_ERROR:
            GOTO_END_ERROR();

         case PNG_CHUNK_IHDR:
            if (has_ihdr || has_idat || has_iend)
               GOTO_END_ERROR();

            if (!png_parse_ihdr(file, &chunk, &ihdr))
               GOTO_END_ERROR();

            has_ihdr = true;
            break;

         case PNG_CHUNK_PLTE:
            if (!has_ihdr || has_plte || has_iend || has_idat)
               GOTO_END_ERROR();

            if (chunk.size % 3)
               GOTO_END_ERROR();

            if (!png_read_plte(file, palette, chunk.size / 3))
               GOTO_END_ERROR();

            has_plte = true;
            break;

         case PNG_CHUNK_IDAT:
            if (!has_ihdr || has_iend || (ihdr.color_type == 3 && !has_plte))
               GOTO_END_ERROR();

            if (!png_append_idat(file, &chunk, &idat_buf))
               GOTO_END_ERROR();

            has_idat = true;
            break;

         case PNG_CHUNK_IEND:
            if (!has_ihdr || !has_idat)
               GOTO_END_ERROR();

            if (fseek(file, sizeof(uint32_t), SEEK_CUR) < 0)
               GOTO_END_ERROR();

            has_iend = true;
            break;
      }
   }

   if (!has_ihdr || !has_idat || !has_iend)
      GOTO_END_ERROR();

   if (inflateInit(&stream) != Z_OK)
      GOTO_END_ERROR();

   png_pass_geom(&ihdr, ihdr.width, ihdr.height, NULL, NULL, &inflate_buf_size);
   if (ihdr.interlace == 1) // To be sure.
      inflate_buf_size *= 2;

   inflate_buf = (uint8_t*)malloc(inflate_buf_size);
   if (!inflate_buf)
      GOTO_END_ERROR();

   stream.next_in   = idat_buf.data;
   stream.avail_in  = idat_buf.size;
   stream.avail_out = inflate_buf_size;
   stream.next_out  = inflate_buf;

   if (inflate(&stream, Z_FINISH) != Z_STREAM_END)
   {
      inflateEnd(&stream);
      GOTO_END_ERROR();
   }
   inflateEnd(&stream);

   *width  = ihdr.width;
   *height = ihdr.height;
   *data = (uint32_t*)malloc(ihdr.width * ihdr.height * sizeof(uint32_t));
   if (!*data)
      GOTO_END_ERROR();

   if (ihdr.interlace == 1)
   {
      if (!png_reverse_filter_adam7(*data, &ihdr, inflate_buf, stream.total_out, palette))
         GOTO_END_ERROR();
   }
   else if (!png_reverse_filter(*data, &ihdr, inflate_buf, stream.total_out, palette))
      GOTO_END_ERROR();

end:
   if (file)
      fclose(file);
   if (!ret)
      free(*data);
   free(idat_buf.data);
   free(inflate_buf);
   return ret;
}
コード例 #8
0
ファイル: rpng.c プロジェクト: Hydro5/RetroArch
static bool png_reverse_filter(uint32_t *data, const struct png_ihdr *ihdr,
      const uint8_t *inflate_buf, size_t inflate_buf_size, const uint32_t *palette)
{
   unsigned i, h;
   bool ret = true;

   unsigned bpp;
   unsigned pitch;
   size_t pass_size;
   png_pass_geom(ihdr, ihdr->width, ihdr->height, &bpp, &pitch, &pass_size);

   if (inflate_buf_size < pass_size)
      return false;

   uint8_t *prev_scanline    = (uint8_t*)calloc(1, pitch);
   uint8_t *decoded_scanline = (uint8_t*)calloc(1, pitch);

   if (!prev_scanline || !decoded_scanline)
      GOTO_END_ERROR();

   for (h = 0; h < ihdr->height;
         h++, inflate_buf += pitch, data += ihdr->width)
   {
      unsigned filter = *inflate_buf++;
      switch (filter)
      {
         case 0: // None
            memcpy(decoded_scanline, inflate_buf, pitch);
            break;

         case 1: // Sub
            for (i = 0; i < bpp; i++)
               decoded_scanline[i] = inflate_buf[i];
            for (i = bpp; i < pitch; i++)
               decoded_scanline[i] = decoded_scanline[i - bpp] + inflate_buf[i];
            break;

         case 2: // Up
            for (i = 0; i < pitch; i++)
               decoded_scanline[i] = prev_scanline[i] + inflate_buf[i];
            break;

         case 3: // Average
            for (i = 0; i < bpp; i++)
            {
               uint8_t avg = prev_scanline[i] >> 1;
               decoded_scanline[i] = avg + inflate_buf[i];
            }
            for (i = bpp; i < pitch; i++)
            {
               uint8_t avg = (decoded_scanline[i - bpp] + prev_scanline[i]) >> 1;
               decoded_scanline[i] = avg + inflate_buf[i];
            }
            break;

         case 4: // Paeth
            for (i = 0; i < bpp; i++)
               decoded_scanline[i] = paeth(0, prev_scanline[i], 0) + inflate_buf[i];
            for (i = bpp; i < pitch; i++)
               decoded_scanline[i] = paeth(decoded_scanline[i - bpp], prev_scanline[i], prev_scanline[i - bpp]) + inflate_buf[i];
            break;

         default:
            GOTO_END_ERROR();
      }

      if (ihdr->color_type == 0)
         copy_line_bw(data, decoded_scanline, ihdr->width, ihdr->depth);
      else if (ihdr->color_type == 2)
         copy_line_rgb(data, decoded_scanline, ihdr->width, ihdr->depth);
      else if (ihdr->color_type == 3)
         copy_line_plt(data, decoded_scanline, ihdr->width, ihdr->depth, palette);
      else if (ihdr->color_type == 4)
         copy_line_gray_alpha(data, decoded_scanline, ihdr->width, ihdr->depth);
      else if (ihdr->color_type == 6)
         copy_line_rgba(data, decoded_scanline, ihdr->width, ihdr->depth);

      memcpy(prev_scanline, decoded_scanline, pitch);
   }

end:
   free(decoded_scanline);
   free(prev_scanline);
   return ret;
}
コード例 #9
0
ファイル: rpng.c プロジェクト: Hydro5/RetroArch
static bool png_parse_ihdr(FILE *file, struct png_chunk *chunk, struct png_ihdr *ihdr)
{
   unsigned i;
   bool ret = true;
   if (!png_read_chunk(file, chunk))
      return false;

   if (chunk->size != 13)
      GOTO_END_ERROR();

   ihdr->width       = dword_be(chunk->data + 0);
   ihdr->height      = dword_be(chunk->data + 4);
   ihdr->depth       = chunk->data[8];
   ihdr->color_type  = chunk->data[9];
   ihdr->compression = chunk->data[10];
   ihdr->filter      = chunk->data[11];
   ihdr->interlace   = chunk->data[12];

   if (ihdr->width == 0 || ihdr->height == 0)
      GOTO_END_ERROR();

   if (ihdr->color_type == 2 || ihdr->color_type == 4 || ihdr->color_type == 6)
   {
      if (ihdr->depth != 8 && ihdr->depth != 16)
         GOTO_END_ERROR();
   }
   else if (ihdr->color_type == 0)
   {
      static const unsigned valid_bpp[] = { 1, 2, 4, 8, 16 };
      bool correct_bpp = false;
      for (i = 0; i < ARRAY_SIZE(valid_bpp); i++)
      {
         if (valid_bpp[i] == ihdr->depth)
         {
            correct_bpp = true;
            break;
         }
      }

      if (!correct_bpp)
         GOTO_END_ERROR();
   }
   else if (ihdr->color_type == 3)
   {
      static const unsigned valid_bpp[] = { 1, 2, 4, 8 };
      bool correct_bpp = false;
      for (i = 0; i < ARRAY_SIZE(valid_bpp); i++)
      {
         if (valid_bpp[i] == ihdr->depth)
         {
            correct_bpp = true;
            break;
         }
      }

      if (!correct_bpp)
         GOTO_END_ERROR();
   }
   else
      GOTO_END_ERROR();

#ifdef RPNG_TEST
   fprintf(stderr, "IHDR: (%u x %u), bpc = %u, palette = %s, color = %s, alpha = %s, adam7 = %s.\n",
         ihdr->width, ihdr->height,
         ihdr->depth, ihdr->color_type == 3 ? "yes" : "no",
         ihdr->color_type & 2 ? "yes" : "no",
         ihdr->color_type & 4 ? "yes" : "no",
         ihdr->interlace == 1 ? "yes" : "no");
#endif

   if (ihdr->compression != 0)
      GOTO_END_ERROR();

   //if (ihdr->interlace != 0) // No Adam7 supported.
   //   GOTO_END_ERROR();

end:
   png_free_chunk(chunk);
   return ret;
}
コード例 #10
0
ファイル: rpng_fbio.c プロジェクト: chungy/RetroArch
bool rpng_load_image_argb(const char *path, uint32_t **data,
      unsigned *width, unsigned *height)
{
   long pos, file_len;
   FILE *file;
   char header[8]     = {0};
   rpng_t rpng        = {{0}};
   bool ret           = true;
   int retval         = 0;

   *data   = NULL;
   *width  = 0;
   *height = 0;

   file = fopen(path, "rb");
   if (!file)
      return false;

   fseek(file, 0, SEEK_END);
   file_len = ftell(file);
   rewind(file);

   if (fread(header, 1, sizeof(header), file) != sizeof(header))
      GOTO_END_ERROR();

   if (memcmp(header, png_magic, sizeof(png_magic)) != 0)
      GOTO_END_ERROR();

   /* feof() apparently isn't triggered after a seek (IEND). */
   for (pos = ftell(file); 
         pos < file_len && pos >= 0; pos = ftell(file))
   {
      if (!rpng_load_image_argb_iterate(&file, &rpng))
         GOTO_END_ERROR();
   }

   if (!rpng.has_ihdr || !rpng.has_idat || !rpng.has_iend)
      GOTO_END_ERROR();

   if (!rpng_load_image_argb_process_init(&rpng, data, width,
            height))
      GOTO_END_ERROR();

   do{
      retval = rpng_load_image_argb_process_inflate_init(&rpng, data,
               width, height);
   }while(retval == 0);

   if (retval == -1)
      GOTO_END_ERROR();

   do{
      retval = png_reverse_filter_iterate(&rpng, data);
   }while(retval == PNG_PROCESS_NEXT);

   if (retval == PNG_PROCESS_ERROR || retval == PNG_PROCESS_ERROR_END)
      GOTO_END_ERROR();

end:
   if (file)
      fclose(file);
   if (!ret)
      free(*data);
   free(rpng.idat_buf.data);
   free(rpng.process.inflate_buf);

   if (rpng.process.stream)
   {
      zlib_stream_free(rpng.process.stream);
      free(rpng.process.stream);
   }
   return ret;
}
コード例 #11
0
ファイル: rpng_decode_fnbio.c プロジェクト: maddox/RetroArch
static bool png_parse_ihdr(uint8_t *buf,
      struct png_ihdr *ihdr)
{
   unsigned i;
   bool ret = true;

   buf += 4 + 4;

   ihdr->width       = dword_be(buf + 0);
   ihdr->height      = dword_be(buf + 4);
   ihdr->depth       = buf[8];
   ihdr->color_type  = buf[9];
   ihdr->compression = buf[10];
   ihdr->filter      = buf[11];
   ihdr->interlace   = buf[12];

   if (ihdr->width == 0 || ihdr->height == 0)
      GOTO_END_ERROR();

   if (ihdr->color_type == 2 || 
         ihdr->color_type == 4 || ihdr->color_type == 6)
   {
      if (ihdr->depth != 8 && ihdr->depth != 16)
         GOTO_END_ERROR();
   }
   else if (ihdr->color_type == 0)
   {
      static const unsigned valid_bpp[] = { 1, 2, 4, 8, 16 };
      bool correct_bpp = false;

      for (i = 0; i < ARRAY_SIZE(valid_bpp); i++)
      {
         if (valid_bpp[i] == ihdr->depth)
         {
            correct_bpp = true;
            break;
         }
      }

      if (!correct_bpp)
         GOTO_END_ERROR();
   }
   else if (ihdr->color_type == 3)
   {
      static const unsigned valid_bpp[] = { 1, 2, 4, 8 };
      bool correct_bpp = false;

      for (i = 0; i < ARRAY_SIZE(valid_bpp); i++)
      {
         if (valid_bpp[i] == ihdr->depth)
         {
            correct_bpp = true;
            break;
         }
      }

      if (!correct_bpp)
         GOTO_END_ERROR();
   }
   else
      GOTO_END_ERROR();

#ifdef RPNG_TEST
   fprintf(stderr, "IHDR: (%u x %u), bpc = %u, palette = %s, color = %s, alpha = %s, adam7 = %s.\n",
         ihdr->width, ihdr->height,
         ihdr->depth, ihdr->color_type == 3 ? "yes" : "no",
         ihdr->color_type & 2 ? "yes" : "no",
         ihdr->color_type & 4 ? "yes" : "no",
         ihdr->interlace == 1 ? "yes" : "no");
#endif

   if (ihdr->compression != 0)
      GOTO_END_ERROR();

#if 0
   if (ihdr->interlace != 0) /* No Adam7 supported. */
      GOTO_END_ERROR();
#endif

end:
   return ret;
}