restore static method

bool restore(
  1. dynamic rawBytes
)

Implementation

static bool restore(rawBytes){
  var fileBytes = List.from(rawBytes);
  //List<int> restoreData = List<int>();

  Chunk? nextChunk = IFF.readChunk(fileBytes);
  if (!assertChunk(Chunk.form, nextChunk)) return false;

  nextChunk = IFF.readChunk(fileBytes);
  if (!assertChunk(Chunk.ifzs, nextChunk)) return false;

  var gotStacks = false;
  var gotMem = false;
  var gotHeader = false;
  late int pc;
  var memBytes = [];
  final stackList = <StackFrame>[];

  nextChunk = IFF.readChunk(fileBytes);
  if (nextChunk == null) return false;

  while(nextChunk != null){
    switch(nextChunk){
      case Chunk.ifhd:
        // here we are validating that this file is compatible
        // with the game currently loaded into the machine.

        IFF.read4Byte(fileBytes); //size (always 13)
        if (Z.engine.mem.loadw(Header.release) != IFF.read2Byte(fileBytes)){
          return false;
        }
        if (Z.engine.mem.loadw(Header.serialNumber) != IFF.read2Byte(fileBytes)){
          return false;
        }
        if (Z.engine.mem.loadw(Header.serialNumber + 2) != IFF.read2Byte(fileBytes)){
          return false;
        }
        if (Z.engine.mem.loadw(Header.serialNumber + 4) != IFF.read2Byte(fileBytes)){
          return false;
        }
        if (Z.engine.mem.loadw(Header.checkSumOfFile) != IFF.read2Byte(fileBytes)){
          return false;
        }
        pc = IFF.read3Byte(fileBytes); //PC
        IFF.nextByte(fileBytes); //pad
        gotHeader = true;
        break;
      case Chunk.stks:
        var stacksLen = IFF.read4Byte(fileBytes);

        StackFrame getNextStackFrame(){
          var sf = StackFrame.empty();

          sf.returnAddr = IFF.read3Byte(fileBytes);

          var flagByte = IFF.nextByte(fileBytes)!;

          var returnVar = IFF.nextByte(fileBytes);

          sf.returnVar = BinaryHelper.isSet(flagByte, 4)
                            ? Engine.stackMarker
                            : returnVar!;

          var numLocals = BinaryHelper.bottomBits(flagByte, 4);

          var argsPassed = IFF.nextByte(fileBytes)!;

          var args = 0;
          while(BinaryHelper.isSet(argsPassed, 0)){
            args++;
            argsPassed = argsPassed >> 1;
          }
          sf.totalArgsPassed = args;

          var numEvals = IFF.read2Byte(fileBytes);

          for(int i = 0; i < numLocals; i++){
            sf.locals.add(IFF.read2Byte(fileBytes));
          }

          for(int i = 0; i < numEvals; i++){
            sf.evals.add(IFF.read2Byte(fileBytes));
          }
          return sf;
        }

        while(stacksLen > 0){
          if (stacksLen == 1){
            //pad byte
            IFF.nextByte(fileBytes);
            continue;
          }

          stackList.add(getNextStackFrame());
          stacksLen -= stackList.last.computedByteSize;
        }

        gotStacks = true;
        break;
      case Chunk.umem:
        var numBytes = IFF.read4Byte(fileBytes);

        //memory length mismatch
        if (numBytes != Z.engine.mem.memList.length) {
          return false;
        }

        memBytes = fileBytes.getRange(0, numBytes) as List<dynamic>;
        fileBytes.removeRange(0, numBytes);

        //IFF.read pad byte if present
        if (numBytes % 2 != 0) {
          IFF.nextByte(fileBytes);
        }
        gotMem = true;
        break;
      default:
        if (!gotStacks || !gotMem || !gotHeader){
          if (nextChunk == Chunk.form || nextChunk == Chunk.ifzs){
            return false; //something went horribly wrong in the file format
          }

          //attempt to skip the chunk
          var sizeOfChunk = IFF.read4Byte(fileBytes);
          fileBytes.removeRange(0, sizeOfChunk);
        }
    }

    if(gotStacks && gotMem && gotHeader) break;
    nextChunk = IFF.readChunk(fileBytes);
  }

  if (!gotStacks || !gotMem || !gotHeader) return false;

  //now that we have all the data structures, do the restore...

  //memory
  Z.engine.mem = MemoryMap(memBytes as List<int>);
  Z.engine.visitHeader();


  Z.engine.callStack.clear();
  Z.engine.stack.clear();

  //stacks
  for(StackFrame sf in stackList){

    //callstack first
    stdout.writeln(sf);

    //locals
    Z.engine.callStack.push(sf.locals.length);

    for(final local in sf.locals){
      Z.engine.callStack.push(local!);
    }

    //total locals
    Z.engine.callStack.push(sf.locals.length);

    //returnTo variable
    Z.engine.callStack.push(sf.returnVar);

    //return addr
    Z.engine.callStack.push(sf.returnAddr);


    //eval stack
    Z.engine.stack.push(Engine.stackMarker);
    for(final eval in sf.evals){
      Z.engine.stack.push(eval!);
    }
  }

  Z.engine.programCounter = pc;

  return true;
}