Skip to content

Commit

Permalink
Improve robustness of Archive file handling
Browse files Browse the repository at this point in the history
  • Loading branch information
chances committed Jul 2, 2024
1 parent 7f53b65 commit fcda27f
Showing 1 changed file with 25 additions and 3 deletions.
28 changes: 25 additions & 3 deletions src/dbpf/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -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`)
Expand All @@ -259,26 +267,31 @@ struct Archive(float DBPF = 1, float V = 7.0) if (isValidVersion!(DBPF, V)) {
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 : 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
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;

Expand All @@ -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"));
}

0 comments on commit fcda27f

Please sign in to comment.