private void previewToolStripMenuItem_Click(object sender, EventArgs e) { var menuItem = sender as ToolStripMenuItem; var source = (menuItem.Owner as ContextMenuStrip).SourceControl as TreeView; DatFile df = source?.SelectedNode?.Tag as DatFile; tbInfo.Text = null; tbRaw.Text = null; tbAscii.Text = null; pbPreview.Image = null; pbPreview.Tag = null; // Select the clicked node if (df != null) { StringBuilder sbInfo = new StringBuilder(); StringBuilder sbRaw = new StringBuilder(); StringBuilder sbAscii = new StringBuilder(); string extraInfo = null; string contentDescription = null; byte[] actualContent = null; byte[] header1 = null; byte[] header2 = null; if (df.CompressionLevel == CompressionType.Default || df.CompressionLevel == CompressionType.Maximum) { // for compressed files, the header is only an unknown dword header1 = _database.GetData(df.FileOffset + 8, 4); var compressed = _database.GetData(df.FileOffset + 12, (int)df.Size1); try { actualContent = Ionic.Zlib.ZlibStream.UncompressBuffer(compressed); // inside the compressed content is the file id (dword), and an unknown dword // of a very low (<256, typically) value. header2 = actualContent.Take(8).ToArray(); actualContent = actualContent.Skip(8).ToArray(); var compressionRatio = 100 * (decimal)compressed.Length / (decimal)actualContent.Length; contentDescription = $"Content was compressed by {compressionRatio:#} percent. Viewing decompressed content."; } catch (Exception ex) { byte[] fakeHeader = new byte[2]; contentDescription = "Unable to decompress content. Showing raw content instead."; header1 = new byte[0]; actualContent = compressed; } } else { // for uncompressed files, the header is the file id (dword) and the file size (dword) header1 = _database.GetData(df.FileOffset + 8, 8); actualContent = _database.GetData(df.FileOffset + 16, (int)BitConverter.ToUInt32(header1, 4)); } sbInfo.AppendLine("File ID: " + df.FileId.ToString("X8")); sbInfo.AppendLine("Offset: 0x" + df.FileOffset.ToString("X")); sbInfo.AppendLine("File Date: " + df.FileDate); sbInfo.AppendLine("Version: " + df.Version); sbInfo.AppendLine("Compression: " + df.CompressionLevel.ToString()); sbInfo.AppendLine("File Size: " + df.Size1); sbInfo.AppendLine("Dat Space Consumed: " + df.Size2); sbInfo.AppendLine("Type: 0x" + df.FileType.ToString("X8")); sbInfo.AppendLine("Unknown 1: 0x" + df.Unknown1.ToString("X8")); sbInfo.AppendLine("Unknown 2: 0x" + df.Unknown2.ToString("X8")); var fileType = DatFile.GetActualFileType(actualContent); // raw data tab if (!string.IsNullOrWhiteSpace(contentDescription)) { sbRaw.AppendLine(contentDescription); } sbRaw.AppendLine().AppendLine($"File Header ({header1.Length} bytes)"); sbRaw.AppendLine(header1.PrintBytes()); if (header2 != null) { sbRaw.AppendLine().AppendLine($"Compressed Header ({header2.Length} bytes)"); sbRaw.AppendLine(header2.PrintBytes()); } sbRaw.AppendLine().AppendLine($"Content ({actualContent.Length} bytes)"); sbRaw.AppendLine(actualContent.PrintBytes()); // ascii tab sbAscii.AppendLine($"File Header ({header1.Length} bytes)"); sbAscii.AppendLine(header1.PrintAsciiBytes()); if (header2 != null) { sbAscii.AppendLine().AppendLine($"Compressed Header ({header2.Length} bytes)"); sbAscii.AppendLine(header2.PrintAsciiBytes()); } sbAscii.AppendLine().AppendLine($"Content ({actualContent.Length} bytes)"); sbAscii.Append(actualContent.PrintAsciiBytes()); switch (fileType) { case KnownFileType.DXT1: case KnownFileType.DXT3: case KnownFileType.DXT5: { uint height = BitConverter.ToUInt32(actualContent, 0); uint width = BitConverter.ToUInt32(actualContent, 4); try { var dds = DdsFile.ConvertFromDxt(fileType, actualContent.Skip(16).ToArray(), width, height); pbPreview.Image = DdsFile.DdsToBmp((int)width, (int)height, dds); pbPreview.Tag = df; sbInfo.AppendLine("Image Content available for preview (use Mouse Wheel to zoom)."); } catch (Exception ex) { sbInfo.AppendLine("Image Content Detected but no preview is available."); } break; } break; } tbInfo.Text = sbInfo.ToString(); tbRaw.Text = sbRaw.ToString(); tbAscii.Text = sbAscii.ToString(); } }