Skip to content

Stupid Valve Format (SVF)

Derek Morris edited this page Oct 5, 2015 · 7 revisions

Introduction

Stupid Valve Format, or SVF, is a format that was first introduced with the release of the Dota 2 Workshop Tools, the first public release of the Source 2 engine. The main purpose of the format is to standardize and consolidate most of Valve's formats; since its introduction, the number of binary release formats used in the source 2 engine has dropped to 4 (SVF, VPK, DMX, and VCS). It serves as an attempt to handle resource dependencies more smoothly, such that code in the engine only needs to reference a resource directly and all of the dependent resources will be properly loaded automatically.

The name comes from the early stages in reverse engineering it; the file format has some pretty stupid design decisions, and breaks a few guidelines for file format design that make it harder to deal with. As there is no magic number to guide naming intentions, as well as no official name given in any tools or symbols, Stupid Valve Format is the most commonly recognized and non-ambiguous name assigned to the format.

In practice, those identifying files in Valve games in the Source 2 engine should consider that things may be in SVF if they have a _c at the end of their extension (e.g. .vmdl_c, .vxml_c). This isn't a hard rule for either positive or negative identification; inspection of the data revealing the strings REDI, NTRO, RERL, or DATA would also indicate that it is likely SVF. Only a couple of variants of SVF are known to exist, and for brevity (and for lack of interest) we'll only cover the currently released version here.

Binary Format

Header

(Don't look at how I formatted this too closely - GitHub is awful for wide tables) (All values are little-endian uint32 unless otherwise specified)

- 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
0x00 file length* 0x0C version num
0x08 OFFSETCOUNT lumps
Note that there is no magic number for this file format. The file length value, which is the first value in the file, is also often incorrect, so it shouldn't be depended upon for allocation purposes. What follows the file header is *nl* lump tag headers, formatted as follows:
- 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
0x00 lump tag, 4 chars OFFS(lump offset)
0x08 lump length, incl. header
The lump tag identifies which lump is being referenced; this can be any of "RERL", "REDI", "DATA", etc. The lump offset is handled similarly to many other offsets in this file format, in that it is a relative offset from the offset location itself (that is to say, if the lump tag header begins at 0x10, the offset is at 0x14 and has value 0x30, the referenced data is at 0x44). This is referenced throughout this documentation with OFFS tags (and if you look at the accompanying C code, the OFFS macro is used to handle these values).