Exemplo n.º 1
0
bool Launcher::UnshieldThread::extract_file(Unshield* unshield, bfs::path output_dir, const char* prefix, int index)
{
    bool success;
    bfs::path dirname;
    bfs::path filename;
    int directory = unshield_file_directory(unshield, index);

    dirname = output_dir;

    if (prefix && prefix[0])
        dirname /= prefix;

    if (directory >= 0)
    {
        const char* tmp = unshield_directory_name(unshield, directory);
        if (tmp && tmp[0])
            fill_path(dirname, tmp);
    }

    make_sure_directory_exists(dirname);

    filename = dirname;
    filename /= unshield_file_name(unshield, index);
  
    emit signalGUI(QString("Extracting: ") + QString(filename.c_str()));
  
    success = unshield_file_save(unshield, index, filename.c_str());

    if (!success)
        bfs::remove(filename);

    return success;
}
Exemplo n.º 2
0
bool unshield_file_save_old(Unshield* unshield, int index, const char* filename)/*{{{*/
{
  /* XXX: Thou Shalt Not Cut & Paste... */
  bool success = false;
  FILE* output = NULL;
  size_t input_buffer_size = BUFFER_SIZE;
  unsigned char* input_buffer   = (unsigned char*)malloc(BUFFER_SIZE);
  unsigned char* output_buffer  = (unsigned char*)malloc(BUFFER_SIZE);
  int bytes_left;
  uLong total_written = 0;
  UnshieldReader* reader = NULL;
  FileDescriptor* file_descriptor;

  if (!unshield)
    goto exit;

  if (!(file_descriptor = unshield_get_file_descriptor(unshield, index)))
  {
    unshield_error("Failed to get file descriptor for file %i", index);
    goto exit;
  }

  if ((file_descriptor->flags & FILE_INVALID) || 0 == file_descriptor->data_offset)
  {
    /* invalid file */
    goto exit;
  }

  if (file_descriptor->link_flags & LINK_PREV)
  {
    success = unshield_file_save(unshield, file_descriptor->link_previous, filename);
    goto exit;
  }

  reader = unshield_reader_create(unshield, index, file_descriptor);
  if (!reader)
  {
    unshield_error("Failed to create data reader for file %i", index);
    goto exit;
  }

  if (unshield_fsize(reader->volume_file) == (long)file_descriptor->data_offset)
  {
    unshield_error("File %i is not inside the cabinet.", index);
    goto exit;
  }

  if (filename) 
  {
    output = fopen(filename, "w");
    if (!output)
    {
      unshield_error("Failed to open output file '%s'", filename);
      goto exit;
    }
  }

  if (file_descriptor->flags & FILE_COMPRESSED)
    bytes_left = file_descriptor->compressed_size;
  else
    bytes_left = file_descriptor->expanded_size;

  /*unshield_trace("Bytes to read: %i", bytes_left);*/

  while (bytes_left > 0)
  {
    uLong bytes_to_write = 0;
    int result;

    if (file_descriptor->flags & FILE_COMPRESSED)
    {
      static const uint8_t END_OF_CHUNK[4] = { 0x00, 0x00, 0xff, 0xff };
      uLong read_bytes;
      size_t input_size = reader->volume_bytes_left;
      uint8_t* chunk_buffer;

      while (input_size > input_buffer_size) 
      {
        input_buffer_size *= 2;
#if VERBOSE >= 3
        unshield_trace("increased input_buffer_size to 0x%x", input_buffer_size);
#endif

        input_buffer = realloc(input_buffer, input_buffer_size);
        assert(input_buffer);
      }

      if (!unshield_reader_read(reader, input_buffer, input_size))
      {
#if VERBOSE
        unshield_error("Failed to read 0x%x bytes of file %i (%s) from input cabinet file %i", 
            input_size, index, unshield_file_name(unshield, index), file_descriptor->volume);
#endif
        goto exit;
      }

      bytes_left -= input_size;

      for (chunk_buffer = input_buffer; input_size; )
      {
        size_t chunk_size;
        uint8_t* match = find_bytes(chunk_buffer, input_size, END_OF_CHUNK, sizeof(END_OF_CHUNK));
        if (!match)
        {
          unshield_error("Could not find end of chunk for file %i (%s) from input cabinet file %i", 
              index, unshield_file_name(unshield, index), file_descriptor->volume);
          goto exit;
        }

        chunk_size = match - chunk_buffer;

        /*
           Detect when the chunk actually contains the end of chunk marker.

           Needed by Qtime.smk from "The Feeble Files - spanish version".

           The first bit of a compressed block is always zero, so we apply this
           workaround if it's a one.

           A possibly more proper fix for this would be to have
           unshield_uncompress_old eat compressed data and discard chunk
           markers inbetween.
           */
        while ((chunk_size + sizeof(END_OF_CHUNK)) < input_size &&
            chunk_buffer[chunk_size + sizeof(END_OF_CHUNK)] & 1)
        {
          unshield_warning("It seems like we have an end of chunk marker inside of a chunk.");
          chunk_size += sizeof(END_OF_CHUNK);
          match = find_bytes(chunk_buffer + chunk_size, input_size - chunk_size, END_OF_CHUNK, sizeof(END_OF_CHUNK));
          if (!match)
          {
            unshield_error("Could not find end of chunk for file %i (%s) from input cabinet file %i",
                index, unshield_file_name(unshield, index), file_descriptor->volume);
            goto exit;
          }
          chunk_size = match - chunk_buffer;
        }

#if VERBOSE >= 3
        unshield_trace("chunk_size = 0x%x", chunk_size);
#endif

        /* add a null byte to make inflate happy */
        chunk_buffer[chunk_size] = 0;

        bytes_to_write = BUFFER_SIZE;
        read_bytes = chunk_size;
        result = unshield_uncompress_old(output_buffer, &bytes_to_write, chunk_buffer, &read_bytes);

        if (Z_OK != result)
        {
          unshield_error("Decompression failed with code %i. input_size=%i, volume_bytes_left=%i, volume=%i, read_bytes=%i", 
              result, input_size, reader->volume_bytes_left, file_descriptor->volume, read_bytes);
          goto exit;
        }

#if VERBOSE >= 3
        unshield_trace("read_bytes = 0x%x", read_bytes);
#endif

        chunk_buffer += chunk_size;
        chunk_buffer += sizeof(END_OF_CHUNK);

        input_size -= chunk_size;
        input_size -= sizeof(END_OF_CHUNK);

        if (output)
          if (bytes_to_write != fwrite(output_buffer, 1, bytes_to_write, output))
          {
            unshield_error("Failed to write %i bytes to file '%s'", bytes_to_write, filename);
            goto exit;
          }

        total_written += bytes_to_write;
      }
    }
    else
    {
      bytes_to_write = MIN(bytes_left, BUFFER_SIZE);

      if (!unshield_reader_read(reader, output_buffer, bytes_to_write))
      {
#if VERBOSE
        unshield_error("Failed to read %i bytes from input cabinet file %i", 
            bytes_to_write, file_descriptor->volume);
#endif
        goto exit;
      }

      bytes_left -= bytes_to_write;

      if (output)
        if (bytes_to_write != fwrite(output_buffer, 1, bytes_to_write, output))
        {
          unshield_error("Failed to write %i bytes to file '%s'", bytes_to_write, filename);
          goto exit;
        }

      total_written += bytes_to_write;
    }
  }

  if (file_descriptor->expanded_size != total_written)
  {
    unshield_error("Expanded size expected to be %i, but was %i", 
        file_descriptor->expanded_size, total_written);
    goto exit;
  }

  success = true;
  
exit:
  unshield_reader_destroy(reader);
  FCLOSE(output);
  FREE(input_buffer);
  FREE(output_buffer);
  return success;
}/*}}}*/
Exemplo n.º 3
0
/*
 * If filename is NULL, just throw away the result
 */
bool unshield_file_save (Unshield* unshield, int index, const char* filename)/*{{{*/
{
  bool success = false;
  FILE* output = NULL;
  unsigned char* input_buffer   = (unsigned char*)malloc(BUFFER_SIZE+1);
  unsigned char* output_buffer  = (unsigned char*)malloc(BUFFER_SIZE);
  int bytes_left;
  uLong total_written = 0;
  UnshieldReader* reader = NULL;
  FileDescriptor* file_descriptor;
	MD5_CTX md5;

	MD5Init(&md5);

  if (!unshield)
    goto exit;

  if (!(file_descriptor = unshield_get_file_descriptor(unshield, index)))
  {
    unshield_error("Failed to get file descriptor for file %i", index);
    goto exit;
  }

  if ((file_descriptor->flags & FILE_INVALID) || 0 == file_descriptor->data_offset)
  {
    /* invalid file */
    goto exit;
  }

  if (file_descriptor->link_flags & LINK_PREV)
  {
    success = unshield_file_save(unshield, file_descriptor->link_previous, filename);
    goto exit;
  }

  reader = unshield_reader_create(unshield, index, file_descriptor);
  if (!reader)
  {
    unshield_error("Failed to create data reader for file %i", index);
    goto exit;
  }

  if (unshield_fsize(reader->volume_file) == (long)file_descriptor->data_offset)
  {
    unshield_error("File %i is not inside the cabinet.", index);
    goto exit;
  }

  if (filename) 
  {
    output = fopen(filename, "w");
    if (!output)
    {
      unshield_error("Failed to open output file '%s'", filename);
      goto exit;
    }
  }

  if (file_descriptor->flags & FILE_COMPRESSED)
    bytes_left = file_descriptor->compressed_size;
  else
    bytes_left = file_descriptor->expanded_size;

  /*unshield_trace("Bytes to read: %i", bytes_left);*/

  while (bytes_left > 0)
  {
    uLong bytes_to_write = BUFFER_SIZE;
    int result;

    if (file_descriptor->flags & FILE_COMPRESSED)
    {
      uLong read_bytes;
      uint16_t bytes_to_read = 0;

      if (!unshield_reader_read(reader, &bytes_to_read, sizeof(bytes_to_read)))
      {
#if VERBOSE
        unshield_error("Failed to read %i bytes of file %i (%s) from input cabinet file %i", 
            sizeof(bytes_to_read), index, unshield_file_name(unshield, index), file_descriptor->volume);
#endif
        goto exit;
      }

      bytes_to_read = letoh16(bytes_to_read);
      if (!unshield_reader_read(reader, input_buffer, bytes_to_read))
      {
#if VERBOSE
        unshield_error("Failed to read %i bytes of file %i (%s) from input cabinet file %i", 
            bytes_to_read, index, unshield_file_name(unshield, index), file_descriptor->volume);
#endif
        goto exit;
      }

      /* add a null byte to make inflate happy */
      input_buffer[bytes_to_read] = 0;
      read_bytes = bytes_to_read+1;
      result = unshield_uncompress(output_buffer, &bytes_to_write, input_buffer, &read_bytes);

      if (Z_OK != result)
      {
        unshield_error("Decompression failed with code %i. bytes_to_read=%i, volume_bytes_left=%i, volume=%i, read_bytes=%i", 
            result, bytes_to_read, reader->volume_bytes_left, file_descriptor->volume, read_bytes);
        goto exit;
      }

#if VERBOSE >= 3
    unshield_trace("read_bytes = %i", 
        read_bytes);
#endif

      bytes_left -= 2;
      bytes_left -= bytes_to_read;
    }
    else
    {
      bytes_to_write = MIN(bytes_left, BUFFER_SIZE);

      if (!unshield_reader_read(reader, output_buffer, bytes_to_write))
      {
#if VERBOSE
        unshield_error("Failed to read %i bytes from input cabinet file %i", 
            bytes_to_write, file_descriptor->volume);
#endif
        goto exit;
      }

      bytes_left -= bytes_to_write;
    }

    MD5Update(&md5, output_buffer, bytes_to_write);

    if (output)
    {
      if (bytes_to_write != fwrite(output_buffer, 1, bytes_to_write, output))
      {
        unshield_error("Failed to write %i bytes to file '%s'", bytes_to_write, filename);
        goto exit;
      }
    }

    total_written += bytes_to_write;
  }

  if (file_descriptor->expanded_size != total_written)
  {
    unshield_error("Expanded size expected to be %i, but was %i", 
        file_descriptor->expanded_size, total_written);
    goto exit;
  }

  if (unshield->header_list->major_version >= 6)
  {
    unsigned char md5result[16];
    MD5Final(md5result, &md5);

    if (0 != memcmp(md5result, file_descriptor->md5, 16))
    {
      unshield_error("MD5 checksum failure for file %i (%s)", 
          index, unshield_file_name(unshield, index));
      goto exit;
    }
  }

  success = true;
  
exit:
  unshield_reader_destroy(reader);
  FCLOSE(output);
  FREE(input_buffer);
  FREE(output_buffer);
  return success;
}/*}}}*/
Exemplo n.º 4
0
static bool unshield_reader_read(UnshieldReader* reader, void* buffer, size_t size)/*{{{*/
{
  bool success = false;
  uint8_t* p = buffer;
  size_t bytes_left = size;

#if VERBOSE >= 3
    unshield_trace("unshield_reader_read start: bytes_left = 0x%x, volume_bytes_left = 0x%x", 
        bytes_left, reader->volume_bytes_left);
#endif

  for (;;)
  {
    /* 
       Read as much as possible from this volume
     */
    size_t bytes_to_read = MIN(bytes_left, reader->volume_bytes_left);

#if VERBOSE >= 3
    unshield_trace("Trying to read 0x%x bytes from offset %08x in volume %i", 
        bytes_to_read, ftell(reader->volume_file), reader->volume);
#endif

    if (bytes_to_read != fread(p, 1, bytes_to_read, reader->volume_file))
    {
      unshield_error("Failed to read 0x%08x bytes of file %i (%s) from volume %i. Current offset = 0x%08x",
          bytes_to_read, reader->index, 
          unshield_file_name(reader->unshield, reader->index), reader->volume,
          ftell(reader->volume_file));
      goto exit;
    }

    bytes_left -= bytes_to_read;
    reader->volume_bytes_left -= bytes_to_read;

#if VERBOSE >= 3
    unshield_trace("bytes_left = %i, volume_bytes_left = %i", 
        bytes_left, reader->volume_bytes_left);
#endif

    if (!bytes_left)
      break;

    p += bytes_to_read;

    /*
       Open next volume
     */

    if (!unshield_reader_open_volume(reader, reader->volume + 1))
    {
      unshield_error("Failed to open volume %i to read %i more bytes",
          reader->volume + 1, bytes_to_read);
      goto exit;
    }
  }

  if (reader->file_descriptor->flags & FILE_OBFUSCATED)
    unshield_reader_deobfuscate(reader, buffer, size);

  success = true;

exit:
  return success;
}/*}}}*/