public void showPreview(screenshotItem shot) { this.WindowState = FormWindowState.Normal; MemoryStream previewMem = new MemoryStream(reader.readFile(shot)); Bitmap preview = new Bitmap(previewMem); previewMem.Close(); previewMem.Dispose(); this.Text = "Previewing \"" + shot.shotTitle + "\""; pictureBox1.Image = preview; this.ClientSize = new Size(preview.Width / 2, preview.Height / 2); }
internal screenshotItem shotReachBeta(BinaryReader br, int fileStart, screenshotItem screenshot) { br.BaseStream.Position = fileStart + 4; int blfLength = br.ReadBigInt32(); br.BaseStream.Position = fileStart + blfLength + 4; int chdrLength = br.ReadBigInt32(); br.BaseStream.Position = fileStart + blfLength + 12; int blfVersion = br.ReadBigInt16(); br.BaseStream.Position += 46; // Move forward 46 bytes to get to the mapID int mapId = br.ReadBigInt32() + 10000; br.BaseStream.Position += 12; // Move forward 12 to get to the created time int shotTime = br.ReadBigInt32(); br.BaseStream.Position += 64; // Move forward 64 bytes to get to the title string shotTitle = Encoding.BigEndianUnicode.GetString(br.ReadBytes(256)).Trim('\0'); br.BaseStream.Position = fileStart + blfLength + chdrLength + 4; int scncLength = 0; // The scnc block doesn't exist in Halo: Reach Beta screenshots br.BaseStream.Position = fileStart + blfLength + chdrLength + scncLength + 12; int jpegLength = br.ReadBigInt32(); int jpegOffset = (int)br.BaseStream.Position; screenshot.blfVersion = blfVersion; screenshot.headerLength = blfLength + chdrLength + scncLength + 16; screenshot.headerStart = (fileStart - 49152) / 4096; screenshot.jpegLength = jpegLength; screenshot.jpegOffset = jpegOffset; screenshot.mapID = mapId; screenshot.fileTime = shotTime; screenshot.shotTitle = shotTitle; return screenshot; }
internal screenshotItem shotReach(BinaryReader br, int fileStart, screenshotItem screenshot) { int headerStart = (fileStart - 49152) / 4096; br.BaseStream.Position = fileStart + 4; int blfLength = br.ReadBigInt32(); br.BaseStream.Position = fileStart + blfLength + 4; int chdrLength = br.ReadBigInt32(); br.BaseStream.Position = fileStart + blfLength + 12; int blfVersion = br.ReadBigInt16(); br.BaseStream.Position += 46; // Move forward 46 bytes to get to the mapID int mapId = br.ReadBigInt32(); if (screenshot.gameID == 4 && mapId == 10080) mapId += 1; // This is done to prevent a discrepancy with Halo: Reach's "Installation 04" br.BaseStream.Position += 12; // Move forward 12 bytes to get to the created timestamp int createTime = br.ReadBigInt32(); br.BaseStream.Position += 32; int modTime = br.ReadBigInt32(); br.BaseStream.Position += 28; // Move forward 28 bytes to get to the title string shotTitle = Encoding.BigEndianUnicode.GetString(br.ReadBytes(256)).Trim('\0'); br.BaseStream.Position = fileStart + blfLength + chdrLength + 4; int scncLength = br.ReadBigInt32(); br.BaseStream.Position = screenshot.hashTable + ((headerStart * 24) + 21); // Since the header in Reach Retail screenshot files spans more than one block, we need to find out where to go next from the hash table int nextBlock = (br.ReadBigInt24() * 4096) + 49152; int bytesRemain = (blfLength + chdrLength + scncLength) - 4096; br.BaseStream.Position = nextBlock + bytesRemain + 12; int jpegLength = br.ReadBigInt32(); int jpegOffset = (int)br.BaseStream.Position; screenshot.blfVersion = blfVersion; screenshot.headerLength = blfLength + chdrLength + scncLength + 16; screenshot.headerStart = headerStart; screenshot.jpegLength = jpegLength; screenshot.jpegOffset = jpegOffset; screenshot.mapID = mapId; screenshot.fileTime = createTime; screenshot.shotTitle = shotTitle; return screenshot; }
internal screenshotItem shotHalo3ODST(BinaryReader br, int fileStart, screenshotItem screenshot) { br.BaseStream.Position = fileStart + 4; int blfLength = br.ReadBigInt32(); br.BaseStream.Position = fileStart + blfLength + 4; int chdrLength = br.ReadBigInt32(); br.BaseStream.Position = fileStart + blfLength + 12; int blfVersion = br.ReadBigInt16(); br.BaseStream.Position += 10; // Move forward 10 bytes to get to the start of the title string shotTitle = Encoding.BigEndianUnicode.GetString(br.ReadBytes(32)).Trim('\0'); br.BaseStream.Position += 172; // Move forward 172 bytes to get to the shot time int shotTime = br.ReadBigInt32(); br.BaseStream.Position += 8; int mapId = br.ReadBigInt32(); br.BaseStream.Position += 8; byte fireFight = br.ReadByte(); if (fireFight != 0) mapId += 10000 + fireFight; br.BaseStream.Position = fileStart + blfLength + chdrLength + 4; int scncLength = 0; // The scnc block doesn't exist in versions prior to 12070, so we'll check for that if (blfVersion >= 12070) scncLength = br.ReadBigInt32(); br.BaseStream.Position = fileStart + blfLength + chdrLength + scncLength + 12; int jpegLength = br.ReadBigInt32(); int jpegOffset = (int)br.BaseStream.Position; screenshot.blfVersion = blfVersion; screenshot.headerLength = blfLength + chdrLength + scncLength + 16; screenshot.headerStart = (fileStart - 49152) / 4096; screenshot.jpegLength = jpegLength; screenshot.jpegOffset = jpegOffset; screenshot.fileTime = shotTime; screenshot.mapID = mapId; screenshot.shotTitle = shotTitle; return screenshot; }
public byte[] readFile(screenshotItem shot) { #if DEBUG FileStream debug = new FileStream(shot.fileName + "_debug.txt", FileMode.Create, FileAccess.ReadWrite); StreamWriter sw = new StreamWriter(debug); sw.WriteLine("Total Filesize: " + shot.jpegLength + ", numBlocks: " + shot.numBlocks + " hashBlock: 0x" + shot.hashTable.ToString("X")); sw.Flush(); #endif FileStream fs = new FileStream(shot.fileName, FileMode.Open, FileAccess.Read); BinaryReader br = new BinaryReader(fs); byte[] file = new byte[shot.jpegLength]; int count = 0; int copyTo = 0; int thisBlock = shot.headerStart; int headerLength = shot.headerLength; int numBlocks = shot.numBlocks; short blockRemain = (short)((numBlocks * 4096) - shot.jpegLength - headerLength); if (blockRemain > 4096) { #if DEBUG sw.WriteLine("// Block Remainder: ((" + shot.numBlocks + " * 4096) - " + shot.jpegLength + " - " + shot.headerLength + ") = " + blockRemain + " //"); sw.WriteLine("// Block remainder is greater than 4096, ignoring last block //"); #endif numBlocks--; } while (headerLength >= 4096) // This should only happen in Reach Retail files, because of the extra length of the SCNC block { numBlocks--; headerLength -= 4096; br.BaseStream.Position = shot.hashTable + ((thisBlock * 24) + 21); thisBlock = br.ReadBigInt24(); } #if DEBUG sw.WriteLine(); sw.Flush(); #endif while (count < numBlocks) { br.BaseStream.Position = (thisBlock * 4096) + 49152; byte[] buffer; int readBytes = 4096; if (count == 0) { br.BaseStream.Position += headerLength; readBytes -= headerLength; } else if (count == (numBlocks - 1)) { readBytes -= (numBlocks * 4096) - headerLength - shot.jpegLength; } #if DEBUG sw.WriteLine("count: " + count.ToString().PadLeft(shot.numBlocks.ToString().Length, ' ') + ", thisBlock: " + thisBlock.ToString().PadLeft(shot.numBlocks.ToString().Length, ' ') + ", hashTable: " + (int)(shot.hashTable + ((thisBlock * 24) + 21)) + ", reading " + readBytes.ToString().PadLeft(4, ' ') + " bytes from " + br.BaseStream.Position.ToString().PadLeft(shot.jpegLength.ToString().Length, ' ') + " and copying to " + copyTo.ToString().PadLeft(shot.jpegLength.ToString().Length, ' ')); sw.Flush(); #endif buffer = br.ReadBytes(readBytes); br.BaseStream.Position = shot.hashTable + ((thisBlock * 24) + 21); thisBlock = br.ReadBigInt24(); count++; try { buffer.CopyTo(file, copyTo); } catch (Exception e) { #if DEBUG sw.WriteLine(); sw.WriteLine("// Error occured at count " + count + ": " + e.Message + "//"); sw.WriteLine(); sw.Flush(); #endif } copyTo += readBytes; } br.Close(); fs.Close(); #if DEBUG sw.Close(); debug.Close(); #endif return file; }