async Task <bool> ReadEntry(HttpClient httpClient, Uri url, CDHeader cdh, BinaryReader br, string destinationDirectory) { Context context = Context.Instance; string destFilePath = Path.Combine(destinationDirectory, Path.GetFileName(cdh.FileName)); string compressedFilePath = Path.Combine(destinationDirectory, $"{destFilePath}.deflated"); Log.Status($" {context.Characters.Bullet} {Path.GetFileName (cdh.FileName)} "); Log.Status($"{context.Characters.RightArrow}", ConsoleColor.Cyan); Log.StatusLine($" {Utilities.GetRelativePath (BuildPaths.XamarinAndroidSourceRoot, destFilePath)}"); Log.DebugLine($" {cdh.FileName} (offset: {cdh.RelativeOffsetOfLocalHeader})"); (bool success, Stream contentStream) = await ReadFileData(httpClient, url, cdh); if (!success) { Log.ErrorLine("Failed to read file data"); return(false); } using (var destFile = new BinaryWriter(File.OpenWrite(compressedFilePath))) { using (var fbr = new BinaryReader(contentStream)) { if (!await DownloadAndExtract(fbr, contentStream, destFile, compressedFilePath)) { return(CleanupAndReturn(false)); } } } return(CleanupAndReturn(true)); bool CleanupAndReturn(bool retval) { if (File.Exists(compressedFilePath)) { File.Delete(compressedFilePath); } return(retval); } }
async Task <(bool success, Stream data)> ReadFileData(HttpClient httpClient, Uri url, CDHeader cdh) { long fileOffset = cdh.RelativeOffsetOfLocalHeader; long dataSize = cdh.CompressedSize + 30 + // local file header size, the static portion cdh.FileName.Length + // They're the same in both haders cdh.ExtraFieldLength + // This may differ between headers... 16384; // ...so we add some extra padding var req = new HttpRequestMessage(HttpMethod.Get, url); req.Headers.ConnectionClose = true; req.Headers.Range = new RangeHeaderValue(fileOffset, fileOffset + dataSize); HttpResponseMessage resp = await httpClient.SendAsync(req).ConfigureAwait(false); if (!resp.IsSuccessStatusCode) { Log.ErrorLine($"Failed to read file data: HTTP error {resp.StatusCode}"); return(false, null); } Stream s = await resp.Content.ReadAsStreamAsync().ConfigureAwait(false); if (s.Length < dataSize) { Log.ErrorLine($"Failed to read file data: invalid data length ({s.Length} < {dataSize})"); s.Dispose(); return(false, null); } return(true, s); }