1class Gitg.DiffViewFileInfo : Object
2{
3	public Ggit.DiffDelta delta { get; construct set; }
4	public bool from_workdir { get; construct set; }
5	public Repository? repository { get; construct set; }
6
7	public InputStream? new_file_input_stream { get; set; }
8	public string? new_file_content_type { get; private set; }
9
10	public DiffViewFileInfo(Repository? repository, Ggit.DiffDelta delta, bool from_workdir)
11	{
12		Object(repository: repository, delta: delta, from_workdir: from_workdir);
13	}
14
15	public async void query(Cancellable? cancellable)
16	{
17		yield query_content(cancellable);
18	}
19
20	private async void query_content(Cancellable? cancellable)
21	{
22		var file = delta.get_new_file();
23		var id = file.get_oid();
24		var path = file.get_path();
25
26		if (repository == null || (id.is_zero() && !from_workdir) || (path == null && from_workdir))
27		{
28			return;
29		}
30
31		var workdir = repository.get_workdir();
32		File location = workdir != null ? workdir.get_child(path) : null;
33
34		if (!from_workdir)
35		{
36			Ggit.Blob blob;
37
38			try
39			{
40				blob = repository.lookup<Ggit.Blob>(id);
41			}
42			catch (Error e)
43			{
44				return;
45			}
46
47			var bytes = new Bytes(blob.get_raw_content());
48			new_file_input_stream = new GLib.MemoryInputStream.from_bytes(bytes);
49		}
50		else if (location != null)
51		{
52			// Try to read from disk
53			try
54			{
55				new_file_input_stream = yield location.read_async(Priority.DEFAULT, cancellable);
56			}
57			catch
58			{
59				return;
60			}
61		}
62
63		var seekable = new_file_input_stream as Seekable;
64
65		if (seekable != null && seekable.can_seek())
66		{
67			// Read a little bit of content to guess the type
68			yield guess_content_type(new_file_input_stream, location != null ? location.get_basename() : null, cancellable);
69
70			try
71			{
72				seekable.seek(0, SeekType.SET, cancellable);
73			}
74			catch (Error e)
75			{
76				stderr.printf("Failed to seek back to beginning of stream...\n");
77				new_file_input_stream = null;
78			}
79		}
80	}
81
82	private async void guess_content_type(InputStream stream, string basename, Cancellable? cancellable)
83	{
84		var buffer = new uint8[4096];
85		size_t bytes_read = 0;
86
87		try
88		{
89			yield stream.read_all_async(buffer, Priority.DEFAULT, cancellable, out bytes_read);
90		}
91		catch (Error e)
92		{
93			if (bytes_read <= 0)
94			{
95				return;
96			}
97		}
98
99		buffer.length = (int)bytes_read;
100
101		bool uncertain;
102		new_file_content_type = GLib.ContentType.guess(basename, buffer, out uncertain);
103
104	}
105}