예제 #1
0
파일: manifest.c 프로젝트: MrAlert/megazeux
bool manifest_entry_download_replace(struct host *h, const char *basedir,
 struct manifest_entry *e, void (*delete_hook)(const char *file))
{
  char buf[LINE_BUF_LEN];
  enum host_status ret;
  bool valid = false;
  FILE *f;

  /* Try to open our target file. If we can't open it, it might be
   * write protected or in-use. In this case, it may be possible to
   * rename the original file out of the way. Try this trick first.
   */
  f = fopen_unsafe(e->name, "w+b");
  if(!f)
  {
    snprintf(buf, LINE_BUF_LEN, "%s~", e->name);
    if(rename(e->name, buf))
    {
      warn("Failed to rename in-use file '%s' to '%s'\n", e->name, buf);
      goto err_out;
    }

    if(delete_hook)
      delete_hook(buf);

    f = fopen_unsafe(e->name, "w+b");
    if(!f)
    {
      warn("Unable to open file '%s' for writing\n", e->name);
      goto err_out;
    }
  }

  snprintf(buf, LINE_BUF_LEN, "%s/%08x%08x%08x%08x%08x%08x%08x%08x", basedir,
    e->sha256[0], e->sha256[1], e->sha256[2], e->sha256[3],
    e->sha256[4], e->sha256[5], e->sha256[6], e->sha256[7]);

  ret = host_recv_file(h, buf, f, "application/octet-stream");
  if(ret != HOST_SUCCESS)
  {
    warn("File '%s' could not be downloaded (error %d)\n", e->name, ret);
    goto err_close;
  }

  rewind(f);
  if(!manifest_entry_check_validity(e, f))
  {
    warn("File '%s' failed validation\n", e->name);
    goto err_close;
  }

  valid = true;
err_close:
  fclose(f);
err_out:
  return valid;
}
예제 #2
0
bool updater_init(char *argv[])
{
  struct manifest_entry *e;
  bool ret;
  FILE *f;

  process_argv = argv;

  if(!swivel_current_dir(false))
    return false;

  check_for_updates = __check_for_updates;

  f = fopen_unsafe(DELETE_TXT, "rb");
  if(!f)
    goto err_swivel_back;

  delete_list = manifest_list_create(f);
  fclose(f);

  for(e = delete_list; e; e = e->next)
  {
    f = fopen_unsafe(e->name, "rb");
    if(!f)
      continue;

    ret = manifest_entry_check_validity(e, f);
    fclose(f);

    if(!ret)
      continue;

    if(unlink(e->name))
      continue;

    /* Obtain the path for this file. If the file isn't at the top
     * level, and the directory is empty (rmdir ensures this)
     * the directory will be pruned.
     */
    check_prune_basedir(e->name);
  }

  manifest_list_free(&delete_list);
  unlink(DELETE_TXT);

err_swivel_back:
  swivel_current_dir_back(false);
  return true;
}
예제 #3
0
void COutputBuffer::Flush()
{
    FILE* fp;

    if (_type == OUT_FILE) {
        Flush(_pfile);
    }
    else {
        ASSERTNR(_type == OUT_FILENAME);
        if (_filename != NULL) {
            fp = fopen_unsafe(_filename, "a");
            if (fp == NULL) {
                // We might not be able to open the log or full log output
                // files because someone is grepping or otherwise looking
                // through them while rl is active. In that case, we don't
                // want to just kill rl, so just keep accumulating output
                // and try again next time. Output a warning to the log so
                // they know it happened (but they won't see it unless the
                // output is flushed). We could consider having a maximum,
                // after which we "turn off" this output buffer, but we're
                // unlikely to ever have so much output that it causes a
                // problem.

                Warning("Cannot open '%s' for appending with error '%s'", _filename, strerror_unsafe(errno));
            }
            else {
                Flush(fp);
                fclose(fp);
            }
        }
    }
}
예제 #4
0
파일: mzm.c 프로젝트: colin-branch/megazeux
int load_mzm(struct world *mzx_world, char *name, int start_x, int start_y,
 int mode, int savegame)
{
  FILE *input_file;
  size_t file_size;
  void *buffer;
  int success;
  input_file = fopen_unsafe(name, "rb");
  if(input_file)
  {
    fseek(input_file, 0, SEEK_END);
    file_size = ftell(input_file);
    buffer = cmalloc(file_size);
    fseek(input_file, 0, SEEK_SET);
    fread(buffer, file_size, 1, input_file);
    fclose(input_file);

    success = load_mzm_common(mzx_world, buffer, (int)file_size, start_x, start_y, mode, savegame, name);
    free(buffer);
    return success;
  } else {
    error_message(E_MZM_DOES_NOT_EXIST, 0, name);
    return -1;
  }
}
예제 #5
0
파일: board.c 프로젝트: AliceLR/megazeux
void save_board_file(struct world *mzx_world, struct board *cur_board,
 char *name)
{
  FILE *fp = fopen_unsafe(name, "wb");
  struct zip_archive *zp;
  boolean success = false;

  if(fp)
  {
    fputc(0xFF, fp);

    fputc('M', fp);
    fputc((MZX_VERSION >> 8) & 0xFF, fp);
    fputc(MZX_VERSION & 0xFF, fp);

    zp = zip_open_fp_write(fp);

    if(zp)
    {
      if(!save_board(mzx_world, cur_board, zp, 0, MZX_VERSION, 0))
        success = true;

      zip_close(zp, NULL);
    }
    else
      fclose(fp);
  }

  if(!success)
    error_message(E_WORLD_IO_SAVING, 0, NULL);
}
예제 #6
0
파일: manifest.c 프로젝트: MrAlert/megazeux
static struct manifest_entry *manifest_get_remote(struct host *h,
 const char *base)
{
  struct manifest_entry *manifest = NULL;
  char url[LINE_BUF_LEN];
  enum host_status ret;
  FILE *f;

  snprintf(url, LINE_BUF_LEN, "%s/" MANIFEST_TXT, base);

  f = fopen_unsafe(MANIFEST_TXT, "w+b");
  if(!f)
  {
    warn("Failed to open local " MANIFEST_TXT " for writing\n");
    goto err_out;
  }

  ret = host_recv_file(h, url, f, "text/plain");
  if(ret != HOST_SUCCESS)
  {
    warn("Processing " MANIFEST_TXT " failed (error %d)\n", ret);
    goto err_fclose;
  }

  rewind(f);
  manifest = manifest_list_create(f);

err_fclose:
  fclose(f);
err_out:
  return manifest;
}
예제 #7
0
파일: helpsys.c 프로젝트: MrAlert/megazeux
void help_open(struct world *mzx_world, const char *file_name)
{
  mzx_world->help_file = fopen_unsafe(file_name, "rb");
  if(!mzx_world->help_file)
    return;

  help = cmalloc(1024 * 64);
}
예제 #8
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;
}
예제 #9
0
파일: mzm.c 프로젝트: colin-branch/megazeux
void save_mzm(struct world *mzx_world, char *name, int start_x, int start_y,
 int width, int height, int mode, int savegame)
{
  FILE *output_file = fopen_unsafe(name, "wb");
  size_t *buffer;
  size_t length;
  if(output_file)
  {
    buffer = NULL;
    save_mzm_common(mzx_world, start_x, start_y, width, height, mode, savegame, mem_allocate, (void **)(&buffer));
    length = buffer[0];
    fwrite(&buffer[1], length, 1, output_file);
    free(buffer);
    fclose(output_file);
  }
}
예제 #10
0
파일: manifest.c 프로젝트: MrAlert/megazeux
static struct manifest_entry *manifest_get_local(void)
{
  struct manifest_entry *manifest;
  FILE *f;

  f = fopen_unsafe(MANIFEST_TXT, "rb");
  if(!f)
  {
    warn("Local " MANIFEST_TXT " is missing\n");
    return NULL;
  }

  manifest = manifest_list_create(f);
  fclose(f);

  return manifest;
}
예제 #11
0
BOOL
    CheckForPass(char * filename, char * optReportBuf, char * cmdbuf, BOOL fDumpOutputFile = TRUE)
{
    FILE * fp;
    char buf[BUFFER_SIZE];

    // Check to see if the exe ran at all.

    fp = fopen_unsafe(filename, "r");
    if (fp == NULL) {
        LogOut("ERROR: Test failed to run. Unable to open file '%s', error '%s' (%s):", filename, strerror_unsafe(errno), optReportBuf);
        LogOut("    %s", cmdbuf);
        return FALSE;
    }

    // Parse the output file and verify that all lines must be pass/passed, or empty lines
    BOOL pass = FALSE;
    while(fgets(buf, BUFFER_SIZE, fp) != NULL)
    {
        if(!_strcmpi(buf, "pass\n") || !_strcmpi(buf, "passed\n"))
        {
            // Passing strings were found - pass
            pass = TRUE;
        }
        else if(_strcmpi(buf, "\n") != 0)
        {
            // Something else other than a newline was found - this is a failure.
            pass = FALSE;
            break;
        }
    }

    fclose(fp);

    if (!pass)
    {
        LogOut("ERROR: Test failed to run correctly: pass not found in output file (%s):", optReportBuf);
        LogOut("    %s", cmdbuf);
        if (fDumpOutputFile)
        {
            DumpFileToLog(filename);
        }
    }

    return pass;
}
예제 #12
0
FILE * val_fopen(const char *filename)
{
  struct stat stat_result;
  int stat_op_result = stat(filename, &stat_result);
  FILE *f;

  if(stat_op_result)
    return NULL;

  if(!S_ISREG(stat_result.st_mode))
    return NULL;

  if(!(f = fopen_unsafe(filename, "rb")))
    return NULL;

  return f;
}
예제 #13
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;
}
예제 #14
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;
}
예제 #15
0
파일: manifest.c 프로젝트: MrAlert/megazeux
static void manifest_add_list_validate_augment(struct manifest_entry *local,
 struct manifest_entry **added)
{
  struct manifest_entry *e, *a = *added;

  // Scan along to penultimate `added' (if we have any)
  if(a)
    while(a->next)
      a = a->next;

  for(e = local; e; e = e->next)
  {
    struct manifest_entry *new_added;
    FILE *f;

    f = fopen_unsafe(e->name, "rb");
    if(f)
    {
      if(manifest_entry_check_validity(e, f))
      {
        fclose(f);
        continue;
      }
      fclose(f);
    }

    warn("Local file '%s' failed manifest validation\n", e->name);

    new_added = manifest_entry_copy(e);
    if(*added)
    {
      a->next = new_added;
      a = a->next;
    }
    else
      a = *added = new_added;
  }
}
예제 #16
0
파일: downver.c 프로젝트: mdsherry/megazeux
int main(int argc, char *argv[])
{
  int world, byte;
  long ext_pos;
  FILE *fp;

  if(argc <= 1)
  {
    error("Usage: %s [mzx/mzb file]\n", argv[0]);
    goto exit_out;
  }

  ext_pos = strlen(argv[1]) - 4;
  if(ext_pos < 0)
  {
    error("File '%s' of an unknown type.\n", argv[1]);
    goto exit_out;
  }

  if(!strcasecmp(argv[1] + ext_pos, ".mzb"))
  {
    world = false;
  }
  else if(!strcasecmp(argv[1] + ext_pos, ".mzx"))
  {
    world = true;
  }
  else
  {
    error("Unknown extension '%s'.\n", argv[1] + ext_pos);
    goto exit_out;
  }

  fp = fopen_unsafe(argv[1], "r+b");
  if(!fp)
  {
    error("Could not open '%s' for read/write.\n", argv[1]);
    goto exit_out;
  }

  /* World files need some crap at the beginning skipped. Also, world files
   * can theoretically be encrypted, though practically this will not happen
   * with modern worlds. Just in case, check for it and abort.
   *
   * Board files just need the 0xFF byte at the start skipping.
   */
  if(world)
  {
    char name[BOARD_NAME_SIZE];
    size_t fret;

    // Last selected board name; junked, we simply don't care
    fret = fread(name, BOARD_NAME_SIZE, 1, fp);
    if(fret != 1)
      goto err_read;

    // Check protection isn't enabled
    byte = fgetc(fp);
    if(byte < 0)
      goto err_read;
    else if(byte != 0)
    {
      error("Protected worlds are not supported.\n");
      goto exit_close;
    }
  }
  else
  {
    byte = fgetc(fp);
    if(byte < 0)
      goto err_read;
    else if(byte != 0xff)
      error("Board file is corrupt or unsupported.\n");
  }

  // Validate version is current

  byte = fgetc(fp);
  if(byte < 0)
    goto err_read;
  else if(byte != 'M')
  {
    error("World file is corrupt or unsupported.\n");
    goto exit_close;
  }

  byte = fgetc(fp);
  if(byte < 0)
    goto err_read;
  else if(byte != WORLD_VERSION_HI)
  {
    error("This tool only supports worlds or boards from %d.%d.\n",
     WORLD_VERSION_HI, WORLD_VERSION_LO);
    goto exit_close;
  }

  byte = fgetc(fp);
  if(byte < 0)
    goto err_read;
  else if(byte != WORLD_VERSION_LO)
  {
    error("This tool only supports worlds or boards from %d.%d.\n",
     WORLD_VERSION_HI, WORLD_VERSION_LO);
    goto exit_close;
  }

  // Re-write current magic with previous version's magic

  if(fseek(fp, -2, SEEK_CUR) != 0)
    goto err_seek;

  byte = fputc(WORLD_VERSION_PREV_HI, fp);
  if(byte == EOF)
    goto err_write;

  byte = fputc(WORLD_VERSION_PREV_LO, fp);
  if(byte == EOF)
    goto err_write;

#if WORLD_VERSION == 0x0254
  {
    enum status ret;

    if(world)
      ret = convert_284_to_283(fp);
    else
      ret = convert_284_to_283_board(fp, NULL);

    switch(ret)
    {
      case SEEK_ERROR:  goto err_seek;
      case READ_ERROR:  goto err_read;
      case WRITE_ERROR: goto err_write;
      case SUCCESS:     break;
    }
  }
#endif

  fprintf(stdout, "File '%s' successfully downgraded from %d.%d to %d.%d.\n",
   argv[1], WORLD_VERSION_HI, WORLD_VERSION_LO,
   WORLD_VERSION_PREV_HI, WORLD_VERSION_PREV_LO);

exit_close:
  fclose(fp);
exit_out:
  return 0;

err_seek:
  error("Seek error, aborting.\n");
  goto exit_close;

err_read:
  error("Read error, aborting.\n");
  goto exit_close;

err_write:
  error("Write error, aborting.\n");
  goto exit_close;
}
예제 #17
0
파일: board.c 프로젝트: AliceLR/megazeux
void replace_current_board(struct world *mzx_world, char *name)
{
  int current_board_id = mzx_world->current_board_id;
  struct board *src_board = mzx_world->current_board;

  FILE *fp = fopen_unsafe(name, "rb");
  struct zip_archive *zp;

  char version_string[4];
  int file_version;
  int success = 0;

  if(fp)
  {
    if(!fread(version_string, 4, 1, fp))
    {
      error_message(E_IO_READ, 0, NULL);
      fclose(fp);
      return;
    }

    file_version = board_magic(version_string);

    if(file_version > 0 && file_version <= MZX_LEGACY_FORMAT_VERSION)
    {
      // Legacy board.
      clear_board(src_board);

      src_board =
       legacy_load_board_allocate_direct(mzx_world, fp, file_version);

      success = 1;
      fclose(fp);
    }
    else

    if(file_version <= MZX_VERSION)
    {
      int board_id;

      // Regular board or maybe not a board at all.
      zp = zip_open_fp_read(fp);

      // Make sure it's an actual zip.
      if(zp)
      {
        // Make sure the zip contains a board.
        board_id = find_first_board(zp);

        if(board_id >= 0)
        {
          clear_board(src_board);

          src_board =
           load_board_allocate(mzx_world, zp, 0, file_version, board_id);

          success = 1;
        }
      }

      if(!success)
        error_message(E_BOARD_FILE_INVALID, 0, NULL);

      zip_close(zp, NULL);
    }

    else
    {
      error_message(E_BOARD_FILE_FUTURE_VERSION, file_version, NULL);
      fclose(fp);
    }

    if(success)
    {
      // Set up the newly allocated board.
      optimize_null_objects(src_board);

      if(src_board->robot_list)
        src_board->robot_list[0] = &mzx_world->global_robot;

      set_update_done_current(mzx_world);

      set_current_board(mzx_world, src_board);
      mzx_world->board_list[current_board_id] = src_board;
    }
  }
}
예제 #18
0
static void __check_for_updates(struct world *mzx_world, struct config_info *conf)
{
  int cur_host;
  char *update_host;
  bool try_next_host = true;
  bool ret = false;

  set_context(CTX_UPDATER);

  if(conf->update_host_count < 1)
  {
    error("No updater hosts defined! Aborting.", 1, 8, 0);
    goto err_out;
  }

  if(!swivel_current_dir(true))
    goto err_out;

  for(cur_host = 0; (cur_host < conf->update_host_count) && try_next_host; cur_host++)
  {
    char **list_entries, buffer[LINE_BUF_LEN], *url_base, *value;
    struct manifest_entry *removed, *replaced, *added, *e;
    int i = 0, entries = 0, buf_len, result;
    char update_branch[LINE_BUF_LEN];
    const char *version = VERSION;
    int list_entry_width = 0;
    enum host_status status;
    struct host *h = NULL;
    unsigned int retries;
    FILE *f;

    // Acid test: Can we write to this directory?
    f = fopen_unsafe(UPDATES_TXT, "w+b");
    if(!f)
    {
      error("Failed to create \"" UPDATES_TXT "\". Check permissions.", 1, 8, 0);
      goto err_chdir;
    }

    update_host = conf->update_hosts[cur_host];

    if(!reissue_connection(conf, &h, update_host))
      goto err_host_destroy;

    for(retries = 0; retries < MAX_RETRIES; retries++)
    {
      // Grab the file containing the names of the current Stable and Unstable
      status = host_recv_file(h, "/" UPDATES_TXT, f, "text/plain");
      rewind(f);

      if(status == HOST_SUCCESS)
        break;

      if(!reissue_connection(conf, &h, update_host))
        goto err_host_destroy;
    }

    if(retries == MAX_RETRIES)
    {
      snprintf(widget_buf, WIDGET_BUF_LEN, "Failed to download \""
       UPDATES_TXT "\" (err=%d).\n", status);
      widget_buf[WIDGET_BUF_LEN - 1] = 0;
      error(widget_buf, 1, 8, 0);
      goto err_host_destroy;
    }

    snprintf(update_branch, LINE_BUF_LEN, "Current-%s",
     conf->update_branch_pin);

    // Walk this list (of two, hopefully)
    while(true)
    {
      char *m = buffer, *key;
      value = NULL;

      // Grab a single line from the manifest
      if(!fgets(buffer, LINE_BUF_LEN, f))
        break;

      key = strsep(&m, ":\n");
      if(!key)
        break;

      value = strsep(&m, ":\n");
      if(!value)
        break;

      if(strcmp(key, update_branch) == 0)
        break;
    }

    fclose(f);
    unlink(UPDATES_TXT);

    /* There was no "Current-XXX: Version" found; we cannot proceed with the
     * update because we cannot compute an update URL below.
     */
    if(!value)
    {
      error("Failed to identify applicable update version.", 1, 8, 0);
      goto err_host_destroy;
    }

    /* There's likely to be a space prepended to the version number.
     * Skip it here.
     */
    if(value[0] == ' ')
      value++;

    /* We found the latest update version, but we should check to see if that
     * matches the version we're already using. The user may choose to receive
     * "stability" updates for their current major version, or upgrade to the
     * newest one.
     */
    if(strcmp(value, version) != 0)
    {
      struct element *elements[6];
      struct dialog di;

      buf_len = snprintf(widget_buf, WIDGET_BUF_LEN,
       "A new major version is available (%s)", value);
      widget_buf[WIDGET_BUF_LEN - 1] = 0;

      elements[0] = construct_label((55 - buf_len) >> 1, 2, widget_buf);

      elements[1] = construct_label(2, 4,
       "You can continue to receive updates for the version\n"
       "installed (if available), or you can upgrade to the\n"
       "newest major version (recommended).");

      elements[2] = construct_label(2, 8,
       "If you do not upgrade, this question will be asked\n"
       "again the next time you run the updater.\n");

      elements[3] = construct_button(9, 11, "Upgrade", 0);
      elements[4] = construct_button(21, 11, "Update Old", 1);
      elements[5] = construct_button(36, 11, "Cancel", 2);

      construct_dialog(&di, "New Major Version", 11, 6, 55, 14, elements, 6, 3);
      result = run_dialog(mzx_world, &di);
      destruct_dialog(&di);

      // User pressed Escape, abort all updates
      if(result < 0 || result == 2)
      {
        try_next_host = false;
        goto err_host_destroy;
      }

      // User pressed Upgrade, use new major
      if(result == 0)
        version = value;
    }

    /* We can now compute a unique URL base for the updater. This will
     * be composed of a user-selected version and a static platform-archicture
     * name.
     */
    url_base = cmalloc(LINE_BUF_LEN);
    snprintf(url_base, LINE_BUF_LEN, "/%s/" PLATFORM, version);
    debug("Update base URL: %s\n", url_base);

    /* The call to manifest_get_updates() destroys any existing manifest
     * file in this directory. Since we still allow user to abort after
     * this call, and downloading the updates may fail, we copy the
     * old manifest to a backup location and optionally restore it later.
     */
    if(!backup_original_manifest())
    {
      error("Failed to back up manifest. Check permissions.", 1, 8, 0);
      try_next_host = false;
      goto err_free_url_base;
    }

    for(retries = 0; retries < MAX_RETRIES; retries++)
    {
      bool m_ret;

      m_hide();

      draw_window_box(3, 11, 76, 13, DI_MAIN, DI_DARK, DI_CORNER, 1, 1);
      write_string("Computing manifest deltas (added, replaced, deleted)..",
       13, 12, DI_TEXT, 0);
      update_screen();

      m_ret = manifest_get_updates(h, url_base, &removed, &replaced, &added);

      clear_screen(32, 7);
      m_show();
      update_screen();

      if(m_ret)
        break;

      if(!reissue_connection(conf, &h, update_host))
        goto err_roll_back_manifest;
    }

    if(retries == MAX_RETRIES)
    {
      error("Failed to compute update manifests", 1, 8, 0);
      goto err_roll_back_manifest;
    }

    // At this point, we have a successful manifest, so we won't need another host
    try_next_host = false;

    if(!removed && !replaced && !added)
    {
      struct element *elements[3];
      struct dialog di;

      elements[0] = construct_label(2, 2, "This client is already current.");
      elements[1] = construct_button(7, 4, "OK", 0);
      elements[2] = construct_button(13, 4, "Try next host", 1);

      construct_dialog(&di, "No Updates", 22, 9, 35, 6, elements, 3, 1);
      result = run_dialog(mzx_world, &di);
      destruct_dialog(&di);

      if((result == 1) && (cur_host < conf->update_host_count))
        try_next_host = true;

      goto err_free_update_manifests;
    }

    for(e = removed; e; e = e->next, entries++)
      list_entry_width = MAX(list_entry_width, 2 + (int)strlen(e->name)+1+1);
    for(e = replaced; e; e = e->next, entries++)
      list_entry_width = MAX(list_entry_width, 2 + (int)strlen(e->name)+1+1);
    for(e = added; e; e = e->next, entries++)
      list_entry_width = MAX(list_entry_width, 2 + (int)strlen(e->name)+1+1);

    // We don't want the listbox to be too wide
    list_entry_width = MIN(list_entry_width, 60);

    list_entries = cmalloc(entries * sizeof(char *));

    for(e = removed; e; e = e->next, i++)
    {
      list_entries[i] = cmalloc(list_entry_width);
      snprintf(list_entries[i], list_entry_width, "- %s", e->name);
      list_entries[i][list_entry_width - 1] = 0;
    }

    for(e = replaced; e; e = e->next, i++)
    {
      list_entries[i] = cmalloc(list_entry_width);
      snprintf(list_entries[i], list_entry_width, "* %s", e->name);
      list_entries[i][list_entry_width - 1] = 0;
    }

    for(e = added; e; e = e->next, i++)
    {
      list_entries[i] = cmalloc(list_entry_width);
      snprintf(list_entries[i], list_entry_width, "+ %s", e->name);
      list_entries[i][list_entry_width - 1] = 0;
    }

    draw_window_box(19, 1, 59, 4, DI_MAIN, DI_DARK, DI_CORNER, 1, 1);
    write_string(" Task Summary ", 33, 1, DI_TITLE, 0);
    write_string("ESC   - Cancel   [+] Add   [-] Delete", 21, 2, DI_TEXT, 0);
    write_string("ENTER - Proceed  [*] Replace  ", 21, 3, DI_TEXT, 0);

    result = list_menu((const char **)list_entries, list_entry_width,
     NULL, 0, entries, ((80 - (list_entry_width + 9)) >> 1) + 1, 4);

    for(i = 0; i < entries; i++)
      free(list_entries[i]);
    free(list_entries);

    clear_screen(32, 7);
    update_screen();

    if(result < 0)
      goto err_free_update_manifests;

    /* Defer deletions until we restart; any of these files may still be
     * in use by this (old) process. Reduce the number of entries by the
     * number of removed items for the progress meter below.
     */
    for(e = removed; e; e = e->next, entries--)
      delete_hook(e->name);

    /* Since the operations for adding and replacing a file are identical,
     * we modify the replaced list and tack on the added list to the end.
     *
     * Either list may be NULL; in the case that `replaced' is NULL, simply
     * re-assign the `added' pointer. `added' being NULL has no effect.
     *
     * Later, we need only free the replaced list (see below).
     */
    if(replaced)
    {
      for(e = replaced; e->next; e = e->next)
        ;
      e->next = added;
    }
    else
      replaced = added;

    cancel_update = false;
    host_set_callbacks(h, NULL, recv_cb, cancel_cb);

    i = 1;
    for(e = replaced; e; e = e->next, i++)
    {
      for(retries = 0; retries < MAX_RETRIES; retries++)
      {
        char name[72];
        bool m_ret;

        if(!check_create_basedir(e->name))
          goto err_free_delete_list;

        final_size = (long)e->size;

        m_hide();
        snprintf(name, 72, "%s (%ldb) [%u/%u]", e->name, final_size, i, entries);
        meter(name, 0, final_size);
        update_screen();

        m_ret = manifest_entry_download_replace(h, url_base, e, delete_hook);

        clear_screen(32, 7);
        m_show();
        update_screen();

        if(m_ret)
          break;

        if(cancel_update)
        {
          error("Download was cancelled; update aborted.", 1, 8, 0);
          goto err_free_delete_list;
        }

        if(!reissue_connection(conf, &h, update_host))
          goto err_free_delete_list;
        host_set_callbacks(h, NULL, recv_cb, cancel_cb);
      }

      if(retries == MAX_RETRIES)
      {
        snprintf(widget_buf, WIDGET_BUF_LEN,
         "Failed to download \"%s\" (after %d attempts).", e->name, retries);
        widget_buf[WIDGET_BUF_LEN - 1] = 0;
        error(widget_buf, 1, 8, 0);
        goto err_free_delete_list;
      }
    }

    if(delete_list)
    {
      f = fopen_unsafe(DELETE_TXT, "wb");
      if(!f)
      {
        error("Failed to create \"" DELETE_TXT "\". Check permissions.", 1, 8, 0);
        goto err_free_delete_list;
      }

      for(e = delete_list; e; e = e->next)
      {
        fprintf(f, "%08x%08x%08x%08x%08x%08x%08x%08x %lu %s\n",
         e->sha256[0], e->sha256[1], e->sha256[2], e->sha256[3],
         e->sha256[4], e->sha256[5], e->sha256[6], e->sha256[7],
         e->size, e->name);
      }

      fclose(f);
    }

    try_next_host = false;
    ret = true;
err_free_delete_list:
    manifest_list_free(&delete_list);
    delete_list = delete_p = NULL;
err_free_update_manifests:
    manifest_list_free(&removed);
    manifest_list_free(&replaced);
err_roll_back_manifest:
    restore_original_manifest(ret);
err_free_url_base:
    free(url_base);
err_host_destroy:
    host_destroy(h);

    pop_context();
  } //end host for loop

err_chdir:
  swivel_current_dir_back(true);
err_out:

  /* At this point we found updates and we successfully updated
   * to them. Reload the program with the original argv.
   */
  if(ret)
  {
    const void *argv = process_argv;
    struct element *elements[2];
    struct dialog di;

    elements[0] = construct_label(2, 2,
     "This client will now attempt to restart itself.");
    elements[1] = construct_button(23, 4, "OK", 0);

    construct_dialog(&di, "Update Successful", 14, 9, 51, 6, elements, 2, 1);
    run_dialog(mzx_world, &di);
    destruct_dialog(&di);

    execv(process_argv[0], argv);
    perror("execv");

    error("Attempt to invoke self failed!", 1, 8, 0);
    return;
  }
}
예제 #19
0
파일: png2smzx.c 프로젝트: ajs1984/megazeux
int main (int argc, char **argv) {
	FILE *fd;
	unsigned char mzmhead[16] = {
		'M', 'Z', 'M', '2', /* Magic */
		0, 0, /* Width */
		0, 0, /* Height */
		0, 0, 0, 0, 0, 1, 0, 0 /* Stuff */
	};
        char input_file_name[MAX_PATH] = { '\0' };
        char output_mzm_name[MAX_PATH] = { '\0' };
        char output_chr_name[MAX_PATH] = { '\0' };
        char output_pal_name[MAX_PATH] = { '\0' };
        char output_base_name[MAX_PATH] = { '\0' };
        char ext[5] = { '\0' };

        int skip_char = -1;

	png_uint_32 w, h, i, t;
	rgba_color *img;
	mzx_tile *tile;
	mzx_glyph chr[256];
	mzx_color pal[256];
	smzx_converter *c;

	if (argc < 2 || argv[1][0] == '-') {
		fprintf(stderr, "png2smzx Image Conversion Utility\n\n"

                        "Usage: %s <in.png> [<out> | <out.mzm> "
			"[<out.chr] [<out.pal>]] [options]\n\n"

			"Options:\n"

			"--skip-char=[value 0-255]	Skip this "
			"char in the conversion process.\n"
                        "\n"
		, argv[0]);
		return 1;
	}

        strncpy(input_file_name, argv[1], MAX_PATH);
        input_file_name[MAX_PATH - 1] = '\0';

        // Read the input files
        for(i = 2; i < (unsigned int) argc; i++)
        {
          strncpy(ext, (argv[i] + strlen(argv[i]) - 4), 5);

          if(!strcasecmp(ext, ".mzm"))
            strncpy(output_mzm_name, argv[i], MAX_PATH);
          if(!strcasecmp(ext, ".chr"))
            strncpy(output_chr_name, argv[i], MAX_PATH);
          if(!strcasecmp(ext, ".pal"))
            strncpy(output_pal_name, argv[i], MAX_PATH);

          if(!strncasecmp(argv[i], "--skip-char", 11) &&
           (argv[i][11] == '=') && argv[i][12])
          {
            skip_char = strtol(argv[i] + 12, NULL, 10) % 256;
            fprintf(stderr, "Skipping char %i.", skip_char);
          }
        }
        output_mzm_name[MAX_PATH - 1] = '\0';
        output_chr_name[MAX_PATH - 1] = '\0';
        output_pal_name[MAX_PATH - 1] = '\0';

        // Fill in the missing filenames
        if(output_mzm_name[0])
        {
          strncpy(output_base_name, output_mzm_name,
           strlen(output_mzm_name) - 4);
          output_base_name[strlen(output_mzm_name) - 4] = '\0';
        }
        else
        {
          if(argc >= 3 && argv[2] && argv[2][0] != '-')
            strncpy(output_base_name, argv[2], MAX_PATH - 5);

          else
            strncpy(output_base_name, input_file_name, MAX_PATH - 5);

          output_base_name[MAX_PATH - 6] = '\0';

          strcpy(output_mzm_name, output_base_name);
          strcpy(output_mzm_name + strlen(output_mzm_name), ".mzm");

          output_pal_name[0] = '\0';
          output_chr_name[0] = '\0';
        }

        if(!output_chr_name[0])
        {
          strcpy(output_chr_name, output_base_name);
          strcpy(output_chr_name + strlen(output_chr_name), ".chr");
        }

        if(!output_pal_name[0])
        {
          strcpy(output_pal_name, output_base_name);
          strcpy(output_pal_name + strlen(output_pal_name), ".pal");
        }


        // Do stuff
	img = (rgba_color *)read_png(input_file_name, &w, &h);
	if (!img) {
		fprintf(stderr, "Error reading image.\n");
		return 1;
	}
	if ((w % 8) || (h % 14)) {
		fprintf(stderr, "Image not divisible by 8x14; cropping...\n");
		if (w % 8) {
			t = w / 8 * 8;
			for (i = 1; i < h; i++)
				memmove(img + i * t, img + i * w,
					sizeof(rgba_color) * t);
		}
	}
	w /= 8;
	h /= 14;
	c = smzx_convert_init(w, h, 0, skip_char, 256, 0, 16);
	if (!c) {
		fprintf(stderr, "Error initializing converter.\n");
		free(img);
		return 1;
	}
	tile = malloc(sizeof(mzx_tile) * w * h);
	if (!tile) {
		fprintf(stderr, "Error allocating tile buffer.\n");
		smzx_convert_free(c);
		free(img);
		return 1;
	}
	smzx_convert(c, img, tile, chr, pal);
	smzx_convert_free(c);
	free(img);
	mzmhead[4] = w & 0xFF;
	mzmhead[5] = w >> 8;
	mzmhead[6] = h & 0xFF;
	mzmhead[7] = h >> 8;
	fd = fopen_unsafe(output_mzm_name, "wb");
	if (!fd) {
		fprintf(stderr, "Error opening MZM file.\n");
		free(tile);
		return 1;
	}
	if (fwrite(mzmhead, sizeof(mzmhead), 1, fd) != 1) {
		fprintf(stderr, "Error writing MZM header.\n");
		fclose(fd);
		free(tile);
		return 1;
	}
	if (fwrite(tile, sizeof(mzx_tile) * w * h, 1, fd) != 1) {
		fprintf(stderr, "Error writing MZM data.\n");
		fclose(fd);
		free(tile);
		return 1;
	}
	free(tile);
	fclose(fd);
	fd = fopen_unsafe(output_chr_name, "wb");
	if (!fd) {
		fprintf(stderr, "Error opening CHR file.\n");
		return 1;
	}
	if (fwrite(chr, sizeof(chr), 1, fd) != 1) {
		fprintf(stderr, "Error writing CHR data.\n");
		fclose(fd);
		return 1;
	}
	fclose(fd);
	fd = fopen_unsafe(output_pal_name, "wb");
	if (!fd) {
		fprintf(stderr, "Error opening PAL file.\n");
		return 1;
	}
	if (fwrite(pal, sizeof(pal), 1, fd) != 1) {
		fprintf(stderr, "Error writing PAL data.\n");
		fclose(fd);
		return 1;
	}
	fclose(fd);
	return 0;
}
예제 #20
0
void
    DumpFileToLog(
    char* path
    )
{
    FILE* fp;
    char buf[BUFFER_SIZE];
    char* p;

    fp = fopen_unsafe(path, "r");
    if (fp == NULL) {
        LogError("ERROR: DumpFileToLog couldn't open file '%s' with error '%s'", path, strerror_unsafe(errno));
    }
    else {
        int fd = _fileno(fp);
        struct _stat64 fileStats;
        if (fd != -1 && _fstat64(fd, &fileStats) != -1)
        {
            char creationTime[256];
            char accessTime[256];
            char currTime[256];
            __time64_t now = _time64(NULL);
            _ctime64_s(currTime, &now);
            _ctime64_s(creationTime, &fileStats.st_ctime);
            _ctime64_s(accessTime, &fileStats.st_atime);
            auto stripNewline = [](char *buf) {
                if (char *ptr = strchr(buf, '\n'))
                    *ptr = '\0';
            };
            stripNewline(creationTime);
            stripNewline(accessTime);
            stripNewline(currTime);

            LogOut("ERROR: name of output file: %s; size: %I64d; creation: %s, last access: %s, now: %s", path, fileStats.st_size, creationTime, accessTime, currTime);
        }
        if (!FNoProgramOutput)
        {
            bool printlines = !FOnlyAssertOutput;
            if (printlines)
            {
                LogOut("ERROR: bad output file follows ============");
            }
            while (fgets(buf, BUFFER_SIZE, fp) != NULL) {
                // Strip the newline, since LogOut adds one
                p = strchr(buf, '\n');
                if (p != NULL) {
                    *p = '\0';
                }
                if (!printlines && strlen(buf) > 8 && buf[0] == 'A' && buf[1] == 'S' && buf[2] == 'S' && buf[3] == 'E' && buf[4] == 'R' && buf[5] == 'T')
                {
                    printlines = true;
                    LogOut("ERROR: bad output file follows ============");
                }
                if (printlines)
                {
                    LogOut("%s", buf);
                }
            }
            if (printlines)
            {
                LogOut("ERROR: end of bad output file  ============");
            }
        }
        fclose(fp);
    }
}
예제 #21
0
파일: pngops.c 프로젝트: AliceLR/megazeux
int png_write_screen(Uint8 *pixels, struct rgb_color *pal, int count,
 const char *name)
{
  png_structp png_ptr = NULL;
  png_infop info_ptr = NULL;
  png_bytep * volatile row_ptrs = NULL;
  png_colorp volatile pal_ptr = NULL;
  int volatile ret = false;
  int type;
  int i;
  FILE *f;

  f = fopen_unsafe(name, "wb");
  if(!f)
    goto exit_out;

  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if(!png_ptr)
    goto exit_close;

  info_ptr = png_create_info_struct(png_ptr);
  if(!info_ptr)
    goto exit_free_close;

  if(setjmp(png_jmpbuf(png_ptr)))
    goto exit_free_close;

  png_init_io(png_ptr, f);

  // we know we have an 8-bit surface; save a palettized PNG
  type = PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE;
  png_set_IHDR(png_ptr, info_ptr, 640, 350, 8, type,
   PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
   PNG_FILTER_TYPE_DEFAULT);

  pal_ptr = cmalloc(count * sizeof(png_color));
  if(!pal_ptr)
    goto exit_free_close;

  for(i = 0; i < count; i++)
  {
    pal_ptr[i].red = pal[i].r;
    pal_ptr[i].green = pal[i].g;
    pal_ptr[i].blue = pal[i].b;
  }
  png_set_PLTE(png_ptr, info_ptr, pal_ptr, count);

  // do the write of the header
  png_write_info(png_ptr, info_ptr);
  png_set_packing(png_ptr);

  row_ptrs = cmalloc(sizeof(png_bytep) * 350);
  if(!row_ptrs)
    goto exit_free_close;

  // and then the surface
  for(i = 0; i < 350; i++)
    row_ptrs[i] = (png_bytep)(Uint8 *)pixels + i * 640;
  png_write_image(png_ptr, row_ptrs);
  png_write_end(png_ptr, info_ptr);

  // all done
  ret = true;

exit_free_close:
  png_destroy_write_struct(&png_ptr, &info_ptr);
  free(pal_ptr);
  free(row_ptrs);
exit_close:
  fclose(f);
exit_out:
  return ret;
}
예제 #22
0
파일: pngops.c 프로젝트: AliceLR/megazeux
void *png_read_file(const char *name, png_uint_32 *_w, png_uint_32 *_h,
 check_w_h_constraint_t constraint, rgba_surface_allocator_t allocator)
{
  png_uint_32 i, w, h, stride;
  png_byte header[8];
  png_structp png_ptr = NULL;
  png_infop info_ptr = NULL;
  png_bytep * volatile row_ptrs = NULL;
  void * volatile s = NULL;
  void *pixels;
  int type;
  int bpp;
  FILE *f;

  f = fopen_unsafe(name, "rb");
  if(!f)
    goto exit_out;

  if(fread(header, 1, 8, f) < 8)
    goto exit_close;

  if(png_sig_cmp(header, 0, 8))
    goto exit_close;

  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if(!png_ptr)
    goto exit_close;

  info_ptr = png_create_info_struct(png_ptr);
  if(!info_ptr)
    goto exit_free_close;

  if(setjmp(png_jmpbuf(png_ptr)))
    goto exit_free_close;

  png_init_io(png_ptr, f);
  png_set_sig_bytes(png_ptr, 8);
  png_read_info(png_ptr, info_ptr);
  png_get_IHDR(png_ptr, info_ptr, &w, &h, &bpp, &type, NULL, NULL, NULL);

  if(!constraint(w, h))
  {
    warn("Requested image '%s' failed dimension checks.\n", name);
    goto exit_free_close;
  }

  if(type == PNG_COLOR_TYPE_PALETTE)
    png_set_palette_to_rgb(png_ptr);

  else if(type == PNG_COLOR_TYPE_GRAY_ALPHA || !(type & PNG_COLOR_MASK_COLOR))
    png_set_gray_to_rgb(png_ptr);

  else if(!(type & PNG_COLOR_MASK_COLOR) && bpp < 8)
    png_set_expand_gray_1_2_4_to_8(png_ptr);

  if(bpp == 16)
    png_set_strip_16(png_ptr);

  else if(bpp < 8)
    png_set_packing(png_ptr);

  if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    png_set_tRNS_to_alpha(png_ptr);
  else if(!(type & PNG_COLOR_MASK_ALPHA))
    png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);

  // FIXME: Are these necessary?
  png_read_update_info(png_ptr, info_ptr);
  png_get_IHDR(png_ptr, info_ptr, &w, &h, &bpp, &type, NULL, NULL, NULL);

  row_ptrs = cmalloc(sizeof(png_bytep) * h);
  if(!row_ptrs)
    goto exit_free_close;

  s = allocator(w, h, &stride, &pixels);
  if(!s)
    goto exit_free_close;

  for(i = 0; i < h; i++)
    row_ptrs[i] = (png_bytep)(unsigned char *)pixels + i * stride;

  png_read_image(png_ptr, row_ptrs);

  if(_w)
    *_w = w;
  if(_h)
    *_h = h;

exit_free_close:
  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
  free(row_ptrs);
exit_close:
  fclose(f);
exit_out:
  return s;
}
예제 #23
0
파일: pngops.c 프로젝트: AliceLR/megazeux
int png_write_screen_32bpp(Uint32 *pixels, const char *name)
{
  png_structp png_ptr = NULL;
  png_infop info_ptr = NULL;
  png_bytep * volatile row_ptrs = NULL;
  int volatile ret = false;
  int type;
  int i;
  FILE *f;

  f = fopen_unsafe(name, "wb");
  if(!f)
    goto exit_out;

  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if(!png_ptr)
    goto exit_close;

  info_ptr = png_create_info_struct(png_ptr);
  if(!info_ptr)
    goto exit_free_close;

  if(setjmp(png_jmpbuf(png_ptr)))
    goto exit_free_close;

  png_init_io(png_ptr, f);

  // 24-bit png
  type = PNG_COLOR_TYPE_RGB;
  png_set_IHDR(png_ptr, info_ptr, 640, 350, 8, type,
   PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
   PNG_FILTER_TYPE_DEFAULT);

  // do the write of the header
  png_write_info(png_ptr, info_ptr);
  png_set_packing(png_ptr);

  row_ptrs = cmalloc(sizeof(png_bytep) * 350);
  if(!row_ptrs)
    goto exit_free_close;

  // our surface is 32bpp ABGR, so set up filler and order
  png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
  png_set_bgr(png_ptr);

  // and then the surface
  for(i = 0; i < 350; i++)
    row_ptrs[i] = (png_bytep)(pixels + i * 640);
  png_write_image(png_ptr, row_ptrs);
  png_write_end(png_ptr, info_ptr);

  // all done
  ret = true;

exit_free_close:
  png_destroy_write_struct(&png_ptr, &info_ptr);
  free(row_ptrs);
exit_close:
  fclose(f);
exit_out:
  return ret;
}