saveload.c
changeset 193 0a7025304867
parent 121 c2f18f4d8be1
child 222 b88456001397
equal deleted inserted replaced
192:614bba52258d 193:0a7025304867
    86 	if (_sl.bufp != NULL) {
    86 	if (_sl.bufp != NULL) {
    87 		uint len = _sl.bufp - _sl.buf;
    87 		uint len = _sl.bufp - _sl.buf;
    88 		_sl.offs_base += len;
    88 		_sl.offs_base += len;
    89 		if (len) _sl.write_bytes(len);
    89 		if (len) _sl.write_bytes(len);
    90 	}
    90 	}
    91 	
    91 
    92 	// setup next buffer
    92 	// setup next buffer
    93 	_sl.bufp = _sl.buf;
    93 	_sl.bufp = _sl.buf;
    94 	_sl.bufe = _sl.buf + _sl.bufsize;
    94 	_sl.bufe = _sl.buf + _sl.bufsize;
    95 }
    95 }
    96 
    96 
   201 
   201 
   202 int SlIterateArray()
   202 int SlIterateArray()
   203 {
   203 {
   204 	int ind;
   204 	int ind;
   205 	static uint32 next_offs;
   205 	static uint32 next_offs;
   206 	
   206 
   207 	// Must be at end of current block.
   207 	// Must be at end of current block.
   208 	assert(next_offs == 0 || SlGetOffs() == next_offs);
   208 	assert(next_offs == 0 || SlGetOffs() == next_offs);
   209 
   209 
   210 	while(true) {
   210 	while(true) {
   211 		uint len = SlReadArrayLength();
   211 		uint len = SlReadArrayLength();
   222 		case CH_ARRAY:        ind = _sl.array_index++; break;
   222 		case CH_ARRAY:        ind = _sl.array_index++; break;
   223 		default:
   223 		default:
   224 			DEBUG(misc, 0) ("SlIterateArray: error\n");
   224 			DEBUG(misc, 0) ("SlIterateArray: error\n");
   225 			return -1; // error
   225 			return -1; // error
   226 		}
   226 		}
   227 		
   227 
   228 		if (len != 0)
   228 		if (len != 0)
   229 			return ind;
   229 			return ind;
   230 	}
   230 	}
   231 }
   231 }
   232 
   232 
   298 
   298 
   299 
   299 
   300 static void SlSaveLoadConv(void *ptr, uint conv)
   300 static void SlSaveLoadConv(void *ptr, uint conv)
   301 {
   301 {
   302 	int64 x = 0;
   302 	int64 x = 0;
   303 	
   303 
   304 	if (_sl.save) {
   304 	if (_sl.save) {
   305 		// Read a value from the struct. These ARE endian safe.
   305 		// Read a value from the struct. These ARE endian safe.
   306 		switch((conv >> 4)&0xf) {
   306 		switch((conv >> 4)&0xf) {
   307 		case SLE_VAR_I8>>4: x = *(int8*)ptr; break;
   307 		case SLE_VAR_I8>>4: x = *(int8*)ptr; break;
   308 		case SLE_VAR_U8>>4: x = *(byte*)ptr; break;
   308 		case SLE_VAR_U8>>4: x = *(byte*)ptr; break;
   309 		case SLE_VAR_I16>>4: x = *(int16*)ptr; break;
   309 		case SLE_VAR_I16>>4: x = *(int16*)ptr; break;
   310 		case SLE_VAR_U16>>4: x = *(uint16*)ptr; break;
   310 		case SLE_VAR_U16>>4: x = *(uint16*)ptr; break;
   311 		case SLE_VAR_I32>>4: x = *(int32*)ptr; break;
   311 		case SLE_VAR_I32>>4: x = *(int32*)ptr; break;
   312 		case SLE_VAR_U32>>4: x = *(uint32*)ptr; break;
   312 		case SLE_VAR_U32>>4: x = *(uint32*)ptr; break;
   313 		case SLE_VAR_I64>>4: x = *(int64*)ptr; break; 
   313 		case SLE_VAR_I64>>4: x = *(int64*)ptr; break;
   314 		case SLE_VAR_U64>>4: x = *(uint64*)ptr; break;
   314 		case SLE_VAR_U64>>4: x = *(uint64*)ptr; break;
   315 		case SLE_VAR_NULL>>4: x = 0; break;
   315 		case SLE_VAR_NULL>>4: x = 0; break;
   316 		default:
   316 		default:
   317 			NOT_REACHED();
   317 			NOT_REACHED();
   318 		}
   318 		}
   331 		default:
   331 		default:
   332 			assert(0);
   332 			assert(0);
   333 			NOT_REACHED();
   333 			NOT_REACHED();
   334 		}
   334 		}
   335 	} else {
   335 	} else {
   336 		
   336 
   337 		// Read a value from the file
   337 		// Read a value from the file
   338 		switch(conv & 0xF) {
   338 		switch(conv & 0xF) {
   339 		case SLE_FILE_I8: x = (int8)SlReadByte();	break;
   339 		case SLE_FILE_I8: x = (int8)SlReadByte();	break;
   340 		case SLE_FILE_U8: x = (byte)SlReadByte(); break;
   340 		case SLE_FILE_U8: x = (byte)SlReadByte(); break;
   341 		case SLE_FILE_I16: x = (int16)SlReadUint16();	break;
   341 		case SLE_FILE_I16: x = (int16)SlReadUint16();	break;
   439 				}
   439 				}
   440 			}
   440 			}
   441 
   441 
   442 			switch(cmd&3) {
   442 			switch(cmd&3) {
   443 			// Normal variable
   443 			// Normal variable
   444 			case 0: length += SlCalcConvLen(conv, NULL);break;			
   444 			case 0: length += SlCalcConvLen(conv, NULL);break;
   445 			// Reference
   445 			// Reference
   446 			case 1: length += 2; break;
   446 			case 1: length += 2; break;
   447 			// Array
   447 			// Array
   448 			case 2:	length += SlCalcArrayLen(NULL, *d++, conv); break;
   448 			case 2:	length += SlCalcArrayLen(NULL, *d++, conv); break;
   449 			default:NOT_REACHED();
   449 			default:NOT_REACHED();
   507 				break;
   507 				break;
   508 			// Array
   508 			// Array
   509 			case 2:	SlArray(ptr, *d++, conv); break;
   509 			case 2:	SlArray(ptr, *d++, conv); break;
   510 			default:NOT_REACHED();
   510 			default:NOT_REACHED();
   511 			}
   511 			}
   512 	
   512 
   513 		// Write byte.
   513 		// Write byte.
   514 		} else if (cmd == 8) {
   514 		} else if (cmd == 8) {
   515 			if (_sl.save) {
   515 			if (_sl.save) {
   516 				SlWriteByte(d[3]);
   516 				SlWriteByte(d[3]);
   517 			} else {
   517 			} else {
   590 	size_t len;
   590 	size_t len;
   591 	uint32 endoffs;
   591 	uint32 endoffs;
   592 
   592 
   593 	_sl.block_mode = m;
   593 	_sl.block_mode = m;
   594 	_sl.obj_len = 0;
   594 	_sl.obj_len = 0;
   595 	
   595 
   596 	switch(m) {
   596 	switch(m) {
   597 	case CH_ARRAY:
   597 	case CH_ARRAY:
   598 		_sl.array_index = 0;
   598 		_sl.array_index = 0;
   599 		ch->load_proc();
   599 		ch->load_proc();
   600 		break;
   600 		break;
   639 	if (ch->flags & CH_AUTO_LENGTH) {
   639 	if (ch->flags & CH_AUTO_LENGTH) {
   640 		// Need to calculate the length. Solve that by calling SlAutoLength in the save_proc.
   640 		// Need to calculate the length. Solve that by calling SlAutoLength in the save_proc.
   641 		_tmp_proc_1 = proc;
   641 		_tmp_proc_1 = proc;
   642 		proc = SlStubSaveProc;
   642 		proc = SlStubSaveProc;
   643 	}
   643 	}
   644 	
   644 
   645 	_sl.block_mode = ch->flags & CH_TYPE_MASK;
   645 	_sl.block_mode = ch->flags & CH_TYPE_MASK;
   646 	switch(ch->flags & CH_TYPE_MASK) {
   646 	switch(ch->flags & CH_TYPE_MASK) {
   647 	case CH_RIFF:
   647 	case CH_RIFF:
   648 		_sl.need_length = NL_WANTLENGTH;
   648 		_sl.need_length = NL_WANTLENGTH;
   649 		proc();
   649 		proc();
   672 
   672 
   673 	for(p=0; p!=CH_NUM_PRI_LEVELS; p++) {
   673 	for(p=0; p!=CH_NUM_PRI_LEVELS; p++) {
   674 		for(chsc=_sl.chs;(ch=*chsc++) != NULL;) {
   674 		for(chsc=_sl.chs;(ch=*chsc++) != NULL;) {
   675 			while(true) {
   675 			while(true) {
   676 				if (((ch->flags >> CH_PRI_SHL) & (CH_NUM_PRI_LEVELS - 1)) == p)
   676 				if (((ch->flags >> CH_PRI_SHL) & (CH_NUM_PRI_LEVELS - 1)) == p)
   677 					SlSaveChunk(ch);	
   677 					SlSaveChunk(ch);
   678 				if (ch->flags & CH_LAST)
   678 				if (ch->flags & CH_LAST)
   679 					break;
   679 					break;
   680 				ch++;
   680 				ch++;
   681 			}
   681 			}
   682 		}
   682 		}
   739 	// Read header
   739 	// Read header
   740 	if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError("file read failed");
   740 	if (fread(tmp, sizeof(tmp), 1, _sl.fh) != 1) SlError("file read failed");
   741 
   741 
   742 	// Check if size is bad
   742 	// Check if size is bad
   743 	((uint32*)out)[0] = size = tmp[1];
   743 	((uint32*)out)[0] = size = tmp[1];
   744 	
   744 
   745 	if (_sl.version != 0) {
   745 	if (_sl.version != 0) {
   746 		tmp[0] = TO_BE32(tmp[0]);
   746 		tmp[0] = TO_BE32(tmp[0]);
   747 		size = TO_BE32(size);
   747 		size = TO_BE32(size);
   748 	}
   748 	}
   749 
   749 
   752 	// Read block
   752 	// Read block
   753 	if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError("file read failed");
   753 	if (fread(out + sizeof(uint32), size, 1, _sl.fh) != 1) SlError("file read failed");
   754 
   754 
   755 	// Verify checksum
   755 	// Verify checksum
   756 	if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError("bad checksum");
   756 	if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlError("bad checksum");
   757 	
   757 
   758 	// Decompress
   758 	// Decompress
   759 	lzo1x_decompress(out + sizeof(uint32)*1, size, _sl.buf, &len, NULL);
   759 	lzo1x_decompress(out + sizeof(uint32)*1, size, _sl.buf, &len, NULL);
   760 	return len;
   760 	return len;
   761 }
   761 }
   762 
   762 
   765 static void WriteLZO(uint size)
   765 static void WriteLZO(uint size)
   766 {
   766 {
   767 	byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
   767 	byte out[LZO_SIZE + LZO_SIZE / 64 + 16 + 3 + 8];
   768 	byte wrkmem[sizeof(byte*)*4096];
   768 	byte wrkmem[sizeof(byte*)*4096];
   769 	uint outlen;
   769 	uint outlen;
   770 	
   770 
   771 	lzo1x_1_compress(_sl.buf, size, out + sizeof(uint32)*2, &outlen, wrkmem);
   771 	lzo1x_1_compress(_sl.buf, size, out + sizeof(uint32)*2, &outlen, wrkmem);
   772 	((uint32*)out)[1] = TO_BE32(outlen);
   772 	((uint32*)out)[1] = TO_BE32(outlen);
   773 	((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
   773 	((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
   774 	if (fwrite(out, outlen + sizeof(uint32)*2, 1, _sl.fh) != 1) SlError("file write failed");
   774 	if (fwrite(out, outlen + sizeof(uint32)*2, 1, _sl.fh) != 1) SlError("file write failed");
   775 }
   775 }
   819 
   819 
   820 static bool InitReadZlib()
   820 static bool InitReadZlib()
   821 {
   821 {
   822 	memset(&_z, 0, sizeof(_z));
   822 	memset(&_z, 0, sizeof(_z));
   823 	if (inflateInit(&_z) != Z_OK) return false;
   823 	if (inflateInit(&_z) != Z_OK) return false;
   824 	
   824 
   825 	_sl.bufsize = 4096;
   825 	_sl.bufsize = 4096;
   826 	_sl.buf = (byte*)malloc(4096 + 4096); // also contains fread buffer
   826 	_sl.buf = (byte*)malloc(4096 + 4096); // also contains fread buffer
   827 	return true;
   827 	return true;
   828 }
   828 }
   829 
   829 
   843 		// inflate the data
   843 		// inflate the data
   844 		r = inflate(&_z, 0);
   844 		r = inflate(&_z, 0);
   845 		if (r == Z_STREAM_END)
   845 		if (r == Z_STREAM_END)
   846 			break;
   846 			break;
   847 
   847 
   848 		if (r != Z_OK) 
   848 		if (r != Z_OK)
   849 			SlError("inflate() failed");
   849 			SlError("inflate() failed");
   850 	} while (_z.avail_out);
   850 	} while (_z.avail_out);
   851 
   851 
   852 	return 4096 - _z.avail_out;
   852 	return 4096 - _z.avail_out;
   853 }
   853 }
  1018 int SaveOrLoad(const char *filename, int mode)
  1018 int SaveOrLoad(const char *filename, int mode)
  1019 {
  1019 {
  1020 	uint32 hdr[2];
  1020 	uint32 hdr[2];
  1021 	const SaveLoadFormat *fmt;
  1021 	const SaveLoadFormat *fmt;
  1022   uint version;
  1022   uint version;
  1023 		
  1023 
  1024 	// old style load
  1024 	// old style load
  1025 	if (mode == SL_OLD_LOAD) {
  1025 	if (mode == SL_OLD_LOAD) {
  1026 		InitializeGame();
  1026 		InitializeGame();
  1027 		if (!LoadOldSaveGame(filename)) return SL_REINIT;
  1027 		if (!LoadOldSaveGame(filename)) return SL_REINIT;
  1028 		AfterLoadGame(0);
  1028 		AfterLoadGame(0);
  1029 		return SL_OK;
  1029 		return SL_OK;
  1030 	}
  1030 	}
  1031 	
  1031 
  1032 	_sl.fh = fopen(filename, mode?"wb":"rb");
  1032 	_sl.fh = fopen(filename, mode?"wb":"rb");
  1033 	if (_sl.fh == NULL)
  1033 	if (_sl.fh == NULL)
  1034 		return SL_ERROR;
  1034 		return SL_ERROR;
  1035 	
  1035 
  1036 	_sl.bufe = _sl.bufp = NULL;
  1036 	_sl.bufe = _sl.bufp = NULL;
  1037 	_sl.offs_base = 0;
  1037 	_sl.offs_base = 0;
  1038 	_sl.int_to_ref_proc = IntToReference;
  1038 	_sl.int_to_ref_proc = IntToReference;
  1039 	_sl.ref_to_int_proc = ReferenceToInt;
  1039 	_sl.ref_to_int_proc = ReferenceToInt;
  1040 	_sl.save = mode;
  1040 	_sl.save = mode;
  1058 			ShowInfoF("Save game failed: %s.", _sl.excpt_msg);
  1058 			ShowInfoF("Save game failed: %s.", _sl.excpt_msg);
  1059 			return SL_ERROR;
  1059 			return SL_ERROR;
  1060 		}
  1060 		}
  1061 	}
  1061 	}
  1062 
  1062 
  1063   // we first initialize here to avoid: "warning: variable `version' might 
  1063   // we first initialize here to avoid: "warning: variable `version' might
  1064   // be clobbered by `longjmp' or `vfork'"
  1064   // be clobbered by `longjmp' or `vfork'"
  1065 	version = 0;
  1065 	version = 0;
  1066 
  1066 
  1067 	if (mode != SL_LOAD) {
  1067 	if (mode != SL_LOAD) {
  1068 		fmt = GetSavegameFormat(_savegame_format);
  1068 		fmt = GetSavegameFormat(_savegame_format);
  1069 		
  1069 
  1070 		_sl.write_bytes = fmt->writer;
  1070 		_sl.write_bytes = fmt->writer;
  1071 		_sl.excpt_uninit = fmt->uninit_write;
  1071 		_sl.excpt_uninit = fmt->uninit_write;
  1072 		if (!fmt->init_write()) goto init_err;
  1072 		if (!fmt->init_write()) goto init_err;
  1073 		
  1073 
  1074 		hdr[0] = fmt->tag;
  1074 		hdr[0] = fmt->tag;
  1075 		hdr[1] = TO_BE32((SAVEGAME_MAJOR_VERSION<<16) + (SAVEGAME_MINOR_VERSION << 8));
  1075 		hdr[1] = TO_BE32((SAVEGAME_MAJOR_VERSION<<16) + (SAVEGAME_MINOR_VERSION << 8));
  1076 		if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError("file write failed");
  1076 		if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError("file write failed");
  1077 		
  1077 
  1078 		_sl.version = SAVEGAME_MAJOR_VERSION;
  1078 		_sl.version = SAVEGAME_MAJOR_VERSION;
  1079 		
  1079 
  1080 		BeforeSaveGame();
  1080 		BeforeSaveGame();
  1081 		SlSaveChunks();
  1081 		SlSaveChunks();
  1082 		SlWriteFill(); // flush the save buffer
  1082 		SlWriteFill(); // flush the save buffer
  1083 		fmt->uninit_write();
  1083 		fmt->uninit_write();
  1084 
  1084 
  1102 				break;
  1102 				break;
  1103 			}
  1103 			}
  1104 			if (fmt->tag == hdr[0]) {
  1104 			if (fmt->tag == hdr[0]) {
  1105 				// check version number
  1105 				// check version number
  1106 				version = TO_BE32(hdr[1]) >> 8;
  1106 				version = TO_BE32(hdr[1]) >> 8;
  1107 				
  1107 
  1108 				// incompatible version?
  1108 				// incompatible version?
  1109 				if (version > SAVEGAME_LOADABLE_VERSION) goto read_err;
  1109 				if (version > SAVEGAME_LOADABLE_VERSION) goto read_err;
  1110 				_sl.version = (version>>8);
  1110 				_sl.version = (version>>8);
  1111 				break;
  1111 				break;
  1112 			}
  1112 			}