|
@@ -3,32 +3,20 @@ using Gee;
|
|
|
|
|
|
namespace Ppub {
|
|
|
|
|
|
- public class Publication {
|
|
|
-
|
|
|
+ public abstract class Publication {
|
|
|
public const string MAGIC = "ppub";
|
|
|
|
|
|
- public Enumerable<Asset> assets {get; private set;}
|
|
|
-
|
|
|
- public Metadata metadata {get; private set;}
|
|
|
-
|
|
|
- private uint64 asset_offset;
|
|
|
- private File ppub_file;
|
|
|
-
|
|
|
- public Publication(string path) throws Error {
|
|
|
- ppub_file = File.new_for_path(path);
|
|
|
- from_stream(ppub_file.read());
|
|
|
- metadata = new Metadata.from_stream(read_asset("metadata"));
|
|
|
- }
|
|
|
+ public Enumerable<Asset> assets {get; protected set;}
|
|
|
+ public Metadata metadata {get; protected set;}
|
|
|
|
|
|
- private void from_stream(InputStream stream) throws Error {
|
|
|
- var dis = new DataInputStream(stream);
|
|
|
- var magic = dis.read_line();
|
|
|
+ protected void read_header(DataInputStream stream) throws Error {
|
|
|
+ var magic = stream.read_line();
|
|
|
if(magic != MAGIC) {
|
|
|
throw new IOError.INVALID_DATA("Invalid magic number");
|
|
|
}
|
|
|
|
|
|
- var asset_index_size = int.parse(dis.read_line());
|
|
|
- var asset_index_data = ((string)dis.read_bytes(asset_index_size).get_data()).split("\n");
|
|
|
+ var asset_index_size = int.parse(stream.read_line());
|
|
|
+ var asset_index_data = ((string)stream.read_bytes(asset_index_size).get_data()).split("\n");
|
|
|
|
|
|
var asset_seq = new Series<Asset>();
|
|
|
foreach (var index_data in asset_index_data) {
|
|
@@ -38,15 +26,39 @@ namespace Ppub {
|
|
|
}
|
|
|
|
|
|
assets = asset_seq;
|
|
|
- asset_offset = dis.tell();
|
|
|
- dis.close();
|
|
|
}
|
|
|
|
|
|
- public Asset? get_asset(string name) {
|
|
|
+ public virtual Asset? get_asset(string name) {
|
|
|
return assets.where(a => a.name == name).first_or_default();
|
|
|
}
|
|
|
|
|
|
- public InputStream? read_asset(string name) throws Error {
|
|
|
+ public virtual Asset get_default_asset() {
|
|
|
+ return assets.skip(1).first_or_default();
|
|
|
+ }
|
|
|
+
|
|
|
+ public abstract InputStream? read_asset(string name) throws Error;
|
|
|
+ public abstract async InputStream? read_asset_async(string name) throws Error;
|
|
|
+ }
|
|
|
+
|
|
|
+ public class FilePublication : Publication {
|
|
|
+
|
|
|
+ private uint64 asset_offset;
|
|
|
+ private File ppub_file;
|
|
|
+
|
|
|
+ public FilePublication(string path) throws Error {
|
|
|
+ ppub_file = File.new_for_path(path);
|
|
|
+ from_stream(ppub_file.read());
|
|
|
+ metadata = new Metadata.from_stream(read_asset("metadata"));
|
|
|
+ }
|
|
|
+
|
|
|
+ private void from_stream(InputStream stream) throws Error {
|
|
|
+ var dis = new DataInputStream(stream);
|
|
|
+ read_header(dis);
|
|
|
+ asset_offset = dis.tell();
|
|
|
+ dis.close();
|
|
|
+ }
|
|
|
+
|
|
|
+ public override InputStream? read_asset(string name) throws Error {
|
|
|
var asset = get_asset(name);
|
|
|
if(asset == null) {
|
|
|
return null;
|
|
@@ -63,8 +75,21 @@ namespace Ppub {
|
|
|
return asset_stream;
|
|
|
}
|
|
|
|
|
|
- public Asset get_default_asset() {
|
|
|
- return assets.skip(1).first_or_default();
|
|
|
+ public override async InputStream? read_asset_async(string name) throws Error {
|
|
|
+ var asset = get_asset(name);
|
|
|
+ if(asset == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ var stream = yield ppub_file.read_async(Priority.DEFAULT);
|
|
|
+ var asset_stream = new AssetStream(asset, stream, asset_offset + asset.start_location);
|
|
|
+
|
|
|
+ if(asset.flags.any(f => f == "gzip")) {
|
|
|
+ var converter = new ZlibDecompressor(GLib.ZlibCompressorFormat.GZIP);
|
|
|
+ return new ConverterInputStream(asset_stream, converter);
|
|
|
+ }
|
|
|
+
|
|
|
+ return asset_stream;
|
|
|
}
|
|
|
|
|
|
}
|