Beispiel #1
0
static bool backup_original_manifest(void)
{
  unsigned int len, pos = 0;
  char block[BLOCK_SIZE];
  FILE *input, *output;
  bool ret = false;
  struct stat s;

  // No existing manifest; this is non-fatal
  if(stat(MANIFEST_TXT, &s))
  {
    ret = true;
    goto err_out;
  }

  input = fopen_unsafe(MANIFEST_TXT, "rb");
  if(!input)
    goto err_out;

  output = fopen_unsafe(MANIFEST_TXT "~", "wb");
  if(!output)
    goto err_close_input;

  len = (unsigned int)ftell_and_rewind(input);

  while(pos < len)
  {
    unsigned int block_size = MIN(BLOCK_SIZE, len - pos);

    if(fread(block, block_size, 1, input) != 1)
      goto err_close_output;
    if(fwrite(block, block_size, 1, output) != 1)
      goto err_close_output;

    pos += block_size;
  }

  ret = true;
err_close_output:
  fclose(output);
err_close_input:
  fclose(input);
err_out:
  return ret;
}
Beispiel #2
0
static void delete_hook(const char *file)
{
  struct manifest_entry *new_entry;
  struct SHA256_ctx ctx;
  bool ret;
  FILE *f;

  new_entry = ccalloc(1, sizeof(struct manifest_entry));
  if(!new_entry)
    goto err_out;

  if(delete_p)
  {
    delete_p->next = new_entry;
    delete_p = delete_p->next;
  }
  else
    delete_list = delete_p = new_entry;

  delete_p->name = cmalloc(strlen(file) + 1);
  if(!delete_p->name)
    goto err_delete_p;
  strcpy(delete_p->name, file);

  f = fopen_unsafe(file, "rb");
  if(!f)
    goto err_delete_p_name;
  delete_p->size = (unsigned long)ftell_and_rewind(f);

  ret = manifest_compute_sha256(&ctx, f, delete_p->size);
  fclose(f);
  if(!ret)
    goto err_delete_p_name;

  memcpy(delete_p->sha256, ctx.H, sizeof(Uint32) * 8);
  return;

err_delete_p_name:
  free(delete_p->name);
err_delete_p:
  free(delete_p);
  delete_p = NULL;
err_out:
  return;
}
Beispiel #3
0
struct audio_stream *construct_mikmod_stream(char *filename, Uint32 frequency,
 Uint32 volume, Uint32 repeat)
{
  FILE *input_file;
  char *input_buffer;
  Uint32 file_size;
  struct audio_stream *ret_val = NULL;

  input_file = fopen_unsafe(filename, "rb");

  if(input_file)
  {
    MODULE *open_file;

    file_size = ftell_and_rewind(input_file);

    input_buffer = cmalloc(file_size);
    fread(input_buffer, file_size, 1, input_file);
    open_file = MikMod_LoadSongRW(SDL_RWFromMem(input_buffer, file_size), 64);

    if(open_file)
    {
      struct mikmod_stream *mm_stream = cmalloc(sizeof(struct mikmod_stream));
      mm_stream->module_data = open_file;
      Player_Start(mm_stream->module_data);

      initialize_sampled_stream((struct sampled_stream *)mm_stream,
       mm_set_frequency, mm_get_frequency, frequency, 2, 0);

      ret_val = (struct audio_stream *)mm_stream;

      construct_audio_stream((struct audio_stream *)mm_stream,
       mm_mix_data, mm_set_volume, mm_set_repeat, mm_set_order,
       mm_set_position, mm_get_order, mm_get_position, mm_destruct,
       volume, repeat);
    }

    fclose(input_file);
    free(input_buffer);
  }

  return ret_val;
}
Beispiel #4
0
bool manifest_entry_check_validity(struct manifest_entry *e, FILE *f)
{
  unsigned long len = e->size;
  struct SHA256_ctx ctx;

  // It must be the same length
  if((unsigned long)ftell_and_rewind(f) != len)
    return false;

  /* Compute the SHA256 digest for this file. Do it block-wise so as to
   * conserve RAM and scale to enormously large files.
   */
  if(!manifest_compute_sha256(&ctx, f, len))
    return false;

  // Verify the digest against the manifest
  if(memcmp(ctx.H, e->sha256, sizeof(Uint32) * 8) != 0)
    return false;

  return true;
}
Beispiel #5
0
enum host_status host_send_file(struct host *h, FILE *file,
 const char *mime_type)
{
  boolean mid_deflate = false;
  char line[LINE_BUF_LEN];
  uint32_t crc, uSize;
  z_stream stream;
  long size;

  // Tell the client that we're going to use HTTP/1.1 features
  if(http_send_line(h, "HTTP/1.1 200 OK") < 0)
    return -HOST_SEND_FAILED;

  /* To bring ourselves into complete HTTP 1.1 compliance, send
   * some headers that we know our client doesn't actually need.
   */
  if(http_send_line(h, "Accept-Ranges: bytes") < 0)
    return -HOST_SEND_FAILED;
  if(http_send_line(h, "Vary: Accept-Encoding") < 0)
    return -HOST_SEND_FAILED;

  // Always zlib deflate content; keeps code simple
  if(http_send_line(h, "Content-Encoding: gzip") < 0)
    return -HOST_SEND_FAILED;

  // We'll just send everything chunked, unconditionally
  if(http_send_line(h, "Transfer-Encoding: chunked") < 0)
    return -HOST_SEND_FAILED;

  // Pass along a type hint for the client (mandatory sanity check for MZX)
  snprintf(line, LINE_BUF_LEN, "Content-Type: %s", mime_type);
  line[LINE_BUF_LEN - 1] = 0;
  if(http_send_line(h, line) < 0)
    return -HOST_SEND_FAILED;

  // Terminate the headers with a blank line
  if(http_send_line(h, "") < 0)
    return -HOST_SEND_FAILED;

  // Initialize CRC for GZIP footer
  crc = crc32(0L, Z_NULL, 0);

  // Record uncompressed size for GZIP footer
  size = ftell_and_rewind(file);
  uSize = (uint32_t)size;
  if(size < 0)
    return -HOST_FREAD_FAILED;

  while(true)
  {
    int deflate_offset = 0, ret = Z_OK, deflate_flag = Z_SYNC_FLUSH;
    char block[BLOCK_SIZE], zblock[BLOCK_SIZE];
    size_t block_size;

    /* Read a block from the disk source and compute a CRC32 on the
     * fly. This CRC will be dumped at the end of the deflated data
     * and is required for RFC 1952 compliancy.
     */
    block_size = fread(block, 1, BLOCK_SIZE, file);
    crc = crc32(crc, (Bytef *)block, block_size);

    /* The fread() above pretty much guarantees that block_size will
     * be BLOCK_SIZE up to the final block. However, fread() also
     * returns a short count if there was an I/O error, and we must
     * detect this. If it's legitimately the final block, give the
     * compressor this information.
     */
    if(block_size != BLOCK_SIZE)
    {
      if(!feof(file))
        return -HOST_FREAD_FAILED;
      deflate_flag = Z_FINISH;
    }

    /* We exhausted input at a block boundary. This is unlikely,
     * but in the event that it happens we can simply ignore
     * the deflate stage and write out the terminal chunk signature.
     */
    if(block_size == 0)
      break;

    /* Regardless of whether we are initializing the compressor in
     * the next section or not, we always have BLOCK_SIZE aligned
     * input data available.
     */
    stream.avail_in = block_size;
    stream.next_in = (Bytef *)block;

    if(!mid_deflate)
    {
      deflate_offset = zlib_forge_gzip_header(zblock);

      stream.avail_out = BLOCK_SIZE - (unsigned long)deflate_offset;
      stream.next_out = (Bytef *)&zblock[deflate_offset];
      stream.zalloc = Z_NULL;
      stream.zfree = Z_NULL;
      stream.opaque = Z_NULL;

      ret = deflateInit2(&stream, Z_BEST_COMPRESSION,
       Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
      if(ret != Z_OK)
        return -HOST_ZLIB_DEFLATE_FAILED;

      mid_deflate = true;
    }
    else
    {
      stream.avail_out = BLOCK_SIZE;
      stream.next_out = (Bytef *)zblock;
    }

    while(true)
    {
      unsigned long chunk_size;

      // Deflate a chunk of the input (partially or fully)
      ret = deflate(&stream, deflate_flag);
      if(ret != Z_OK && ret != Z_STREAM_END)
        return -HOST_ZLIB_INFLATE_FAILED;

      // Compute chunk length (final chunk includes GZIP footer)
      chunk_size = BLOCK_SIZE - stream.avail_out;
      if(ret == Z_STREAM_END)
        chunk_size += 2 * sizeof(uint32_t);

      // Dump compressed chunk length
      snprintf(line, LINE_BUF_LEN, "%lx", chunk_size);
      if(http_send_line(h, line) < 0)
        return -HOST_SEND_FAILED;

      // Send the compressed output block over the socket
      if(!__send(h, zblock, BLOCK_SIZE - stream.avail_out))
        return -HOST_SEND_FAILED;

      /* We might not have finished the entire stream, but the
       * available input is likely to have been exhausted. With
       * Z_SYNC_FLUSH this will commonly result in zero bytes
       * remaining in the input source. Additionally, if this is
       * the final chunk (and Z_FINISH was flagged), Z_STREAM_END
       * will be set. In either case, we must break out.
       */
      if((ret == Z_OK && stream.avail_in == 0) || ret == Z_STREAM_END)
        break;

      // Output has been flushed; start over for the remaining input (if any)
      stream.avail_out = BLOCK_SIZE;
      stream.next_out = (Bytef *)zblock;
    }

    /* Z_FINISH was flagged, stream ended
     * Terminate compression
     */
    if(ret == Z_STREAM_END)
    {
      // Free any zlib allocated resources
      deflateEnd(&stream);

      // Write out GZIP `CRC32' footer
      if(!__send(h, &crc, sizeof(uint32_t)))
        return -HOST_SEND_FAILED;

      // Write out GZIP `ISIZE' footer
      if(!__send(h, &uSize, sizeof(uint32_t)))
        return -HOST_SEND_FAILED;

      mid_deflate = false;
    }

    // Newline after chunk's data
    if(http_send_line(h, "") < 0)
      return -HOST_SEND_FAILED;

    // Final block; can break out
    if(block_size != BLOCK_SIZE)
      break;
  }

  // Terminal chunk signature, so called "trailer"
  if(http_send_line(h, "0") < 0)
    return -HOST_SEND_FAILED;

  // Post-trailer newline
  if(http_send_line(h, "") < 0)
    return -HOST_SEND_FAILED;

  return HOST_SUCCESS;
}
Beispiel #6
0
static void decrypt(const char *file_name)
{
  FILE *source;
  FILE *dest;
  int file_length;
  int pro_method;
  int i;
  int len;
  char num_boards;
  char offset_low_byte;
  char xor_val;
  char password[15];
  char *file_buffer;
  char *src_ptr;

  int meter_target, meter_curr = 0;

  source = fopen(file_name, "rb");
  file_length = ftell_and_rewind(source);

  meter_target = file_length + (file_length - 15) + 4;
 
  meter_initial_draw(meter_curr, meter_target, "Decrypting...");

  file_buffer = cmalloc(file_length);
  src_ptr = file_buffer;
  fread(file_buffer, file_length, 1, source);
  fclose(source);

  meter_curr = file_length - 1;
  meter_update_screen(&meter_curr, meter_target);

  src_ptr += 25;

  dest = fopen(file_name, "wb");
  if(!dest)
  {
    error("Cannot decrypt write-protected world.", 1, 8, 0x0DD5);
    return;
  }
  pro_method = *src_ptr;
  src_ptr++;

  // Get password
  memcpy(password, src_ptr, 15);
  src_ptr += 18;
  // First, normalize password...
  for(i = 0; i < 15; i++)
  {
    password[i] ^= magic_code[i];
    password[i] -= 0x12 + pro_method;
    password[i] ^= 0x8D;
  }

  // Xor code
  xor_val = get_pw_xor_code(password, pro_method);

  // Copy title
  fwrite(file_buffer, 25, 1, dest);
  fputc(0, dest);
  fputs("M\x02\x11", dest);

  meter_curr += 25 + 1 + 3 - 1;
  meter_update_screen(&meter_curr, meter_target);

  len = file_length - 44;
  for(; len > 0; len--)
  {
    fputc((*src_ptr) ^ xor_val, dest);
    src_ptr++;

    if((len % 1000) == 0)
    {
      meter_curr += 999;
      meter_update_screen(&meter_curr, meter_target);
    }
  }

  meter_curr = file_length + (file_length - 15) - 1;
  meter_update_screen(&meter_curr, meter_target);

  // Must fix all the absolute file positions so that they're 15
  // less now
  src_ptr = file_buffer + 4245;
  fseek(dest, 4230, SEEK_SET);
  offset_low_byte = src_ptr[0] ^ xor_val;
  fputc(offset_low_byte - 15, dest);
  if(offset_low_byte < 15)
  {
    fputc((src_ptr[1] ^ xor_val) - 1, dest);
  }
  else
  {
    fputc(src_ptr[1] ^ xor_val, dest);
  }

  fputc(src_ptr[2] ^ xor_val, dest);
  fputc(src_ptr[3] ^ xor_val, dest);

  meter_curr += 4 - 1;
  meter_update_screen(&meter_curr, meter_target);

  src_ptr += 4;

  num_boards = ((*src_ptr) ^ xor_val);
  src_ptr++;

  // If custom SFX is there, run through and skip it
  if(!num_boards)
  {
    int sfx_length = (char)(src_ptr[0] ^ xor_val);
    sfx_length |= ((char)(src_ptr[1] ^ xor_val)) << 8;
    src_ptr += sfx_length + 2;
    num_boards = (*src_ptr) ^ xor_val;
    src_ptr++;
  }

  meter_target += num_boards * 4;
  meter_curr--;
  meter_update_screen(&meter_curr, meter_target);

  // Skip titles
  src_ptr += (25 * num_boards);
  // Synchronize source and dest positions
  fseek(dest, (long)(src_ptr - file_buffer - 15), SEEK_SET);

  // Offset boards
  for(i = 0; i < num_boards; i++)
  {
    // Skip length
    src_ptr += 4;
    fseek(dest, 4, SEEK_CUR);

    // Get offset
    offset_low_byte = src_ptr[0] ^ xor_val;
    fputc(offset_low_byte - 15, dest);
    if(offset_low_byte < 15)
    {
      fputc((src_ptr[1] ^ xor_val) - 1, dest);
    }
    else
    {
      fputc(src_ptr[1] ^ xor_val, dest);
    }
    fputc(src_ptr[2] ^ xor_val, dest);
    fputc(src_ptr[3] ^ xor_val, dest);
    src_ptr += 4;

    meter_target += 4 - 1;
    meter_update_screen(&meter_curr, meter_target);
  }

  free(file_buffer);
  fclose(dest);

  meter_restore_screen();
}