Exemple #1
0
/* perform_restoreundo():
   Pull a state pointer from the undo chain. This returns 0 on success,
   1 on failure. Note that if it succeeds, the frameptr, localsbase,
   and valstackbase registers are invalid; they must be rebuilt from
   the stack.
*/
glui32 perform_restoreundo()
{
  dest_t dest;
  glui32 res, val;
  glui32 heapsumlen = 0;
  glui32 *heapsumarr = NULL;

  if (undo_chain_size == 0 || undo_chain_num == 0)
    return 1;

  dest.ismem = TRUE;
  dest.size = 0;
  dest.pos = 0;
  dest.ptr = undo_chain[0];
  dest.str = NULL;

  res = 0;
  if (res == 0) {
    res = read_long(&dest, &val);
  }
  if (res == 0) {
    res = read_memstate(&dest, val);
  }
  if (res == 0) {
    res = read_long(&dest, &val);
  }
  if (res == 0) {
    res = read_heapstate(&dest, val, FALSE, &heapsumlen, &heapsumarr);
  }
  if (res == 0) {
    res = read_long(&dest, &val);
  }
  if (res == 0) {
    res = read_stackstate(&dest, val, FALSE);
  }
  /* ### really, many of the failure modes of those calls ought to
     cause fatal errors. The stack or main memory may be damaged now. */

  if (res == 0) {
    if (heapsumarr)
      res = heap_apply_summary(heapsumlen, heapsumarr);
  }

  if (res == 0) {
    /* It worked. */
    if (undo_chain_size > 1)
      memmove(undo_chain, undo_chain+1,
        (undo_chain_size-1) * sizeof(unsigned char *));
    undo_chain_num -= 1;
    glulx_free(dest.ptr);
    dest.ptr = NULL;
  }
  else {
    /* It didn't work. */
    dest.ptr = NULL;
  }

  return res;
}
Exemple #2
0
/* perform_restore():
   Pull a state pointer from a stream. This returns 0 on success,
   1 on failure. Note that if it succeeds, the frameptr, localsbase,
   and valstackbase registers are invalid; they must be rebuilt from
   the stack.
 
   If fromshell is true, the restore is being invoked by the library
   shell (an autorestore of some kind). This currently happens only in
   iosglk.
*/
glui32 perform_restore(strid_t str, int fromshell)
{
  dest_t dest;
  int ix;
  glui32 lx, res, val;
  glui32 filestart, filelen;
  glui32 heapsumlen = 0;
  glui32 *heapsumarr = NULL;

  /* If profiling is enabled and active then fail. */
  #if VM_PROFILING
  if (profile_profiling_active())
    return 1;
  #endif /* VM_PROFILING */

  stream_get_iosys(&val, &lx);
  if (val != 2 && !fromshell) {
    /* Not using the Glk I/O system, so bail. This function only
       knows how to read from a Glk stream. (But in the autorestore
       case, iosys hasn't been set yet, so ignore this test.) */
    fatal_error("Streams are only available in Glk I/O system.");
  }

  if (str == 0)
    return 1;

  dest.ismem = FALSE;
  dest.size = 0;
  dest.pos = 0;
  dest.ptr = NULL;
  dest.str = str;

  res = 0;

  /* ### the format errors checked below should send error messages to
     the current stream. */

  if (res == 0) {
    res = read_long(&dest, &val);
  }
  if (res == 0 && val != IFFID('F', 'O', 'R', 'M')) {
    /* ### bad header */
    return 1;
  }
  if (res == 0) {
    res = read_long(&dest, &filelen);
  }
  filestart = dest.pos;

  if (res == 0) {
    res = read_long(&dest, &val);
  }
  if (res == 0 && val != IFFID('I', 'F', 'Z', 'S')) { /* ### ? */
    /* ### bad header */
    return 1;
  }

  while (res == 0 && dest.pos < filestart+filelen) {
    /* Read a chunk and deal with it. */
    glui32 chunktype=0, chunkstart=0, chunklen=0;
    unsigned char dummy;

    if (res == 0) {
      res = read_long(&dest, &chunktype);
    }
    if (res == 0) {
      res = read_long(&dest, &chunklen);
    }
    chunkstart = dest.pos;

    if (chunktype == IFFID('I', 'F', 'h', 'd')) {
      for (ix=0; res==0 && ix<128; ix++) {
        res = read_byte(&dest, &dummy);
        if (res == 0 && Mem1(ix) != dummy) {
          /* ### non-matching header */
          return 1;
        }
      }
    }
    else if (chunktype == IFFID('C', 'M', 'e', 'm')) {
      res = read_memstate(&dest, chunklen);
    }
    else if (chunktype == IFFID('M', 'A', 'l', 'l')) {
      res = read_heapstate(&dest, chunklen, TRUE, &heapsumlen, &heapsumarr);
    }
    else if (chunktype == IFFID('S', 't', 'k', 's')) {
      res = read_stackstate(&dest, chunklen, TRUE);
    }
    else {
      /* Unknown chunk type. Skip it. */
      for (lx=0; res==0 && lx<chunklen; lx++) {
        res = read_byte(&dest, &dummy);
      }
    }

    if (chunkstart+chunklen != dest.pos) {
      /* ### funny chunk length */
      return 1;
    }

    if ((chunklen & 1) != 0) {
      if (res == 0) {
        res = read_byte(&dest, &dummy);
      }
    }
  }

  if (res == 0) {
    if (heapsumarr) {
      /* The summary might have come from any interpreter, so it could
         be out of order. We'll sort it. */
      glulx_sort(heapsumarr+2, (heapsumlen-2)/2, 2*sizeof(glui32),
        &sort_heap_summary);
      res = heap_apply_summary(heapsumlen, heapsumarr);
    }
  }

  if (res)
    return 1;

  return 0;
}