saveload.c
changeset 5142 d423c895a5b4
parent 5141 05a806850445
child 5163 83acad83bbdd
equal deleted inserted replaced
5141:05a806850445 5142:d423c895a5b4
   485 
   485 
   486 /** Calculate the net length of a string. This is in almost all cases
   486 /** Calculate the net length of a string. This is in almost all cases
   487  * just strlen(), but if the string is not properly terminated, we'll
   487  * just strlen(), but if the string is not properly terminated, we'll
   488  * resort to the maximum length of the buffer.
   488  * resort to the maximum length of the buffer.
   489  * @param ptr pointer to the stringbuffer
   489  * @param ptr pointer to the stringbuffer
   490  * @param length maximum length of the string (buffer)
   490  * @param length maximum length of the string (buffer). If -1 we don't care
       
   491  * about a maximum length, but take string length as it is.
   491  * @return return the net length of the string */
   492  * @return return the net length of the string */
   492 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
   493 static inline size_t SlCalcNetStringLen(const char *ptr, size_t length)
   493 {
   494 {
   494 	return minu(strlen(ptr), length - 1);
   495 	return minu(strlen(ptr), length - 1);
   495 }
   496 }
   503 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
   504 static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv)
   504 {
   505 {
   505 	size_t len;
   506 	size_t len;
   506 	const char *str;
   507 	const char *str;
   507 
   508 
   508 	conv = GetVarMemType(conv);
   509 	switch (GetVarMemType(conv)) {
   509 	/* For strings without a pre-allocated buffer, we need an extra indirection of course */
   510 		default: NOT_REACHED();
   510 	str = (conv == SLE_VAR_STR || conv == SLE_VAR_STRQ) ? *(const char**)ptr : (const char*)ptr;
   511 		case SLE_VAR_STR:
   511 	len = SlCalcNetStringLen(str, length);
   512 		case SLE_VAR_STRQ:
       
   513 			str = *(const char**)ptr;
       
   514 			len = -1;
       
   515 			break;
       
   516 		case SLE_VAR_STRB:
       
   517 		case SLE_VAR_STRBQ:
       
   518 			str = (const char*)ptr;
       
   519 			len = length;
       
   520 			break;
       
   521 	}
       
   522 
       
   523 	len = SlCalcNetStringLen(str, len);
   512 	return len + SlGetArrayLength(len); // also include the length of the index
   524 	return len + SlGetArrayLength(len); // also include the length of the index
   513 }
   525 }
   514 
   526 
   515 /**
   527 /**
   516  * Save/Load a string.
   528  * Save/Load a string.
   521 {
   533 {
   522 	size_t len;
   534 	size_t len;
   523 
   535 
   524 	if (_sl.save) { /* SAVE string */
   536 	if (_sl.save) { /* SAVE string */
   525 		switch (GetVarMemType(conv)) {
   537 		switch (GetVarMemType(conv)) {
       
   538 			default: NOT_REACHED();
   526 			case SLE_VAR_STRB:
   539 			case SLE_VAR_STRB:
   527 			case SLE_VAR_STRBQ:
   540 			case SLE_VAR_STRBQ:
   528 				len = SlCalcNetStringLen(ptr, length);
   541 				len = SlCalcNetStringLen(ptr, length);
   529 				break;
   542 				break;
   530 			case SLE_VAR_STR:
   543 			case SLE_VAR_STR:
   531 			case SLE_VAR_STRQ:
   544 			case SLE_VAR_STRQ:
   532 				ptr = *(char**)ptr;
   545 				ptr = *(char**)ptr;
   533 				len = SlCalcNetStringLen(ptr, 0);
   546 				len = SlCalcNetStringLen(ptr, -1);
   534 				break;
   547 				break;
   535 			default: NOT_REACHED();
       
   536 		}
   548 		}
   537 
   549 
   538 		SlWriteArrayLength(len);
   550 		SlWriteArrayLength(len);
   539 		SlCopyBytes(ptr, len);
   551 		SlCopyBytes(ptr, len);
   540 	} else { /* LOAD string */
   552 	} else { /* LOAD string */
   541 		len = SlReadArrayLength();
   553 		len = SlReadArrayLength();
   542 
   554 
   543 		switch (GetVarMemType(conv)) {
   555 		switch (GetVarMemType(conv)) {
       
   556 			default: NOT_REACHED();
   544 			case SLE_VAR_STRB:
   557 			case SLE_VAR_STRB:
   545 			case SLE_VAR_STRBQ:
   558 			case SLE_VAR_STRBQ:
   546 				if (len >= length) {
   559 				if (len >= length) {
   547 					DEBUG(misc, 0) ("[Sl] String length in savegame is bigger than buffer, truncating");
   560 					DEBUG(misc, 0) ("[Sl] String length in savegame is bigger than buffer, truncating");
   548 					SlCopyBytes(ptr, length);
   561 					SlCopyBytes(ptr, length);
   557 				free(*(char**)ptr);
   570 				free(*(char**)ptr);
   558 				*(char**)ptr = malloc(len + 1); // terminating '\0'
   571 				*(char**)ptr = malloc(len + 1); // terminating '\0'
   559 				ptr = *(char**)ptr;
   572 				ptr = *(char**)ptr;
   560 				SlCopyBytes(ptr, len);
   573 				SlCopyBytes(ptr, len);
   561 				break;
   574 				break;
   562 			default: NOT_REACHED();
       
   563 		}
   575 		}
   564 
   576 
   565 		((char*)ptr)[len] = '\0'; // properly terminate the string
   577 		((char*)ptr)[len] = '\0'; // properly terminate the string
   566 	}
   578 	}
   567 }
   579 }
   640 
   652 
   641 /**
   653 /**
   642  * Calculate the size of an object.
   654  * Calculate the size of an object.
   643  * @param sld The @SaveLoad description of the object so we know how to manipulate it
   655  * @param sld The @SaveLoad description of the object so we know how to manipulate it
   644  */
   656  */
   645 static size_t SlCalcObjLength(const SaveLoad *sld)
   657 static size_t SlCalcObjLength(const void *object, const SaveLoad *sld)
   646 {
   658 {
   647 	size_t length = 0;
   659 	size_t length = 0;
   648 
   660 
   649 	// Need to determine the length and write a length tag.
   661 	// Need to determine the length and write a length tag.
   650 	for (; sld->cmd != SL_END; sld++) {
   662 	for (; sld->cmd != SL_END; sld++) {
   651 		length += SlCalcObjMemberLength(sld);
   663 		length += SlCalcObjMemberLength(object, sld);
   652 	}
   664 	}
   653 	return length;
   665 	return length;
   654 }
   666 }
   655 
   667 
   656 size_t SlCalcObjMemberLength(const SaveLoad *sld)
   668 size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
   657 {
   669 {
   658 	assert(_sl.save);
   670 	assert(_sl.save);
   659 
   671 
   660 	switch (sld->cmd) {
   672 	switch (sld->cmd) {
   661 		case SL_VAR:
   673 		case SL_VAR:
   667 
   679 
   668 			switch (sld->cmd) {
   680 			switch (sld->cmd) {
   669 			case SL_VAR: return SlCalcConvFileLen(sld->conv);
   681 			case SL_VAR: return SlCalcConvFileLen(sld->conv);
   670 			case SL_REF: return SlCalcRefLen();
   682 			case SL_REF: return SlCalcRefLen();
   671 			case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
   683 			case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv);
   672 			case SL_STR: return SlCalcStringLen(sld->address, sld->length, sld->conv);
   684 			case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv);
   673 			default: NOT_REACHED();
   685 			default: NOT_REACHED();
   674 			}
   686 			}
   675 			break;
   687 			break;
   676 		case SL_WRITEBYTE: return 1; // a byte is logically of size 1
   688 		case SL_WRITEBYTE: return 1; // a byte is logically of size 1
   677 		case SL_INCLUDE: return SlCalcObjLength(_sl.includes[sld->version_from]);
   689 		case SL_INCLUDE: return SlCalcObjLength(object, _sl.includes[sld->version_from]);
   678 		default: NOT_REACHED();
   690 		default: NOT_REACHED();
   679 	}
   691 	}
   680 	return 0;
   692 	return 0;
   681 }
   693 }
   682 
   694 
   744  */
   756  */
   745 void SlObject(void *object, const SaveLoad *sld)
   757 void SlObject(void *object, const SaveLoad *sld)
   746 {
   758 {
   747 	// Automatically calculate the length?
   759 	// Automatically calculate the length?
   748 	if (_sl.need_length != NL_NONE) {
   760 	if (_sl.need_length != NL_NONE) {
   749 		SlSetLength(SlCalcObjLength(sld));
   761 		SlSetLength(SlCalcObjLength(object, sld));
   750 		if (_sl.need_length == NL_CALCLENGTH) return;
   762 		if (_sl.need_length == NL_CALCLENGTH) return;
   751 	}
   763 	}
   752 
   764 
   753 	for (; sld->cmd != SL_END; sld++) {
   765 	for (; sld->cmd != SL_END; sld++) {
   754 		void *ptr = GetVariableAddress(object, sld);
   766 		void *ptr = GetVariableAddress(object, sld);
   761  * @param desc The global variable that is being loaded or saved
   773  * @param desc The global variable that is being loaded or saved
   762  */
   774  */
   763 void SlGlobList(const SaveLoadGlobVarList *sldg)
   775 void SlGlobList(const SaveLoadGlobVarList *sldg)
   764 {
   776 {
   765 	if (_sl.need_length != NL_NONE) {
   777 	if (_sl.need_length != NL_NONE) {
   766 		SlSetLength(SlCalcObjLength((const SaveLoad*)sldg));
   778 		SlSetLength(SlCalcObjLength(NULL, (const SaveLoad*)sldg));
   767 		if (_sl.need_length == NL_CALCLENGTH) return;
   779 		if (_sl.need_length == NL_CALCLENGTH) return;
   768 	}
   780 	}
   769 
   781 
   770 	for (; sldg->cmd != SL_END; sldg++) {
   782 	for (; sldg->cmd != SL_END; sldg++) {
   771 		SlObjectMember(sldg->address, (const SaveLoad*)sldg);
   783 		SlObjectMember(sldg->address, (const SaveLoad*)sldg);