aboutsummaryrefslogtreecommitdiff
path: root/libdino/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'libdino/src/util')
-rw-r--r--libdino/src/util/limit_input_stream.vala73
-rw-r--r--libdino/src/util/util.vala31
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;
+}
+
}