Skip to content

Instantly share code, notes, and snippets.

@hasufell
Last active December 7, 2021 22:26
Show Gist options
  • Save hasufell/ce7c18ef3ad44d1d59b548206cdcb59d to your computer and use it in GitHub Desktop.
Save hasufell/ce7c18ef3ad44d1d59b548206cdcb59d to your computer and use it in GitHub Desktop.
{--
; ABNF for windows paths
; based on https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/62e862f4-2a51-452e-8eeb-dc4ff5ee33cc?redirectedfrom=MSDN
; missing: unix separators
filepath = namespace *"\" ( disk 1*"\" relative-path ; C:foo\bar is not valid
; namespaced paths are all absolute
/ disk *"\"
/ relative-path
)
/ UNC
/ [ disk ] *"\" relative-path
/ disk *"\"
relative-path = 1*(path-name 1*"\") [ file-name ] / file-name
path-name = 1*pchar
file-name = 1*pchar [ stream ]
; namespaces
namespace = file-namespace / device-namespace / nt-namespace
file-namespace = "\" "\" "?" "\"
device-namespace = "\" "\" "." "\"
nt-namespace = "\" "?" "?" "\"
UNC = "\\" 1*pchar "\" 1*pchar [ 1*"\" [ relative-path ] ]
disk = ALPHA ":"
stream = ":" 1*schar [ ":" 1*schar ] / ":" ":" 1*schar
; path compontent charactes (all printable chars except '\')
pchar = %x21-5B / %x5D-7E
; stream compontent charactes (all printable chars except '\' and ':')
schar = %x21-39 / %x3B-5B / %x5D-7E
--}
-- filepath = namespace *"\" ( disk 1*"\" relative-path ; C:foo\bar is not valid
-- ; namespaced paths are all absolute
-- / disk *"\"
-- / relative-path
-- )
-- / UNC
-- / [ disk ] *"\" relative-path
-- / disk *"\"
data WindowsFilePath = NS1 NameSpace [Separator] NSTail
| UNC1 UNC
| NN1 (Maybe Char) [Separator] RelFilePath
| NN2 Char [Separator]
-- ^ we allow ':' in filepaths, to let trash fall through
| E1 [Separator]
-- ^ another fallthrough case to allow empty paths
deriving (Show, Eq, Ord)
data NSTail = NST1 Char (NonEmpty Separator) RelFilePath
| NST2 Char [Separator]
| NST3 RelFilePath
deriving (Show, Eq, Ord)
-- UNC = "\\" 1*pchar "\" 1*pchar [ 1*"\" [ relative-path ] ]
data UNC = UNC Separator Separator
NonEmptyString
(NonEmpty Separator)
NonEmptyString
(Maybe (NonEmpty Separator, Maybe RelFilePath))
deriving (Show, Eq, Ord)
-- relative-path = 1*(path-name 1*"\") [ file-name ] / file-name
data RelFilePath = Rel1 (NonEmpty (String, (NonEmpty Separator))) (Maybe FileName)
| Rel2 FileName
deriving (Show, Eq, Ord)
-- file-name = 1*pchar [ stream ]
data FileName = FileName NonEmptyString (Maybe DataStream)
deriving (Show, Eq, Ord)
-- stream = ":" 1*schar [ ":" 1*schar ] / ":" ":" 1*schar
data DataStream = DS1 NonEmptyString (Maybe NonEmptyString)
| DS2 NonEmptyString -- ::datatype
deriving (Show, Eq, Ord)
data Separator = UnixSep
| WindowsSep
deriving (Show, Eq, Ord)
type NonEmptyString = NonEmpty String
-- | Windows API Namespaces
--
-- https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#namespaces
-- https://support.microsoft.com/en-us/topic/70b92942-a643-2f2d-2ac6-aad8acad49fb
-- https://superuser.com/a/1096784/854039
-- https://reverseengineering.stackexchange.com/a/15178
-- https://stackoverflow.com/a/25099634
--
-- namespace = file-namespace / device-namespace / nt-namespace
-- file-namespace = "\" "\" "?" "\"
-- device-namespace = "\" "\" "." "\"
-- nt-namespace = "\" "?" "?" "\"
data NameSpace = FileNameSpace
| DeviceNameSpace
| NTNameSpace
deriving (Show, Eq, Ord)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment