Skip to content
dream-path
guide

Normalization

The four rules, the bytes they leave alone, and the literal results that follow.

A normalized path is the key every lookup agrees on. The rules that produce it are few and deliberately literal, because every component that uses the crate has to get byte-for-byte the same answer.

The rules#

InputBecomes
\/
ASCII A to Za to z
Two or more separators in a rowOne /
Separators at the startNothing

Every other byte passes through unchanged. Normalizing an already-normalized path returns it as it is, so it is always safe to normalize twice.

What comes out#

PathNormalized
Textures\Tx_Wood_01.DDStextures/tx_wood_01.dds
/Textures/Foo.ddstextures/foo.dds
Meshes//x\\Ex_Door.NIFmeshes/x/ex_door.nif
///the empty path
Music/Explore/music/explore/
Sound/Fx/../FX/Door.WAVsound/fx/../fx/door.wav
C:\Morrowind\Data Filesc:/morrowind/data files
HTTP://Example/Foohttp:/example/foo
Été/Ärger.DDSÉté/Ärger.dds
DIR/\xff/FILEdir/\xff/file
FOO\0BARfoo\0bar

\xff and \0 stand for the single bytes 0xFF and 0x00.

Some of those are surprising on purpose:

  • A trailing separator stays. music/explore/ and music/explore are different keys.
  • The empty path is a path. /// normalizes to zero bytes.
  • .. is just two dots. Nothing is resolved; sound/fx/../fx/door.wav is its own key.
  • Host syntax is not recognized. A drive letter or a URI scheme is normalized like any other text, and comes out mangled.
  • Only ASCII changes case. É stays É: non-ASCII bytes are data, not letters.
  • Invalid UTF-8 and NUL bytes survive. A path is bytes, and whatever encoding a plugin or archive used is preserved.

A loader that needs a file-like resource should reject empty paths and trailing separators at its own boundary. This crate only defines the spelling.

What it does not do#

Each of these is a separate job, done by the code that knows the context:

  • Decoding legacy encodings. Morrowind-era data carries Windows code pages; which one is a question for the reader of that data.
  • Unicode normalization or case folding. Two spellings of É stay two keys.
  • Resolving paths. No . or .., no roots, no drive letters, no URIs. A glTF importer that resolves relative URIs does that before it asks for a key.
  • Host file system paths. A normalized path is a key into a virtual file system, not something to open.
  • Archive hashes. BSA and BA2 have their own hash rules; the archive crate owns them.

Normalized, exactly#

is_normalized_path(bytes) is true when normalizing bytes would not change them: no ASCII uppercase, no \, no leading separator, no two separators in a row. It says nothing else about the path. The empty path, c:/foo, a/../b and bytes that are not UTF-8 are all normalized.