/// <summary> /// First-pass processing on saving selected files (Batch Mode). Hands the data off to saveSingle() to finish. /// </summary> /// <param name="p"></param> private void saveSelected(string path) { #if DEBUG // TimeSpan stuff DateTime tstart = DateTime.Now; #endif int numFiles = fileList.SelectedItems.Count; int padLength = numFiles.ToString().Length; toolStripProgressBar1.Value = 0; toolStripProgressBar1.Maximum = numFiles; foreach (int index in fileList.SelectedIndices) { screenshotItem shot = screenshots[index]; string savePath = path + "\\" + gamesTitlesSafe[shot.gameID] + "_" + (index).ToString().PadLeft(padLength, '0') + "_" + shot.shotTitle + ".jpg"; toolStripStatusLabel1.Text = "Saving " + savePath; saveSingle(shot, savePath); toolStripProgressBar1.PerformStep(); Application.DoEvents(); } toolStripStatusLabel1.Text = "Saved " + numFiles + " screenshots to " + path; settings.fbdSavePath = path; settings.Save(); #if DEBUG // TimeSpan stuff DateTime tend = DateTime.Now; TimeSpan duration = tend - tstart; string hours = (duration.Hours != 0) ? duration.Hours + " hours," : ""; string secs = (duration.Minutes != 0) ? duration.Minutes + " minutes," : ""; string mins = (duration.Seconds != 0) ? duration.Seconds + " seconds," : ""; string mill = (duration.Milliseconds != 0) ? duration.Milliseconds + " ms" : ""; toolStripStatusLabel1.Text += " Total Time: " + hours + mins + secs + mill; #endif }
/// <summary> /// Extracts and saves a single screenshot supplied by saveMulti() /// </summary> /// <param name="shot">screenshotItem containing information about the screenshot to be saved</param> /// <param name="savePath">The path on the harddrive where the screenshot will be saved</param> private void saveSingle(screenshotItem shot, string savePath) { FileStream fSave = new FileStream(savePath, FileMode.Create, FileAccess.Write); BinaryWriter bw = new BinaryWriter(fSave); bw.Write(reader.readFile(shot)); bw.Close(); fSave.Close(); }
private void contextMenuSaveThis_Click(object sender, EventArgs e) { screenshotItem shot = screenshots[rightClickIndex]; sfd.FileName = shot.shotTitle; if (sfd.ShowDialog() == DialogResult.OK) { saveSingle(shot, sfd.FileName); toolStripStatusLabel1.Text = "Saved " + sfd.FileName; } }
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 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); }
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); }
/// <summary> /// Handles the extraction of a single screenshot from a supplied screenshot CON file /// </summary> /// <param name="savingFile">Bool determing whether the file will be automatically saved or not</param> /// <param name="warn">Bool determining whether the user will be warned of errors</param> private void processSingle(bool savingFile, bool warn) { if (!CONfirm()) { if (warn) { errorShow(); } return; } if (!confirmShot()) { if (warn) { errorShow(); } return; } // Begin reading the CON file list br.BaseStream.Position = contentStart + fileListAdd + 41; int numBlocks = br.ReadInt24(); br.BaseStream.Position = contentStart + fileListAdd + 47; int fileStart = contentStart + (br.ReadInt24() * 4096); // I now know where my blf file starts, I can use this as a baseline to iterate through the various blf blocks. br.BaseStream.Position = contentStart + fileListAdd + 52; int fileSize = br.ReadBigInt32(); // And I also know how long my blf file is, but I don't think I'll need this. br.BaseStream.Position = contentStart + fileListAdd + 56; int fileTime = br.ReadBigInt32(); // FAT formatted time screenshotItem screenshot = new screenshotItem() // We need to set a few initial variables { fileName = finfo.FullName, //fileTime = fileTime, gameID = gameID, hashTable = hashTable, numBlocks = numBlocks }; switch (gameID) { case 0: // Halo 3 screenshot = reader.shotHalo3(br, fileStart, screenshot); break; case 1: // Halo 3: ODST screenshot = reader.shotHalo3ODST(br, fileStart, screenshot); break; case 2: // Halo: Reach Beta screenshot = reader.shotReachBeta(br, fileStart, screenshot); break; case 3: // Halo: Reach case 4: // Halo 4 (this is a test) screenshot = reader.shotReach(br, fileStart, screenshot); break; } if (savingFile) { sfd.FileName = screenshot.shotTitle; if (sfd.ShowDialog() == DialogResult.OK) { saveSingle(screenshot, sfd.FileName); toolStripStatusLabel1.Text = "Saved " + sfd.FileName; } br.Close(); fs.Close(); return; } if (!screenshots.Contains(screenshot)) { screenshots.Add(screenshot); } br.Close(); fs.Close(); }
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); }