Binary Comma-Separated Values (BCSV)
BCSV (Binary Comma-Separated Values) stores tables of data in Animal Crossing: New Horizons. The table contains fixed-size rows and column descriptors. Field identifiers are stored as CRC32 hashes, rather than readable column names.
Structure
Section titled “Structure”All multi-byte numbers are little-endian. The file contains a header, an array of column descriptors, and an array of fixed-size rows.
Offsets in the header tables are relative to the beginning of the BCSV file. Offsets in the column and row structure tables are relative to the beginning of the corresponding record.
Header
Section titled “Header”The base header is 0x0C (12) bytes long. When the extended-header flag is nonzero, the total header size is 0x1C (28) bytes.
| Offset | Size | Type | Description |
|---|---|---|---|
0x00 |
4 | uint32 | Row count |
0x04 |
4 | uint32 | Size of each row, including its four-byte prefix and any padding |
0x08 |
2 | uint16 | Column count |
0x0A |
1 | uint8 | Has extended header: 0 = no, nonzero = yes (normally 1) |
0x0B |
1 | uint8 | Enum hash language: 0 = Japanese, nonzero = English |
The language flag selects the names used to decode hashed enum values. Column identifier hashes are unaffected.
Extended header
Section titled “Extended header”These bytes are present when HasExtendedHeader is nonzero:
| Offset | Size | Type | Description |
|---|---|---|---|
0x0C |
4 | byte[4] | Magic: VSCB (56 53 43 42), BCSV spelled backward |
0x10 |
12 | byte[12] | Extended metadata; meaning not confirmed |
Preserve the extended metadata when editing. Files without an extended header have no VSCB magic.
Column structure
Section titled “Column structure”The column descriptor array begins immediately after the header. It contains columnCount records, each 0x08 (8) bytes long.
| Offset | Size | Type | Description |
|---|---|---|---|
0x00 |
4 | uint32 | CRC32 hash of the field identifier |
0x04 |
4 | uint32 | Offset to this field’s data from the beginning of a row |
The descriptor does not explicitly store the field’s type or size. Its offset includes the row’s four-byte prefix: an offset of 0x04 refers to the first byte after that prefix.
Row structure
Section titled “Row structure”Rows begin immediately after the column descriptor array. Every row occupies the number of bytes specified by rowSize in the header.
In the checked game files, rows are aligned to four bytes: rowSize is a multiple of four and can include padding after the last field. Individual fields do not all begin at four-byte boundaries. A final one-byte value can therefore occupy a remaining span of two, three, or four bytes; use the field’s type to determine its value size.
| Offset | Size | Type | Description |
|---|---|---|---|
0x00 |
4 | uint32 | Backward distance from this row to the BCSV header |
0x04 |
rowSize - 4 |
Field data and padding | Values at the offsets specified by the column descriptors |
The row prefix lets the game find the owning table header:
headerAddress = rowAddress - rowPrefixAddress calculations
Section titled “Address calculations”For zero-based row index r and column index c:
headerSize = 0x1C if HasExtendedHeader != 0, otherwise 0x0CcolumnOffset = headerSize + c * 0x08rowsOffset = headerSize + columnCount * 0x08rowOffset = rowsOffset + r * rowSizevalueOffset = rowOffset + column[c].offsetThese offsets are relative to the beginning of the BCSV file.
Common types
Section titled “Common types”Identified field names commonly use these suffixes. Types are not stored in the column descriptors.
| Suffix | Storage size | Meaning |
|---|---|---|
s8 / u8 |
1 byte | Signed / unsigned 8-bit integer |
s16 / u16 |
2 bytes | Signed / unsigned 16-bit integer |
s32 / u32 |
4 bytes | Signed / unsigned 32-bit integer |
f32 |
4 bytes | IEEE 754 single-precision floating-point value |
stringN, such as string32 |
N bytes | Fixed-capacity inline UTF-8 string |
hshCstringRef |
4 bytes | Hash reference; determine the hash algorithm from the field’s reader |
Hash values can use CRC32 or MurmurHash3 x86_32 (seed 0), depending on the field. The .hshCstringRef suffix alone does not identify the algorithm; check the game’s field reader.
Field offsets can include padding, so the gap between fields does not reliably identify their types.
Strings and padding
Section titled “Strings and padding”stringN fields store UTF-8 text inside the row, with a capacity of N bytes, not characters. Read up to the first null byte or the end of that capacity.
When editing a string, keep its capacity and null termination, and pad unused bytes. Preserve other padding and field offsets; do not shift later fields or change the row size.