|
@@ -5,27 +5,36 @@ namespace Ppub {
|
|
|
|
|
|
public class Builder {
|
|
|
|
|
|
- private Invercargill.Sequence<BuilderAsset> assets {get; set;}
|
|
|
+ private Invercargill.Sequence<BuilderAsset> assets = new Invercargill.Sequence<BuilderAsset>();
|
|
|
|
|
|
private uint64 position = 0;
|
|
|
|
|
|
public void add_metadata(Metadata metadata) {
|
|
|
var data = (uint8[])metadata.to_string().to_utf8();
|
|
|
var mis = new MemoryInputStream.from_data(data);
|
|
|
- add_asset("metadata", "application/x-ppub-metadata", mis, data.length);
|
|
|
+ var compress = new CompressionInfo(mis);
|
|
|
+ mis.seek(0, SeekType.SET);
|
|
|
+ add_asset("metadata", "application/x-ppub-metadata", mis, empty<string>(), compress);
|
|
|
}
|
|
|
|
|
|
- public void add_asset(string name, string mimetype, InputStream stream, uint64 size) {
|
|
|
+ public void add_asset(string name, string mimetype, InputStream stream, Enumerable<string> flags, CompressionInfo compression) {
|
|
|
|
|
|
lock(assets) {
|
|
|
var asset = new BuilderAsset();
|
|
|
asset.name = name;
|
|
|
asset.start_location = position;
|
|
|
- asset.end_location = position + size;
|
|
|
+ asset.end_location = position + compression.size_in_ppub;
|
|
|
asset.mimetype = mimetype;
|
|
|
asset.stream = stream;
|
|
|
+
|
|
|
+ // Exclude any gzip flags, as we will add that later if we are compressing the content
|
|
|
+ asset.flags = flags.where(f => f != "gzip").to_collection();
|
|
|
+
|
|
|
+ if(compression.compress) {
|
|
|
+ asset.flags.add("gzip");
|
|
|
+ }
|
|
|
|
|
|
- position += size;
|
|
|
+ position += compression.size_in_ppub;
|
|
|
assets.add(asset);
|
|
|
}
|
|
|
|
|
@@ -33,21 +42,28 @@ namespace Ppub {
|
|
|
|
|
|
public void write(OutputStream stream) throws IOError {
|
|
|
|
|
|
- var index_entries = assets.select<string>(a => a.to_string() + "\n").to_array();
|
|
|
- var index_data = (uint8[])string.join("", index_entries).to_utf8();
|
|
|
- var header_data = (uint8[])(@"$(index_data.length)\n".to_utf8());
|
|
|
+ var index_entries = assets.to_string(a => a.to_string());
|
|
|
+
|
|
|
+ print(index_entries);
|
|
|
+ var index_data = (uint8[])index_entries.to_utf8();
|
|
|
+ var header_data = (uint8[])(@"$(Publication.MAGIC)\n$(index_data.length)\n".to_utf8());
|
|
|
|
|
|
stream.write(header_data);
|
|
|
stream.write(index_data);
|
|
|
|
|
|
foreach (var asset in assets.as_iterable()) {
|
|
|
- stream.splice(asset.stream, OutputStreamSpliceFlags.CLOSE_SOURCE);
|
|
|
+ if(asset.flags.contains("gzip")) {
|
|
|
+ var compressor = new ZlibCompressor(ZlibCompressorFormat.GZIP, 9);
|
|
|
+ var conv_stream = new ConverterInputStream(asset.stream, compressor);
|
|
|
+ stream.splice(conv_stream, OutputStreamSpliceFlags.CLOSE_SOURCE);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ stream.splice(asset.stream, OutputStreamSpliceFlags.CLOSE_SOURCE);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
}
|
|
|
|
|
|
public class BuilderAsset : Asset {
|
|
@@ -56,4 +72,52 @@ namespace Ppub {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ public class CompressionInfo {
|
|
|
+
|
|
|
+ public bool compress {get; private set;}
|
|
|
+ public uint64 uncompressed_size {get; private set;}
|
|
|
+ public uint64 compressed_size {get; private set;}
|
|
|
+
|
|
|
+ public CompressionInfo.uncompressed(uint64 size) {
|
|
|
+ compress = false;
|
|
|
+ uncompressed_size = size;
|
|
|
+ }
|
|
|
+
|
|
|
+ public CompressionInfo(InputStream stream, bool force = false) throws IOError {
|
|
|
+ var uncompressed_counter = new InputStreamMonitor(stream);
|
|
|
+ var compressor = new ZlibCompressor(ZlibCompressorFormat.GZIP, 9);
|
|
|
+ var conv_stream = new ConverterInputStream(uncompressed_counter, compressor);
|
|
|
+ var compressed_counter = new InputStreamMonitor(conv_stream);
|
|
|
+
|
|
|
+ compressed_counter.count_to_end();
|
|
|
+
|
|
|
+ uncompressed_size = uncompressed_counter.bytes_read;
|
|
|
+ compressed_size = compressed_counter.bytes_read;
|
|
|
+
|
|
|
+ compress = force || uncompressed_size > compressed_size;
|
|
|
+ }
|
|
|
+
|
|
|
+ public uint64 size_in_ppub {
|
|
|
+ get {
|
|
|
+ return compress ? compressed_size : uncompressed_size;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public static string guess_mimetype(string name, uint8[] sample) {
|
|
|
+ if(name == "metadata") {
|
|
|
+ return "application/x-ppub-metadata";
|
|
|
+ }
|
|
|
+ if(name.has_suffix(".ppvm")) {
|
|
|
+ return "application/x-ppvm";
|
|
|
+ }
|
|
|
+
|
|
|
+ bool result_uncertain;
|
|
|
+ var content_type = ContentType.guess(name, sample, out result_uncertain);
|
|
|
+ var mime = ContentType.get_mime_type(content_type);
|
|
|
+
|
|
|
+ return mime ?? "application/octet-stream";
|
|
|
+ }
|
|
|
+
|
|
|
}
|