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 } |
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(); |
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(); |
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 |
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 } |