private void exportSplicedFileToolStripMenuItem_Click(object sender, EventArgs e) { if (FlashContainer is null) { return; } if (!LoadMappedAddresses()) { return; } /* * we need to.. * - get the fileoffsets of the segment sizes * - get the fileoffsets of the segment addresses * - get the fileoffset of the flash start address * * - patch all the fileoffsets (size+address) with the new value */ int flashDataFileOffset = FlashContainer.CaesarFlashHeader.CffHeaderSize + FlashContainer.CaesarFlashHeader.LanguageBlockLength + 0x414; byte[] nonFlashData = FlashBytes.Take(flashDataFileOffset).ToArray(); using (BinaryReader reader = new BinaryReader(new MemoryStream(FlashBytes))) using (BinaryWriter nonFlashWriter = new BinaryWriter(new MemoryStream(nonFlashData))) using (BinaryWriter flashPayloadWriter = new BinaryWriter(new MemoryStream())) { int segmentCursor = 0; for (int i = 0; i < FlashContainer.CaesarFlashHeader.DataBlocks.Count; i++) { FlashDataBlock db = FlashContainer.CaesarFlashHeader.DataBlocks[i]; // read block offset fileoffset long blockOffsetFileOffset = db.GetFlashDataOffset(reader); // patch segment length on filebytes nonFlashWriter.BaseStream.Seek(blockOffsetFileOffset, SeekOrigin.Begin); nonFlashWriter.Write(segmentCursor); int localBlockLength = 0; for (int j = 0; j < db.FlashSegments.Count; j++) { FlashSegment seg = db.FlashSegments[j]; // check: which fields are mutable when splicing long offset = db.FlashData + // somewhat mutable : probably if there's more than 1 datablock, this value will be nonzero FlashContainer.CaesarFlashHeader.CffHeaderSize + // constant FlashContainer.CaesarFlashHeader.LanguageBlockLength + // constant segmentCursor + // mutable, see below 0x414; // constant byte[] segmentPayload = FlashData[i][j]; if (SplicePath[i][j].Length > 0) { segmentPayload = File.ReadAllBytes(SplicePath[i][j]); } int segmentMappedAddress = MappedAddresses[i][j]; // read segment length's offset long segmentLengthFileOffset = seg.GetSegmentLengthFileOffset(reader); // read segment's mapped address long segmentMappedAddressFileOffset = seg.GetMappedAddressFileOffset(reader); // patch segment length on filebytes nonFlashWriter.BaseStream.Seek(segmentLengthFileOffset, SeekOrigin.Begin); nonFlashWriter.Write(segmentPayload.Length); // patch segment's mapped address nonFlashWriter.BaseStream.Seek(segmentMappedAddressFileOffset, SeekOrigin.Begin); nonFlashWriter.Write(segmentMappedAddress); // increment segment offset for db.flashdata segmentCursor += segmentPayload.Length; localBlockLength += segmentPayload.Length; // append flash payload to temp buffer flashPayloadWriter.Write(segmentPayload); } // refresh the block size // read block size fileoffset long blockSizeFileOffset = db.GetBlockLengthOffset(reader); // patch block length nonFlashWriter.BaseStream.Seek(blockSizeFileOffset, SeekOrigin.Begin); nonFlashWriter.Write(localBlockLength); } // take the non-flash part of the bytes that we patched... // .. then merge it with the flash section that we rebuilt byte[] flashPayload = ((MemoryStream)flashPayloadWriter.BaseStream).ToArray(); byte[] nonFlashPrefix = ((MemoryStream)nonFlashWriter.BaseStream).ToArray(); byte[] result = new byte[flashPayload.Length + nonFlashPrefix.Length + 4]; Array.ConstrainedCopy(nonFlashPrefix, 0, result, 0, nonFlashPrefix.Length); Array.ConstrainedCopy(flashPayload, 0, result, nonFlashPrefix.Length, flashPayload.Length); // restore the checksum uint checksum = CaesarReader.ComputeFileChecksumLazy(result); result[result.Length - 4] = (byte)((checksum >> 0) & 0xFF); result[result.Length - 3] = (byte)((checksum >> 8) & 0xFF); result[result.Length - 2] = (byte)((checksum >> 16) & 0xFF); result[result.Length - 1] = (byte)((checksum >> 24) & 0xFF); // save the result SaveFileDialog sfd = new SaveFileDialog(); sfd.Title = "Specify a location to save your new CFF file"; sfd.Filter = "CFF files (*.cff)|*.cff|All files (*.*)|*.*"; if (sfd.ShowDialog() == DialogResult.OK) { File.WriteAllBytes(sfd.FileName, result); } } }
private void PresentRows() { if (FlashContainer is null) { return; } DataTable dt = new DataTable(); foreach (string header in new string[] { "Block #", "Block Name", "Block Description", "Segment #", "Segment Name", "ECU Target Address (Editable)", "Original Length", "Original Offset", "Splice Mode" }) { dt.Columns.Add(header, typeof(string)); } dgvMain.DataSource = dt; for (int i = 0; i < FlashContainer.CaesarFlashHeader.DataBlocks.Count; i++) { FlashDataBlock db = FlashContainer.CaesarFlashHeader.DataBlocks[i]; long fileCursor = 0; for (int j = 0; j < db.FlashSegments.Count; j++) { FlashSegment seg = db.FlashSegments[j]; long offset = db.FlashData + FlashContainer.CaesarFlashHeader.CffHeaderSize + FlashContainer.CaesarFlashHeader.LanguageBlockLength + fileCursor + 0x414; fileCursor += seg.SegmentLength; // Console.WriteLine($"Segment: {seg.SegmentName} mapped to 0x{seg.FromAddress:X} with size 0x{seg.SegmentLength:X}"); string spliceModeForRow = SplicePath[i][j].Length == 0 ? "Inherit Original" : SplicePath[i][j]; dt.Rows.Add( i.ToString(), db.Qualifier, FlashContainer.CaesarCTFHeader.CtfLanguages[0].GetString(db.Description), j.ToString(), seg.SegmentName, seg.FromAddress.ToString("X"), seg.SegmentLength.ToString("X"), offset.ToString("X"), spliceModeForRow ); } } dgvMain.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells; dgvMain.Columns[0].ReadOnly = true; dgvMain.Columns[1].ReadOnly = true; dgvMain.Columns[2].ReadOnly = true; dgvMain.Columns[3].ReadOnly = true; dgvMain.Columns[4].ReadOnly = true; dgvMain.Columns[5].ReadOnly = false; dgvMain.Columns[6].ReadOnly = true; dgvMain.Columns[7].ReadOnly = true; dgvMain.Columns[8].ReadOnly = false; dgvMain.Columns[dgvMain.Columns.Count - 1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; }