Skip to content

Fix null-terminated string handling in DAT files#7

Merged
redtoad merged 1 commit intosupport-all-filesfrom
fix/null-strings
Jan 30, 2026
Merged

Fix null-terminated string handling in DAT files#7
redtoad merged 1 commit intosupport-all-filesfrom
fix/null-strings

Conversation

@redtoad
Copy link
Owner

@redtoad redtoad commented Jan 30, 2026

Summary

  • Replace the broken NullString.Unpack method with a String() method that strips at the first null byte on access. The old Unpack consumed the
    entire remaining buffer, breaking parsing of any struct with fields after the name.
  • Use NullString type for Name fields in SaveinfoFile, SoldierData, and BaseData so null-terminated strings are handled correctly throughout.
  • Fix two pre-existing round-trip issues: name the anonymous _ field in SaveinfoFile so its value is preserved on pack, and widen BaseData.Active
    from int8 to int32 to cover the full 292-byte record.

Test plan

  • NullString.String() strips at null byte and handles missing null
  • NullString works in multi-field structs (new test)
  • Multi-field NullString round-trips correctly (unpack → pack = identical bytes)
  • SaveinfoFile name parsing returns clean strings ("Test", not "Test\x00...")
  • SaveinfoFile round-trip produces identical binary output
  • SoldierFile round-trip produces identical binary output (250 records, 17 KB)
  • All existing tests pass

🤖 Generated with Claude Code

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes parsing/round-tripping of null-terminated fixed-size strings in X-COM DAT files by removing a broken custom unpacker and switching affected DAT structs to a NullString representation that trims at the first NUL on access.

Changes:

  • Replace NullString.Unpack with NullString.String() and migrate name fields to NullString (soldiers, bases, save metadata).
  • Fix SAVEINFO.DAT round-tripping by making the missdat flag field exported and preserving the full 40-byte record.
  • Adjust BASE.DAT record layout by widening the Active field storage to cover the full 4-byte value.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
savegame/soldiers.go Use NullString.String() for soldier names and empty checks.
savegame/metadata.go Return save title via NullString.String().
savegame/bases.go Use NullString.String() for base names and presence checks.
internal/types.go Remove broken unpacker and add NullString.String() truncation behavior.
internal/types_test.go Update and expand tests for NullString.String() and multi-field round-trip.
internal/geoscape/soldier_dat.go Store soldier name as internal.NullString in SOLDIER.DAT struct.
internal/geoscape/soldier_dat_test.go Adapt tests for NullString name handling.
internal/geoscape/saveinfo_dat.go Store save name as NullString and export missdat flag field.
internal/geoscape/saveinfo_dat_test.go Add tests for SAVEINFO.DAT name parsing and round-trip.
internal/geoscape/base_dat.go Store base name as NullString and widen Active storage to 4 bytes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Replace the broken NullString.Unpack method (which consumed the entire
remaining buffer, breaking multi-field structs) with a String() method
that strips at the first null byte on access. Use NullString type for
Name fields in SaveinfoFile, SoldierData, and BaseData.

Also fix two pre-existing round-trip issues: rename the unnamed field
in SaveinfoFile so its value is preserved, and widen BaseData.Active
from int8 to int32 to cover the full 292-byte record.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@redtoad redtoad marked this pull request as ready for review January 30, 2026 10:16
@redtoad redtoad merged commit 56de438 into support-all-files Jan 30, 2026
@redtoad redtoad deleted the fix/null-strings branch January 30, 2026 10:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant