diff options
Diffstat (limited to 'libdino/src/util')
-rw-r--r-- | libdino/src/util/limit_input_stream.vala | 73 | ||||
-rw-r--r-- | libdino/src/util/util.vala | 31 |
2 files changed, 104 insertions, 0 deletions
diff --git a/libdino/src/util/limit_input_stream.vala b/libdino/src/util/limit_input_stream.vala new file mode 100644 index 00000000..5569d778 --- /dev/null +++ b/libdino/src/util/limit_input_stream.vala @@ -0,0 +1,73 @@ +public class Dino.LimitInputStream : InputStream, PollableInputStream { + private InputStream inner; + public int64 max_bytes { public get; private set; } + public int64 retrieved_bytes { public get; private set; } + + public int64 remaining_bytes { get { + return max_bytes < 0 ? -1 : max_bytes - retrieved_bytes; + }} + + public LimitInputStream(InputStream inner, int64 max_bytes) { + this.inner = inner; + this.max_bytes = max_bytes; + } + + public bool can_poll() { + return inner is PollableInputStream && ((PollableInputStream)inner).can_poll(); + } + + public PollableSource create_source(Cancellable? cancellable = null) { + if (!can_poll()) throw new IOError.NOT_SUPPORTED("Stream is not pollable"); + return ((PollableInputStream)inner).create_source(cancellable); + } + + public bool is_readable() { + if (!can_poll()) throw new IOError.NOT_SUPPORTED("Stream is not pollable"); + return remaining_bytes == 0 || ((PollableInputStream)inner).is_readable(); + } + + private ssize_t check_limit(ssize_t read) throws IOError { + if (remaining_bytes - (int64) read < 0) throw new IOError.FAILED("Stream length exceeded limit"); + this.retrieved_bytes += read; + return read; + } + + public override ssize_t read(uint8[] buffer, Cancellable? cancellable = null) throws IOError { + if (remaining_bytes == 0) return 0; + int original_buffer_length = buffer.length; + if (remaining_bytes != -1 && (int64) buffer.length > remaining_bytes) { + // Never read more than remaining_bytes by limiting the buffer length + buffer.length = (int) remaining_bytes; + } + ssize_t read_bytes = inner.read(buffer, cancellable); + this.retrieved_bytes += read_bytes; + buffer.length = original_buffer_length; + return read_bytes; + } + + public override async ssize_t read_async(uint8[]? buffer, int io_priority = GLib.Priority.DEFAULT, Cancellable? cancellable = null) throws IOError { + if (remaining_bytes == 0) return 0; + int original_buffer_length = buffer.length; + if (remaining_bytes != -1 && (int64) buffer.length > remaining_bytes) { + // Never read more than remaining_bytes by limiting the buffer length + buffer.length = (int) remaining_bytes; + } + ssize_t read_bytes = yield inner.read_async(buffer, io_priority, cancellable); + this.retrieved_bytes += read_bytes; + buffer.length = original_buffer_length; + return read_bytes; + } + + public ssize_t read_nonblocking_fn(uint8[] buffer) throws Error { + if (!is_readable()) throw new IOError.WOULD_BLOCK("Stream is not readable"); + return read(buffer); + } + + public override bool close(Cancellable? cancellable = null) throws IOError { + return inner.close(cancellable); + } + + public override async bool close_async(int io_priority = GLib.Priority.DEFAULT, Cancellable? cancellable = null) throws IOError { + return yield inner.close_async(io_priority, cancellable); + } +}
\ No newline at end of file diff --git a/libdino/src/util/util.vala b/libdino/src/util/util.vala index 9f7ae45f..31f4c105 100644 --- a/libdino/src/util/util.vala +++ b/libdino/src/util/util.vala @@ -1,3 +1,6 @@ +using Gee; +using Xmpp; + namespace Dino { private extern const string SYSTEM_LIBDIR_NAME; @@ -90,4 +93,32 @@ public static void internationalize(string gettext_package, string locales_dir) Intl.bindtextdomain(gettext_package, locales_dir); } +public static async HashMap<ChecksumType, string> compute_file_hashes(File file, Gee.List<ChecksumType> checksum_types) { + var checksums = new Checksum[checksum_types.size]; + + for (int i = 0; i < checksum_types.size; i++) { + checksums[i] = new Checksum(checksum_types.get(i)); + } + + FileInputStream stream = yield file.read_async(); + uint8 fbuf[1024]; + size_t size; + while ((size = yield stream.read_async(fbuf)) > 0) { + for (int i = 0; i < checksum_types.size; i++) { + checksums[i].update(fbuf, size); + } + } + + var ret = new HashMap<ChecksumType, string>(); + for (int i = 0; i < checksum_types.size; i++) { + var checksum_type = checksum_types.get(i); + uint8[] digest = new uint8[64]; + size_t length = digest.length; + checksums[i].get_digest(digest, ref length); + string computed_hash = GLib.Base64.encode(digest[0:length]); + ret[checksum_type] = computed_hash; + } + return ret; +} + } |