diff --git a/src/dbpf/package.d b/src/dbpf/package.d index 9405644..9bd2b2c 100644 --- a/src/dbpf/package.d +++ b/src/dbpf/package.d @@ -234,6 +234,14 @@ struct File(bool Compressed = Flag!"compressed" = false) { } } +/// Thrown when an `Archive` is invalid or corrupt. +class ArchiveException : Exception { + import std.exception : basicExceptionCtors; + + /// + mixin basicExceptionCtors; +} + /// Determines whether `DBPF and `V` are valid DBPF and Index table versions. /// See_Also: $(UL /// $(LI `isValidDbpfVersion`) @@ -245,6 +253,8 @@ enum isValidVersion(float DBPF, float V) = isValidDbpfVersion!DBPF && isValidInd /// struct Archive(float DBPF = 1, float V = 7.0) if (isValidVersion!(DBPF, V)) { alias Head = Header!DBPF; + static if (V == 7.0) alias Table = Entry; + else static if (V == 7.1) alias Table = ResourceEntry; import std.exception : enforce; @@ -254,31 +264,34 @@ struct Archive(float DBPF = 1, float V = 7.0) if (isValidVersion!(DBPF, V)) { /// Head metadata; /// - static if (V == 7.0) Entry[] entries; - /// ditto - static if (V == 7.1) ResourceEntry[] entries; + Table[] entries; /// Open a DBPF archive from the given file `path`. + /// Throws: `FileException` when the archive is not found, or there is some I/O error. + /// Throws: `ArchiveException` when the archive is invalid or corrupt. this(string path) { import std.algorithm : equal; - import std.conv : parse, text, to; + import std.conv : text, to; + import std.file : exists, FileException; + import std.string : format; + if (!path.exists) throw new FileException(path, "File does not exist: " ~ path); this.path = path; this.file = std.stdio.File(path, "rb"); assert(this.file.size >= Head.sizeof); this.file.rawRead!Head((&metadata)[0..1]); - enforce(metadata.magic[].equal(Head.identifier), "Input is not a DBPF archive."); + enforce(metadata.magic[].equal(Head.identifier), "File is not a DBPF archive."); // Ensure file version matches expectation - debug const version_ = metadata.version_.major.text ~ "." ~ metadata.version_.minor.text; - assert( - parse!float(version_) == DBPF, + const version_ = metadata.version_.major.text ~ "." ~ metadata.version_.minor.text; + enforce( + version_.to!float == DBPF, "Mismatched DBPF version. Expected " ~ DBPF.text ~ ", but saw " ~ version_ ); // Ensure index version matches expectation - assert( + enforce( V == 7.1 ? metadata.indexMinorVersion == 2 : true, - "Mismatched index version. Expected " ~ V.text ~ ", but saw " ~ metadata.indexMinorVersion.text + "Mismatched index version. Expected " ~ 2.format!"%x" ~ ", but saw " ~ metadata.indexMinorVersion.format!"%x" ); auto filesOffset = this.file.tell; @@ -297,3 +310,12 @@ struct Archive(float DBPF = 1, float V = 7.0) if (isValidVersion!(DBPF, V)) { file.close(); } } + +unittest { + import core.exception : AssertError; + import std.exception : assertThrown; + import std.file : FileException; + + alias Data = Archive!(); + assertThrown!FileException(new Data("/tmp/voidAndNull")); +}