def getMetadata(self, virtual_path: str) -> Dict[str, Any]:
        if not self._stream:
            raise ValueError("Can't get metadata from a closed file.")
        assert self._zipfile is not None

        if self._mode == OpenMode.WriteOnly:
            raise WriteOnlyError(virtual_path)
        canonical_path = self._processAliases(virtual_path)

        # Find all metadata that begins with the specified virtual path!
        result = {}

        if canonical_path in self._metadata:  # The exact match.
            result[self._metadata_prefix + virtual_path] = self._metadata[canonical_path]
        for entry_path, value in self._metadata.items():
            # We only want to match subdirectories of the provided virtual paths.
            # So if you provide "/foo" then we don't want to match on "/foobar"
            # but we do want to match on "/foo/zoo". This is why we check if they
            # start with the provided virtual path plus a slash.
            if entry_path.startswith(canonical_path + "/"):
                # We need to return the originally requested alias, so replace the canonical path with the virtual path.
                result[self._metadata_prefix + virtual_path + "/" + entry_path[len(canonical_path) + 1:]] = value

        # If requesting the size of a file.
        if canonical_path.endswith("/size"):
            requested_resource = canonical_path[:-len("/size")]
            if self._resourceExists(requested_resource):
                result[self._metadata_prefix + virtual_path] = self._zipfile.getinfo(
                    requested_resource.strip("/")).file_size

        return result
    def toByteArray(self, offset: int = 0, count: int = -1) -> bytes:
        if not self._stream:
            raise ValueError("Can't get the bytes from a closed file.")
        if self._mode == OpenMode.WriteOnly:
            raise WriteOnlyError()
        assert self._zipfile is not None
        assert self._mode is not None

        self._zipfile.close()  # Close the zipfile first so that we won't be messing with the stream without its consent.

        self._stream.seek(offset)
        result = self._stream.read(count)

        self._zipfile = zipfile.ZipFile(self._stream, self._mode.value, compression=zipfile.ZIP_DEFLATED)
        return result
    def getData(self, virtual_path: str) -> Dict[str, Any]:
        if not self._stream:
            raise ValueError("Can't get data from a closed file.")
        assert self._zipfile is not None

        if self._mode == OpenMode.WriteOnly:
            raise WriteOnlyError(virtual_path)

        result = {}  # type: Dict[str, Any]
        if virtual_path.startswith(self._metadata_prefix):
            result = self.getMetadata(virtual_path[len(self._metadata_prefix):])
        else:
            canonical_path = self._processAliases(virtual_path)
            if self._resourceExists(canonical_path):
                result[virtual_path] = self.getStream(
                    canonical_path).read()  # In case of a name clash, the file wins. But that shouldn't be possible.

        return result