Crate xnde

source ·
Expand description



Ex-NDE (Nullsoft Database Engine); Extract-NDE. Extricate your data from your Winamp Music Library database.

This (binary) crate includes logic as well as a small program for reading your Winamp Music Library database & dumping the contents to other (hopefully more convenient) formats. It does not attempt a full re-implementation of the Nullsoft Database Engine (see here for thoughts on that); it just reads the main table of the Music Library database & dumps the contents.

Not only is this is my first Rust crate, but the implementation is incomplete (see fields, e.g.), and the code is generally littered with assorted TODO comments marking things I’d like to do better, or more elegantly, or at all. That said, the point to this crate is to get my data out of an archaic format & into one I can use more readily. I’ve accomplished that, so I don’t know how much time I want to spend polishing the implementation. PRs, suggestions & complaints welcome!


Indicies and Tables

Despite its name, the Nullsoft Database Engine is not a full-featured RDMS. True to the coding ethos that characterized Winamp generally, it was a tightly-coded, purpose-built implementation that produced extremely compact representations on disk.

A “table” in NDE parlance is a collection of records. On disk, it is described by two files:

  1. the “data” file (.dat) in which the table’s records are serialized in a very space efficient manner

  2. the “index” file (.idx) which describes how to traverse the data file in various orders

The index file is described below. See fields for details on the data file.

File Formats

Index File Format

The top-level structure of the index file is:

    | "NDEINDEX" | no. records | primary idx | aux idx...  |

The first element is a signature marking the file’s purpose in the form of the string “NDEINDEX” in ASCII/UTF-8 format. The second is the number of records in the table (and hence the number of elements in each index), expressed as a 32-bit little-endian unsigned integer.

Each index has the following format:

    | idx ID | record location... |

The index ID is a 32-bit little-endian unsigned integer. The only significance to the ID I could find in the code is that the required primary index has an ID of 255 (or PRIMARY_INDEX).

There is no “end-of-record” marker; since each record location is a constant size (eight bytes), one simply reads the expected number of bytes seqeuntially after reading the number of records. There is also no indication of how many indicies the file contains; one simply reads chunks of no. records * 8 bytes until EoF is reached.

Each records is two 32-bit integers:

    | offset | ???? |

The first element is a 32-bit little-endian unsigned int giving the offset into the datafile of a record. The question marks for the second element are because I never figured out what this was for.





  • Dump the contents of a Winamp Music Library to stdout
  • transform your Winamp music library into an in-memory datastructure and serialize it to any variety of formats via Serde.
  • Read all indicies out of an index file; rdr is assumed to be pointing at the signature (i.e. byte zero if we’re reading a .idx file)

Type Definitions