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