internal override void Write(BinaryEndianWriter bw) { base.StartLengthCheck(bw); base.Write(bw); foreach (string s in _strings) { bw.Write(stringToBytes(s)); bw.Write((byte)0); if (_isUnicode) { bw.Write((byte)0); } } while (base.StreamPos(bw) % 4 != 0) { bw.Write((byte)0); } base.WriteEnd(bw); ApplicationException ex = base.TestLengthCheck(this, bw); if (ex != null) { throw ex; } }
public void Write(Stream s) { BinaryEndianWriter bw = new BinaryEndianWriter(s); //using (BinaryEndianWriter bw = new BinaryEndianWriter(s)) //{ this.startLengthCheck(bw); bw.Write(_magic, this.PakFormat.EndianType); bw.Write(_fileSize, this.PakFormat.EndianType); foreach (QbItemBase qib in _items) { qib.Write(bw); } ApplicationException ex = this.testLengthCheck(this, bw); if (ex != null) { throw ex; } //} }
internal override void Write(BinaryEndianWriter bw) { base.StartLengthCheck(bw); base.Write(bw); if (base.QbItemType != QbItemType.StructHeader) { bw.Write(_headerValue, base.Root.PakFormat.EndianType); } bw.Write(_iniNextItemPointer, base.Root.PakFormat.EndianType); foreach (QbItemBase qib in base.Items) { qib.Write(bw); } base.WriteEnd(bw); ApplicationException ex = base.TestLengthCheck(this, bw); if (ex != null) { throw ex; } }
internal override void Write(BinaryEndianWriter bw) { base.StartLengthCheck(bw); base.Write(bw); bw.Write(_unknown, base.Root.PakFormat.EndianType); bw.Write((uint)_scriptData.Length, base.Root.PakFormat.EndianType); byte[] compScript; Lzss lz = new Lzss(); compScript = lz.Compress(_scriptData); if (compScript.Length >= _scriptData.Length) { compScript = _scriptData; } bw.Write((uint)compScript.Length, base.Root.PakFormat.EndianType); bw.Write(compScript); if (compScript.Length % 4 != 0) { for (int i = 0; i < 4 - (compScript.Length % 4); i++) { bw.Write((byte)0); } } base.WriteEnd(bw); ApplicationException ex = base.TestLengthCheck(this, bw); if (ex != null) { throw ex; } }
/// <summary> /// Call after derived class has written its data in Write() /// </summary> /// <param name="br"></param> public virtual void WriteEnd(BinaryEndianWriter bw) { #region switch switch (_qbFormat) { case QbFormat.SectionValue: //Simple section type: // ItemId, FileId, Value, Reserved bw.Write(_reserved, this.Root.PakFormat.EndianType); break; case QbFormat.StructItemValue: //case QbItemType.StructItemQbKeyString: //Simple struct type: // ItemId, Value (4 byte), NextItemPointer bw.Write(_nextItemPointer, this.Root.PakFormat.EndianType); break; default: break; } #endregion }
internal override void Write(BinaryEndianWriter bw) { base.StartLengthCheck(bw); bw.Write(_unknownData); base.WriteEnd(bw); ApplicationException ex = base.TestLengthCheck(this, bw); if (ex != null) { throw ex; } }
private void writeHeaderItem(BinaryEndianWriter bwPakO, PakHeaderItem ph) { bwPakO.Write(ph.FileType.Crc, _pakFormat.EndianType); uint offset = ph.FileOffset; if (_requiresPab) { offset = (uint)_pakFormat.PakPabMinDataOffset + ((_pakFormat.PakPabMinDataOffset == 0 ? ph.HeaderStart : 0) + ph.FileOffset) - (uint)_pakFileLength; } bwPakO.Write(offset, _pakFormat.EndianType); bwPakO.Write(ph.FileLength, _pakFormat.EndianType); bwPakO.Write(ph.PakFullFileNameQbKey, _pakFormat.EndianType); bwPakO.Write(ph.FullFilenameQbKey, _pakFormat.EndianType); bwPakO.Write(ph.NameOnlyCrc, _pakFormat.EndianType); bwPakO.Write(ph.Unknown, _pakFormat.EndianType); bwPakO.Write((uint)ph.Flags, _pakFormat.EndianType); if ((ph.Flags & PakHeaderFlags.Filename) == PakHeaderFlags.Filename) { bwPakO.Write(Encoding.UTF8.GetBytes(ph.PaddedFileName), 0, PakHeaderItem.FileNameMaxLength); } }
internal override void Write(BinaryEndianWriter bw) { base.StartLengthCheck(bw); base.Write(bw); foreach (uint i in _values) { bw.Write(i, base.Root.PakFormat.EndianType); } base.WriteEnd(bw); ApplicationException ex = base.TestLengthCheck(this, bw); if (ex != null) { throw ex; } }
internal override void Write(BinaryEndianWriter bw) { base.StartLengthCheck(bw); base.Write(bw); bw.Write(_unknown, base.Root.PakFormat.EndianType); bw.Write((uint)_scriptData.Length, base.Root.PakFormat.EndianType); byte[] compScript; Lzss lz = new Lzss(); compScript = lz.Compress(_scriptData); if (compScript.Length >= _scriptData.Length) compScript = _scriptData; bw.Write((uint)compScript.Length, base.Root.PakFormat.EndianType); bw.Write(compScript); if (compScript.Length % 4 != 0) { for (int i = 0; i < 4 - (compScript.Length % 4); i++) bw.Write((byte)0); } base.WriteEnd(bw); ApplicationException ex = base.TestLengthCheck(this, bw); if (ex != null) throw ex; }
public void Write(Stream s) { BinaryEndianWriter bw = new BinaryEndianWriter(s); //using (BinaryEndianWriter bw = new BinaryEndianWriter(s)) //{ this.startLengthCheck(bw); bw.Write(_magic, this.PakFormat.EndianType); bw.Write(_fileSize, this.PakFormat.EndianType); foreach (QbItemBase qib in _items) qib.Write(bw); ApplicationException ex = this.testLengthCheck(this, bw); if (ex != null) throw ex; //} }
public static void WriteSingleChunkHeader(WavSingleChunkHeader header, Stream wavStream) { BinaryEndianWriter w = new BinaryEndianWriter(wavStream); w.Write(Encoding.Default.GetBytes(header.FileId)); w.Write(header.FileLength); w.Write(Encoding.Default.GetBytes(header.RiffType)); w.Write(Encoding.Default.GetBytes(header.ChunkHeaderId)); w.Write(header.ChunkHeaderLength); w.Write(header.FormatTag); w.Write(header.Channels); w.Write(header.SamplesPerSec); w.Write(header.AvgBytesPerSec); w.Write(header.BlockAlign); w.Write(header.BitsPerSample); w.Write(header.ExtraBytes); w.Write(Encoding.Default.GetBytes(header.ChunkId)); w.Write(header.ChunkLength); }
public static void CreatePreview(int offset, int length, int fade, float volume, bool volumeApplied, string dstFilename, params AudioFile[] srcFilenames) { if (srcFilenames == null || srcFilenames.Length == 0 || (srcFilenames.Length == 1 && (srcFilenames[0] == null || srcFilenames[0].Name.Length == 0))) return; FileHelper.Delete(dstFilename); WavSingleChunkHeader[] whi = new WavSingleChunkHeader[srcFilenames.Length]; BinaryEndianReader[] br = new BinaryEndianReader[srcFilenames.Length]; float[] vols = new float[srcFilenames.Length]; int outWav = 0; //use this input wav as the format for the output wav int maxLen = 0; for (int c = 0; c < srcFilenames.Length; c++) { br[c] = new BinaryEndianReader(File.OpenRead(srcFilenames[c].Name)); whi[c] = ParseWavSingleChunkHeader(br[c].BaseStream); if (!volumeApplied) vols[c] = srcFilenames[c].Volume / 100F; //get percentage else vols[c] = 1; //100% //move to the correct point in each wav uint wOffset = (uint)(whi[c].AvgBytesPerSec * ((float)offset / 1000)); wOffset -= wOffset % whi[c].BlockAlign; br[c].BaseStream.Seek((long)wOffset, SeekOrigin.Current); if (whi[c].AudioLength > maxLen) maxLen = whi[c].AudioLength; if (whi[c].Channels == 2) outWav = c; } WavSingleChunkHeader who = new WavSingleChunkHeader(); if (length == 0) length = maxLen; uint wLength = (uint)(whi[outWav].AvgBytesPerSec * ((float)length / 1000)); wLength -= wLength % whi[outWav].BlockAlign; who.FileId = "RIFF"; who.FileLength = (uint)(br[outWav].BaseStream.Length - whi[outWav].FileLength) + wLength; who.RiffType = "WAVE"; who.ChunkHeaderId = "fmt "; who.ChunkHeaderLength = whi[outWav].ChunkHeaderLength; who.FormatTag = whi[outWav].FormatTag; who.Channels = whi[outWav].Channels; who.SamplesPerSec = whi[outWav].SamplesPerSec; who.AvgBytesPerSec = whi[outWav].AvgBytesPerSec; who.BlockAlign = whi[outWav].BlockAlign; who.BitsPerSample = whi[outWav].BitsPerSample; who.ExtraBytes = whi[outWav].ExtraBytes; who.ChunkId = "data"; who.ChunkLength = wLength; using (FileStream fso = File.OpenWrite(dstFilename)) { WriteSingleChunkHeader(who, fso); int loops = (int)((who.AvgBytesPerSec / who.BlockAlign) * ((float)length / 1000)); int fadeLen = (int)((who.AvgBytesPerSec / who.BlockAlign) * ((float)fade / 1000)); Double maxVol = (volume / (float)srcFilenames.Length); //reduce volume Audio in game maxVol *= 1F + ((srcFilenames.Length - 1) * 0.33F); //add an extra third per file to cater for volume loss Double vol = 0; //initial volume if (fade == 0) vol = maxVol; int b32; BinaryEndianWriter bw = new BinaryEndianWriter(fso); Double step = (double)(maxVol - 0) / fadeLen; //fade in if (Double.IsInfinity(step)) step = 0; int allLeft = 0; int allRight = 0; long[] streamPos = new long[br.Length]; //fast way to track pos in stream for (int c = 0; c < br.Length; c++) streamPos[c] = br[c].BaseStream.Position; long[] streamLen = new long[br.Length]; //fast way to get length of stream for (int c = 0; c < br.Length; c++) streamLen[c] = br[c].BaseStream.Length; for (int i = 0; i != loops; i++) { if (i == fadeLen) step = 0; //use max volume if (i == loops - fadeLen) //fade out step = (double)(0 - maxVol) / fadeLen; allLeft = 0; allRight = 0; for (int c = 0; c < br.Length; c++) //each input stream { BinaryEndianReader b = br[c]; WavSingleChunkHeader w = whi[c]; //Left channel b32 = 0; if (streamPos[c] + 2 < streamLen[c]) { b32 = (int)(b.ReadInt16(EndianType.Little) * vols[c]); streamPos[c] += 2; } allLeft += (int)(b32 * vol); allLeft = (short)Math.Max((int)short.MinValue, Math.Min((int)short.MaxValue, allLeft)); if (who.Channels > 1) { if (w.Channels > 1) { //Right channel b32 = 0; if (streamPos[c] + 2 < streamLen[c]) { b32 = (int)(b.ReadInt16(EndianType.Little) * vols[c]); streamPos[c] += 2; } } allRight += (int)(b32 * vol); allRight = (short)Math.Max((int)short.MinValue, Math.Min((int)short.MaxValue, allRight)); } } bw.Write((short)allLeft); if (who.Channels > 1) bw.Write((short)allRight); vol += step; } foreach (BinaryEndianReader b in br) b.Close(); fso.Flush(); } }
/// <summary> /// Adds silence to wav files alter volume /// </summary> /// <param name="silenceInsertLength">Milliseconds to insert at start of wav</param> /// <param name="volume">0=silent, 1=100%</param> /// <param name="maxLength">If the wav is longer than this then crop (includes silence), if 0 then don't crop</param> /// <param name="srcFilenames">Filenames to pad</param> public static void SetLengthSilenceAndVolume(float silenceInsertLength, float maxLength, float volume, string fileName) { FileStream inS; FileStream outS; WavSingleChunkHeader h; uint silenceLen; string tmpName; //uint origChunkLen; int copied; byte[] buff = new byte[10000]; for (int i = 0; i < buff.Length; i++) buff[i] = 0; tmpName = string.Format("{0}_{1}", fileName, Guid.NewGuid().ToString("N")); using (inS = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { using (outS = new FileStream(tmpName, FileMode.CreateNew, FileAccess.ReadWrite)) { h = ParseWavSingleChunkHeader(inS); //origChunkLen = h.ChunkLength; silenceLen = (uint)((float)h.AvgBytesPerSec * (silenceInsertLength / 1000F)); silenceLen -= silenceLen % h.BlockAlign; uint newLenBytes = maxLength != 0 ? (uint)((float)h.AvgBytesPerSec * (maxLength / 1000F)) : h.ChunkLength + silenceLen; newLenBytes -= newLenBytes % h.BlockAlign; h.ChunkLength = (uint)((uint)inS.Length - h.DataOffset) + silenceLen; if (h.ChunkLength > newLenBytes) h.ChunkLength = newLenBytes; h.ChunkLength -= h.ChunkLength % h.BlockAlign; h.FileLength = (h.ChunkLength + (uint)h.DataOffset) - 8; WriteSingleChunkHeader(h, outS); copied = 0; int len = 0; while (copied < silenceLen) { len = buff.Length; if (copied + buff.Length > silenceLen) len = (int)silenceLen - copied; outS.Write(buff, 0, len); copied += len; } //origChunkLen = h.ChunkLength; //we need to copy this much //copy audio and set volume BinaryEndianWriter bw = new BinaryEndianWriter(outS); BinaryEndianReader br = new BinaryEndianReader(inS); int b32; while (copied != h.ChunkLength) //length is block aligned so don't worry about channel count { b32 = (int)br.ReadInt16(EndianType.Little); b32 = (int)((float)b32 * volume); b32 = Math.Max((int)short.MinValue, Math.Min((int)short.MaxValue, b32)); bw.Write((short)b32, EndianType.Little); copied += 2; } //copied = (int)origChunkLen; //we've copied this much (silence included) //while (copied < h.ChunkLength) //pad to the length we said it was in the header //{ // inS.Read(buff, 0, buff.Length); // if (copied + buff.Length < h.ChunkLength) // outS.Write(buff, 0, buff.Length); // else // outS.Write(buff, 0, (int)h.ChunkLength % - copied); // copied += buff.Length; //} outS.Flush(); } } if (File.Exists(fileName)) { if (File.Exists(tmpName)) FileHelper.Move(tmpName, fileName); } }
/// <summary> /// Write the item to the Binary Writer /// </summary> /// <param name="bw"></param> internal virtual void Write(BinaryEndianWriter bw) { bw.Write(_qbItemValue, this.Root.PakFormat.EndianType); #region switch uint qbKeyCrc = (_itemQbKey == null ? 0 : _itemQbKey.Crc); switch (_qbFormat) { case QbFormat.SectionPointer: //Complex section type: // ItemId, FileId, Pointer, Reserved bw.Write(qbKeyCrc, this.Root.PakFormat.EndianType); bw.Write(_fileId, this.Root.PakFormat.EndianType); bw.Write(_pointer, this.Root.PakFormat.EndianType); bw.Write(_reserved, this.Root.PakFormat.EndianType); break; case QbFormat.SectionValue: //Simple section type: // ItemId, FileId bw.Write(qbKeyCrc, this.Root.PakFormat.EndianType); bw.Write(_fileId, this.Root.PakFormat.EndianType); break; case QbFormat.StructItemPointer: //Complex struct type: // ItemId, Pointer, NextItemPointer bw.Write(qbKeyCrc, this.Root.PakFormat.EndianType); bw.Write(_pointer, this.Root.PakFormat.EndianType); bw.Write(_nextItemPointer, this.Root.PakFormat.EndianType); break; case QbFormat.StructItemValue: //Simple struct type: // ItemId, Value (4 byte), NextItemPointer bw.Write(qbKeyCrc, this.Root.PakFormat.EndianType); break; case QbFormat.ArrayPointer: //Complex array type: // ItemCount, Pointer, Pointers - (if length is 1 then pointer points to first item and Pointers are abscent) bw.Write(_itemCount, this.Root.PakFormat.EndianType); if (_itemCount == 0) { bw.Write(0, this.Root.PakFormat.EndianType); } else if (_itemCount > 1) { bw.Write(_pointer, this.Root.PakFormat.EndianType); } for (int i = 0; i < _itemCount; i++) { bw.Write(_pointers[i], this.Root.PakFormat.EndianType); } break; case QbFormat.ArrayValue: //Simple array type: // ItemCount, Pointer, Pointers - (if length is 1 then pointer points to first item and Pointers are abscent) bw.Write(_itemCount, this.Root.PakFormat.EndianType); if (_itemCount > 1) { bw.Write(_pointer, this.Root.PakFormat.EndianType); } break; case QbFormat.StructHeader: break; case QbFormat.Floats: break; case QbFormat.Unknown: break; default: break; } #endregion }
private void save() { using (FileStream fs = File.OpenWrite(_datFilename)) { using (BinaryEndianWriter bw = new BinaryEndianWriter(fs)) { bw.Write((uint)_datItems.Count, _endianType); bw.Write(_headerFileSize, _endianType); foreach (DatItem di in _datItems.Values) { bw.Write(di.ItemQbKey.Crc, _endianType); bw.Write(di.FileOffset, _endianType); bw.Write(di.FileSize, _endianType); bw.Write(di.Reserved); } fs.Flush(); } } }
public void ReplaceFsbFileWithWav(DatItem item, string wavFilename) { string tempWadFn = string.Format("{0}_{1}", _wadFilename, Guid.NewGuid().ToString("N")); byte[] buff; int filenameLen = 30; uint fileSize = 0; int diff; //save WAD to temp file using (FileStream fso = File.OpenWrite(tempWadFn)) { using (FileStream fsi = File.OpenRead(_wadFilename)) { if (item.FileOffset != 0) copy(fsi, fso, item.FileOffset); using (FileStream fs = File.OpenRead(wavFilename)) { //not fully correct for XBADPCM WavSingleChunkHeader wh = WavProcessor.ParseWavSingleChunkHeader(fs); long p = fso.Position; BinaryEndianWriter bw = new BinaryEndianWriter(fso); byte[] fsbFilename = new byte[filenameLen]; //http://www.fmod.org/forum/viewtopic.php?t=1551 //FileHeader bw.Write(Encoding.Default.GetBytes("FSB3")); bw.Write((uint)1, EndianType.Little); //1 sample in file bw.Write((uint)80, EndianType.Little); //sampleheader length bw.Write(wh.ChunkLength, EndianType.Little); //sampleheader length bw.Write((uint)0x00030001, EndianType.Little); //header version 3.1 bw.Write((uint)0, EndianType.Little); //global mode flags //p = fso.Position; //SampleHeader (80 byte version) bw.Write((UInt16)80, EndianType.Little); //sampleheader length fsi.Seek(24 + 2, SeekOrigin.Current); //skip the start of the source fsb file name fsi.Read(fsbFilename, 0, filenameLen); //read filename from file being replaced bw.Write(fsbFilename); //write filename //sampleheader length (What's this about?) uint lenSamp = (uint)Math.Round(((double)wh.SamplesPerSec / (double)wh.AvgBytesPerSec) * wh.ChunkLength); if (lenSamp < 0xFA00) lenSamp = 0xFA00; //set smallest allowed size? May be a memory allocation thing for FSB bw.Write(lenSamp, EndianType.Little); //sampleheader length bw.Write(wh.ChunkLength, EndianType.Little); //compressed bytes bw.Write((uint)0x0, EndianType.Little); //loop start bw.Write(lenSamp - 1, EndianType.Little); //loop end bw.Write((uint)0x20400040, EndianType.Little); //sample mode bw.Write(wh.SamplesPerSec, EndianType.Little); //frequency bw.Write((ushort)0xFF, EndianType.Little); //default volume bw.Write((ushort)0x0080, EndianType.Little); //default pan bw.Write((ushort)0x0080, EndianType.Little); //default pri bw.Write(wh.Channels, EndianType.Little); //channels bw.Write((float)1, EndianType.Little); //min distance bw.Write((float)10000, EndianType.Little); //max distance bw.Write((uint)0x0, EndianType.Little); //varfreq bw.Write((ushort)0x0, EndianType.Little); //varvol bw.Write((ushort)0x0, EndianType.Little); //varpan copy(fs, fso, wh.ChunkLength); fileSize = (uint)(24 + 80 + wh.ChunkLength); if (fileSize % DatWad.FileAlignment != 0) { buff = new byte[DatWad.FileAlignment - (fileSize % DatWad.FileAlignment)]; for (int i = 0; i < buff.Length; i++) buff[i] = DatWad.FileAlignmentPadValue; fso.Write(buff, 0, buff.Length); } //move past the rest of this file being replaced long itemSize = item.FileSize; if (item.FileSize % DatWad.FileAlignment != 0) itemSize += (DatWad.FileAlignment - (item.FileSize % DatWad.FileAlignment)); if (itemSize < fsi.Length) fsi.Seek(itemSize - (24 + 2 + filenameLen), SeekOrigin.Current); } diff = (int)(fso.Position - fsi.Position); //copy the rest of the file copy(fsi, fso, fsi.Length - fsi.Position); } fso.Flush(); } //rename the temp wad file FileHelper.Delete(_wadFilename); //save dat headers //int diff = (int)fileSize - (int)item.FileSize; foreach (DatItem di in _datItems.Values) { if (di == item) di.FileSize = fileSize; else di.FileOffset = (uint)((int)di.FileOffset + (di.FileOffset > item.FileOffset ? diff : 0)); } _headerFileSize = (uint)((int)_headerFileSize + diff); this.save(); File.Move(tempWadFn, _wadFilename); }
private void writeHeaderItem(BinaryEndianWriter bwPakO, PakHeaderItem ph) { bwPakO.Write(ph.FileType.Crc, _pakFormat.EndianType); uint offset = ph.FileOffset; if (_requiresPab) offset = (uint)_pakFormat.PakPabMinDataOffset + ((_pakFormat.PakPabMinDataOffset == 0 ? ph.HeaderStart : 0) + ph.FileOffset) - (uint)_pakFileLength; bwPakO.Write(offset, _pakFormat.EndianType); bwPakO.Write(ph.FileLength, _pakFormat.EndianType); bwPakO.Write(ph.PakFullFileNameQbKey, _pakFormat.EndianType); bwPakO.Write(ph.FullFilenameQbKey, _pakFormat.EndianType); bwPakO.Write(ph.NameOnlyCrc, _pakFormat.EndianType); bwPakO.Write(ph.Unknown, _pakFormat.EndianType); bwPakO.Write((uint)ph.Flags, _pakFormat.EndianType); if ((ph.Flags & PakHeaderFlags.Filename) == PakHeaderFlags.Filename) bwPakO.Write(Encoding.UTF8.GetBytes(ph.PaddedFileName), 0, PakHeaderItem.FileNameMaxLength); }
private void replaceFile(string qbFilename, long newLength, bool remove, WriteDataToStream callback) { int filePad = _pakFormat.FilePadSize; PakHeaderItem phi = null; if (_pakHeaders.ContainsKey(qbFilename.ToLower())) phi = _pakHeaders[qbFilename.ToLower()]; else { string fqk = QbKey.Create(qbFilename).Crc.ToString("X").PadLeft(8, '0').ToLower(); if (_pakHeaders.ContainsKey(fqk)) phi = _pakHeaders[fqk]; } if (phi != null) { long pad = filePad - (newLength % filePad); if (pad == filePad) pad = 0; string newPakFilename = string.Format("{0}_{1}", _pakFormat.FullPakFilename, Guid.NewGuid().ToString("N")); string newPabFilename = string.Format("{0}_{1}", _pakFormat.FullPabFilename, Guid.NewGuid().ToString("N")); uint minOffset = uint.MaxValue; bool itemFound = false; uint nextOffset = 0; foreach (PakHeaderItem ph in _pakHeaders.Values) { if (itemFound) { nextOffset = ph.FileOffset + ph.HeaderStart; itemFound = false; //don't enter this if again } if (object.ReferenceEquals(phi, ph)) itemFound = true; if (ph.HeaderStart + ph.FileOffset < minOffset) minOffset = ph.HeaderStart + ph.FileOffset; } uint lastItemPad = 0; int repPad = filePad - ((int)phi.FileLength % filePad); if (repPad == filePad) repPad = 0; //previously badly padded or last file if (nextOffset != 0 && (nextOffset - (phi.FileOffset + phi.HeaderStart)) % filePad != 0) repPad = (int)((nextOffset - (phi.FileOffset + phi.HeaderStart)) - phi.FileLength); //position of the LAST header item long lastHeaderPos = 0; //the length of all the headers (like pak when there's a pab) with padding long allHeadersLen = minOffset; //position in the input file where our file is to be replaced (not including header pos) long fileReplacePos = (phi.HeaderStart + phi.FileOffset) - allHeadersLen; //position in the input file after the file that is to be replaced long fileAfterReplacePos = fileReplacePos + phi.FileLength + repPad; //item size before modifying header //open input pak using (FileStream fsPakI = File.Open(_pakFilename, FileMode.Open, FileAccess.Read)) { using (BinaryEndianReader brPakI = new BinaryEndianReader(fsPakI)) { //open output pak temp file using (FileStream fsPakO = File.Create(newPakFilename)) { using (BinaryEndianWriter bwPakO = new BinaryEndianWriter(fsPakO)) { long diffLen = 0; //do not compensate for missing header when using zlib compression as the header is padded if (remove && _pakFormat.CompressionType != CompressionType.ZLibChunk) //we need to cater for the header being removed on all items before it. { diffLen = PakHeaderItem.FullHeaderLength; if ((phi.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename) diffLen -= PakHeaderItem.FileNameMaxLength; } //write out the headers foreach (PakHeaderItem ph in _pakHeaders.Values) { //apply offset change before finding file to be replaced //this will prevents the offset of the replaced file being changed ph.FileOffset = (uint)(ph.FileOffset - (long)diffLen); if (object.ReferenceEquals(phi, ph)) { if (remove) { long remPad = filePad - (phi.FileLength % filePad); if (remPad == filePad) remPad = 0; diffLen = phi.FileLength + remPad; //now cater for the difference in file size } else { diffLen = (long)((ph.FileLength + repPad) - (newLength + pad)); ph.FileLength = (uint)newLength; //0 for remove } } lastHeaderPos += PakHeaderItem.FullHeaderLength; if (!(remove && object.ReferenceEquals(phi, ph))) writeHeaderItem(bwPakO, ph); if ((ph.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename) lastHeaderPos -= PakHeaderItem.FileNameMaxLength; } //Move to the "last" header fsPakI.Seek(lastHeaderPos, SeekOrigin.Begin); //write out "last" HeaderType bwPakO.Write(brPakI.ReadBytes(4)); //Modify and write the offset of the "last" header's data uint lastOffset = brPakI.ReadUInt32(_pakFormat.EndianType); lastOffset = (uint)(lastOffset - (long)diffLen); //fix bad padding on last file if (nextOffset == 0 && ((lastOffset - (phi.FileOffset + phi.HeaderStart) % filePad) % filePad) != 0) { lastItemPad = (uint)filePad - (uint)(lastOffset % filePad); lastOffset += lastItemPad; } bwPakO.Write(lastOffset, _pakFormat.EndianType); //write out the end of the last header copyData(fsPakI, fsPakO, allHeadersLen - fsPakI.Position); } } } } //open input pak using (FileStream fsPakI = File.Open(_requiresPab ? _pakFormat.FullPabFilename : _pakFilename, FileMode.Open, FileAccess.Read)) { using (BinaryEndianReader brPakI = new BinaryEndianReader(fsPakI)) { //open output pak temp file using (FileStream fsPakO = _requiresPab ? File.Open(newPabFilename, FileMode.Create) : File.Open(newPakFilename, FileMode.Append)) { using (BinaryEndianWriter bwPakO = new BinaryEndianWriter(fsPakO)) { if (!_requiresPab) fsPakI.Seek(allHeadersLen, SeekOrigin.Begin); //Write out the data starting from the last header to the start of the file to be replaced (minus the length of the type and offset) copyData(fsPakI, fsPakO, fileReplacePos); //Write the new file into the pak file int pos = (int)fsPakO.Position; callback(fsPakO); if (pad != 0) fsPakO.Write(new byte[pad], 0, (int)pad); if (!_requiresPab) fileAfterReplacePos += allHeadersLen; if (lastItemPad != 0) fileAfterReplacePos -= lastItemPad; // a bit of a hack as this was not applied when this var was set as we didn't know the values //write the remainder of source the pak file fsPakI.Seek(fileAfterReplacePos, SeekOrigin.Begin); copyData(fsPakI, fsPakO, fsPakI.Length - fileAfterReplacePos); fsPakO.Flush(); } } } } fixUncompressedFileLengths(newPakFilename, newPabFilename); File.Delete(_pakFilename); File.Move(newPakFilename, _pakFilename); if (_requiresPab) { File.Delete(_pakFormat.FullPabFilename); File.Move(newPabFilename, _pakFormat.FullPabFilename); } _pakFormat.Compress(); } else throw new ApplicationException(string.Format("'{0}' does not exist in '{1}'", qbFilename, _pakFilename)); }
public static void CreateDatWad(QbKey songQk, EndianType endianType, string datFilename, string wadFilename, string songFilename, string guitarFilename, string rhythmFilename, string previewFilename) { QbKey[] keys = new QbKey[4]; int[] offsets = new int[5]; int[] sizes = new int[4]; FileHelper.Delete(wadFilename); FileHelper.Delete(datFilename); using (FileStream fsWad = File.OpenWrite(wadFilename)) { offsets[0] = (int)fsWad.Position; keys[0] = QbKey.Create(string.Format("{0}_guitar", songQk.Text)); sizes[0] = (int)writeFsbToStream(fsWad, guitarFilename, string.Concat(keys[0].Text, ".wav")); offsets[1] = (int)fsWad.Position; keys[1] = QbKey.Create(string.Format("{0}_preview", songQk.Text)); sizes[1] = (int)writeFsbToStream(fsWad, previewFilename, string.Concat(keys[1].Text, ".wav")); offsets[2] = (int)fsWad.Position; keys[2] = QbKey.Create(string.Format("{0}_rhythm", songQk.Text)); sizes[2] = (int)writeFsbToStream(fsWad, rhythmFilename, string.Concat(keys[2].Text, ".wav")); offsets[3] = (int)fsWad.Position; keys[3] = QbKey.Create(string.Format("{0}_song", songQk.Text)); sizes[3] = (int)writeFsbToStream(fsWad, songFilename, string.Concat(keys[3].Text, ".wav")); offsets[4] = (int)fsWad.Position; fsWad.Flush(); } using (FileStream fsDat = File.OpenWrite(datFilename)) { using (BinaryEndianWriter bw = new BinaryEndianWriter(fsDat)) { int l = offsets[3] + sizes[3]; if (l % 16 != 0) l += 16 - (l % 16); bw.Write((uint)keys.Length, endianType); bw.Write((uint)l, endianType); for (int i = 0; i < offsets.Length - 1; i++) { bw.Write(keys[i].Crc, endianType); bw.Write(offsets[i], endianType); bw.Write(sizes[i], endianType); bw.Write(new byte[] { 0,0,0,0,0,0,0,0 }); } fsDat.Flush(); } } }
internal override void Write(BinaryEndianWriter bw) { base.StartLengthCheck(bw); base.Write(bw); foreach (string s in _strings) { bw.Write(stringToBytes(s)); bw.Write((byte)0); if (_isUnicode) bw.Write((byte)0); } while (base.StreamPos(bw) % 4 != 0) bw.Write((byte)0); base.WriteEnd(bw); ApplicationException ex = base.TestLengthCheck(this, bw); if (ex != null) throw ex; }
private static uint recurseFiles(bool isRoot, DirectoryInfo dir, BinaryEndianWriter bwFst, BinaryEndianWriter bwStr, ref ulong totalSize, uint parentDirectory, Stream stream, ulong dataOffset, bool deleteWhileBuilding) { uint fileCount = 0; uint t; //temp uint uint rootPlaceHolder = 0; if (isRoot) { bwFst.Write(0x01000000, EndianType.Big); bwFst.Write(0x00000000, EndianType.Big); rootPlaceHolder = (uint)bwFst.BaseStream.Position; bwFst.Write(0x00000000, EndianType.Big); //write the file count to the saved space } FileInfo[] files = dir.GetFiles(); DirectoryInfo[] directories = dir.GetDirectories(); FileInfo f = null; DirectoryInfo d = null; uint fIdx = 0; uint dIdx = 0; while (fIdx < files.Length || dIdx < directories.Length) { //process files and folders in order f = (fIdx < files.Length) ? files[fIdx] : null; d = (dIdx < directories.Length) ? directories[dIdx] : null; if ((f != null && d != null && !compareNamesALessThanB(f.Name, d.Name)) || f == null) { f = null; dIdx++; } else { d = null; fIdx++; } if (d != null) { //add the current folder t = (0x01000000) | ((uint)bwStr.BaseStream.Position & 0x00ffffff); //01=folder | folder name offset bwFst.Write(t, EndianType.Big); bwFst.Write(parentDirectory, EndianType.Big); //parent id uint placeholderPos = (uint)bwFst.BaseStream.Position; bwFst.Write(parentDirectory, EndianType.Big); //placeholder for file count //write to file names stream bwStr.Write(Encoding.Default.GetBytes(d.Name), 0, d.Name.Length); bwStr.Write((byte)0x00); //null terminated fileCount++; fileCount += recurseFiles(false, d, bwFst, bwStr, ref totalSize, fileCount + parentDirectory, stream, dataOffset, deleteWhileBuilding); bwFst.Seek((int)placeholderPos, SeekOrigin.Begin); bwFst.Write(fileCount + parentDirectory + 1, EndianType.Big); //write the file count to the saved space bwFst.Seek(0, SeekOrigin.End); } else { //add the current file t = (0x00000000) | ((uint)bwStr.BaseStream.Position & 0x00ffffff); //00=file | file name offset bwFst.Write(t, EndianType.Big); ulong fstPos = totalSize; bwFst.Write((uint)(totalSize >> 2), EndianType.Big); //file offset bwFst.Write((uint)((uint)f.Length), EndianType.Big); //file length fileCount++; t = (uint)f.Length; if (t % 4 != 0) t += 4 - (t % 4); totalSize += t; bwStr.Write(Encoding.Default.GetBytes(f.Name), 0, f.Name.Length); bwStr.Write((byte)0x00); //null terminated if (stream != null) { //test file is in the correct location if (fstPos != 0 && ((ulong)stream.Position - dataOffset) != fstPos) throw new ApplicationException("Bad fstPos"); copyStream(f.FullName, stream, 4); //test file is padded to the correct length if (fstPos != 0 && ((ulong)stream.Position - dataOffset) != totalSize) throw new ApplicationException("Bad fstPos"); if (deleteWhileBuilding) FileHelper.Delete(f.FullName); } } } if (isRoot) { fileCount++; //add on the 1 for the root directory header bwFst.Seek((int)rootPlaceHolder, SeekOrigin.Begin); bwFst.Write(fileCount, EndianType.Big); //write the file count to the saved space bwFst.Seek(0, SeekOrigin.End); if (bwStr.BaseStream.Position % 4 != 0) bwStr.Write(new byte[4 - (bwStr.BaseStream.Position % 4)]); } return fileCount; }
private void xBoxCompress(string uncompFilename, string compFilename) { if (uncompFilename.ToLower() == compFilename.ToLower()) //nothing to do { return; } if (File.Exists(compFilename)) { File.Delete(compFilename); } try { if (this.CompressionType == CompressionType.ZLib) { using (FileStream outFileStream = new FileStream(compFilename, FileMode.Create)) { using (ZlibOutputStream outZStream = new ZlibOutputStream(outFileStream, true, JZlib.Z_BEST_COMPRESSION)) { using (FileStream inFileStream = new FileStream(uncompFilename, FileMode.Open, FileAccess.Read)) { copyStream(inFileStream, outZStream); } } } } else if (this.CompressionType == CompressionType.ZLibChunk) { List <uint> sizes = new List <uint>(); List <uint> offsets = new List <uint>(); byte[] header = new byte[ZlibFilePad]; int pad = 0; long lastUncompressedChunk; long endPos; EndianType et = this.EndianType; int part = 0; using (FileStream inFileStream = new FileStream(uncompFilename, FileMode.Open, FileAccess.Read)) { long pos; do { using (FileStream outFileStream = new FileStream(compFilename, inFileStream.Position == 0 ? FileMode.Create : FileMode.Append)) { part++; pad = (int)(outFileStream.Position % ZlibBlockPad); if (pad != 0 && outFileStream.Position != 0) { outFileStream.Write(header, 0, (int)ZlibBlockPad - pad); } pos = outFileStream.Position; outFileStream.Write(Encoding.ASCII.GetBytes("CHNK"), 0, 4); outFileStream.Write(header, 0, (int)_zLibHeaderLen - 4); lastUncompressedChunk = (long)_zLibChunkSize; if (inFileStream.Position + lastUncompressedChunk > inFileStream.Length) { lastUncompressedChunk = inFileStream.Length - inFileStream.Position; } using (ZlibOutputStream outZStream = new ZlibOutputStream(outFileStream, true, JZlib.Z_BEST_COMPRESSION)) { copyStream(inFileStream, outZStream, (int)lastUncompressedChunk); offsets.Add((uint)pos); sizes.Add((uint)(outFileStream.Position - pos) - _zLibHeaderLen); } } } while (inFileStream.Position < inFileStream.Length); using (FileStream outFileStream = new FileStream(compFilename, inFileStream.Position == 0 ? FileMode.Create : FileMode.Append)) { //find the end of the last file. endPos = (int)(outFileStream.Position % ZlibBlockPad); if (endPos != 0) { endPos = ZlibBlockPad - endPos; } endPos += outFileStream.Position; //pad the compressed file pad = (int)(outFileStream.Position % ZlibFilePad); if (pad != 0 && outFileStream.Position != 0) { outFileStream.Write(header, 0, (int)ZlibFilePad - pad); } } using (FileStream outFileStream = new FileStream(compFilename, FileMode.Open)) { using (BinaryEndianWriter bw = new BinaryEndianWriter(outFileStream)) { long uncompressedTotal = 0; EndianType e = this.EndianType; for (int i = 0; i < offsets.Count; i++) { outFileStream.Seek(offsets[i] + 4, SeekOrigin.Begin); bw.Write((uint)_zLibHeaderLen, e); //headerlen bw.Write((uint)sizes[i], e); //blocklen bw.Write((uint)(i != offsets.Count - 1 ? offsets[i + 1] - offsets[i] : 0xffffffff), e); //chunklen ffs if last item //next blocklen 00's if last block if (i == offsets.Count - 1) //last item { bw.Write((uint)0x00000000, e); } else if (i + 1 == offsets.Count - 1) //secondlast item { bw.Write((uint)(endPos - offsets[i + 1]), e); } else { bw.Write((uint)offsets[i + 2] - offsets[i + 1], e); } bw.Write((uint)(i != offsets.Count - 1 ? _zLibChunkSize : lastUncompressedChunk), e); //uncompressed size bw.Write((uint)uncompressedTotal, e); uncompressedTotal += (i != offsets.Count - 1 ? _zLibChunkSize : lastUncompressedChunk); } } } } } } catch (Exception ex) { throw new ApplicationException(string.Format("Compress Failed: {0}", ex)); } //using (FileStream sf = File.OpenRead(uncompFilename)) //{ // using (FileStream df = File.Create(compFilename)) // { // using (DeflateStream ds = new DeflateStream(df, CompressionMode.Compress)) // { // byte[] b = new byte[10000]; // int c = 0; // do // { // c = sf.Read(b, 0, b.Length); // ds.Write(b, 0, c); // } // while (c == b.Length); // } // } //} }
private static long writeFsbToStream(FileStream fsWrite, string wavFilename, string internalFilename) { int filenameLen = 30; long pos = fsWrite.Position; long ret; //open XBADPCM file to write as FSB file using (FileStream fs = File.OpenRead(wavFilename)) { //not fully correct for XBADPCM WavSingleChunkHeader wh = WavProcessor.ParseWavSingleChunkHeader(fs); BinaryEndianWriter bw = new BinaryEndianWriter(fsWrite); byte[] fsbFilename = new byte[filenameLen]; //FileHeader bw.Write(Encoding.Default.GetBytes("FSB3")); bw.Write((uint)1, EndianType.Little); //1 sample in file bw.Write((uint)80, EndianType.Little); //sampleheader length bw.Write(wh.ChunkLength, EndianType.Little); //sampleheader length bw.Write((uint)0x00030001, EndianType.Little); //header version 3.1 bw.Write((uint)0, EndianType.Little); //global mode flags //SampleHeader (80 byte version) bw.Write((UInt16)80, EndianType.Little); //sampleheader length bw.Write(Encoding.Default.GetBytes(internalFilename.ToLower().PadRight(filenameLen, '\0').Substring(0, filenameLen))); //write filename //sampleheader length uint lenSamp = (uint)Math.Round(((double)wh.SamplesPerSec / (double)wh.AvgBytesPerSec) * wh.ChunkLength); if (lenSamp < 0xFA00) lenSamp = 0xFA00; //set smallest allowed size? May be a memory allocation thing for FSB bw.Write(lenSamp, EndianType.Little); //sampleheader length bw.Write(wh.ChunkLength, EndianType.Little); //compressed bytes bw.Write((uint)0x0, EndianType.Little); //loop start bw.Write(lenSamp - 1, EndianType.Little); //loop end bw.Write((uint)0x20400041, EndianType.Little); //sample mode bw.Write(wh.SamplesPerSec, EndianType.Little); //frequency bw.Write((ushort)0xFF, EndianType.Little); //default volume bw.Write((ushort)0xFFFF, EndianType.Little); //default pan bw.Write((ushort)0xFF, EndianType.Little); //default pri bw.Write(wh.Channels, EndianType.Little); //channels bw.Write((float)1, EndianType.Little); //min distance bw.Write((float)1000000, EndianType.Little); //max distance bw.Write((uint)0x0, EndianType.Little); //varfreq bw.Write((ushort)0x0, EndianType.Little); //varvol bw.Write((ushort)0x0, EndianType.Little); //varpan copy(fs, fsWrite, wh.ChunkLength); uint fileSize = (uint)(24 + 80 + wh.ChunkLength); byte[] buff; ret = fsWrite.Position - pos; if (fileSize % DatWad.FileAlignment != 0) { buff = new byte[DatWad.FileAlignment - (fileSize % DatWad.FileAlignment)]; for (int i = 0; i < buff.Length; i++) buff[i] = DatWad.FileAlignmentPadValue; fsWrite.Write(buff, 0, buff.Length); } } return ret; }
/// <summary> /// Write the item to the Binary Writer /// </summary> /// <param name="bw"></param> internal virtual void Write(BinaryEndianWriter bw) { bw.Write(_qbItemValue, this.Root.PakFormat.EndianType); #region switch uint qbKeyCrc = (_itemQbKey == null ? 0 : _itemQbKey.Crc); switch (_qbFormat) { case QbFormat.SectionPointer: //Complex section type: // ItemId, FileId, Pointer, Reserved bw.Write(qbKeyCrc, this.Root.PakFormat.EndianType); bw.Write(_fileId, this.Root.PakFormat.EndianType); bw.Write(_pointer, this.Root.PakFormat.EndianType); bw.Write(_reserved, this.Root.PakFormat.EndianType); break; case QbFormat.SectionValue: //Simple section type: // ItemId, FileId bw.Write(qbKeyCrc, this.Root.PakFormat.EndianType); bw.Write(_fileId, this.Root.PakFormat.EndianType); break; case QbFormat.StructItemPointer: //Complex struct type: // ItemId, Pointer, NextItemPointer bw.Write(qbKeyCrc, this.Root.PakFormat.EndianType); bw.Write(_pointer, this.Root.PakFormat.EndianType); bw.Write(_nextItemPointer, this.Root.PakFormat.EndianType); break; case QbFormat.StructItemValue: //Simple struct type: // ItemId, Value (4 byte), NextItemPointer bw.Write(qbKeyCrc, this.Root.PakFormat.EndianType); break; case QbFormat.ArrayPointer: //Complex array type: // ItemCount, Pointer, Pointers - (if length is 1 then pointer points to first item and Pointers are abscent) bw.Write(_itemCount, this.Root.PakFormat.EndianType); if (_itemCount == 0) bw.Write(0, this.Root.PakFormat.EndianType); else if (_itemCount > 1) bw.Write(_pointer, this.Root.PakFormat.EndianType); for (int i = 0; i < _itemCount; i++) bw.Write(_pointers[i], this.Root.PakFormat.EndianType); break; case QbFormat.ArrayValue: //Simple array type: // ItemCount, Pointer, Pointers - (if length is 1 then pointer points to first item and Pointers are abscent) bw.Write(_itemCount, this.Root.PakFormat.EndianType); if (_itemCount > 1) bw.Write(_pointer, this.Root.PakFormat.EndianType); break; case QbFormat.StructHeader: break; case QbFormat.Floats: break; case QbFormat.Unknown: break; default: break; } #endregion }
private void replaceFile(string qbFilename, long newLength, bool remove, WriteDataToStream callback) { int filePad = _pakFormat.FilePadSize; PakHeaderItem phi = null; if (_pakHeaders.ContainsKey(qbFilename.ToLower())) { phi = _pakHeaders[qbFilename.ToLower()]; } else { string fqk = QbKey.Create(qbFilename).Crc.ToString("X").PadLeft(8, '0').ToLower(); if (_pakHeaders.ContainsKey(fqk)) { phi = _pakHeaders[fqk]; } } if (phi != null) { long pad = filePad - (newLength % filePad); if (pad == filePad) { pad = 0; } string newPakFilename = string.Format("{0}_{1}", _pakFormat.FullPakFilename, Guid.NewGuid().ToString("N")); string newPabFilename = string.Format("{0}_{1}", _pakFormat.FullPabFilename, Guid.NewGuid().ToString("N")); uint minOffset = uint.MaxValue; bool itemFound = false; uint nextOffset = 0; foreach (PakHeaderItem ph in _pakHeaders.Values) { if (itemFound) { nextOffset = ph.FileOffset + ph.HeaderStart; itemFound = false; //don't enter this if again } if (object.ReferenceEquals(phi, ph)) { itemFound = true; } if (ph.HeaderStart + ph.FileOffset < minOffset) { minOffset = ph.HeaderStart + ph.FileOffset; } } uint lastItemPad = 0; int repPad = filePad - ((int)phi.FileLength % filePad); if (repPad == filePad) { repPad = 0; } //previously badly padded or last file if (nextOffset != 0 && (nextOffset - (phi.FileOffset + phi.HeaderStart)) % filePad != 0) { repPad = (int)((nextOffset - (phi.FileOffset + phi.HeaderStart)) - phi.FileLength); } //position of the LAST header item long lastHeaderPos = 0; //the length of all the headers (like pak when there's a pab) with padding long allHeadersLen = minOffset; //position in the input file where our file is to be replaced (not including header pos) long fileReplacePos = (phi.HeaderStart + phi.FileOffset) - allHeadersLen; //position in the input file after the file that is to be replaced long fileAfterReplacePos = fileReplacePos + phi.FileLength + repPad; //item size before modifying header //open input pak using (FileStream fsPakI = File.Open(_pakFilename, FileMode.Open, FileAccess.Read)) { using (BinaryEndianReader brPakI = new BinaryEndianReader(fsPakI)) { //open output pak temp file using (FileStream fsPakO = File.Create(newPakFilename)) { using (BinaryEndianWriter bwPakO = new BinaryEndianWriter(fsPakO)) { long diffLen = 0; //do not compensate for missing header when using zlib compression as the header is padded if (remove && _pakFormat.CompressionType != CompressionType.ZLibChunk) //we need to cater for the header being removed on all items before it. { diffLen = PakHeaderItem.FullHeaderLength; if ((phi.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename) { diffLen -= PakHeaderItem.FileNameMaxLength; } } //write out the headers foreach (PakHeaderItem ph in _pakHeaders.Values) { //apply offset change before finding file to be replaced //this will prevents the offset of the replaced file being changed ph.FileOffset = (uint)(ph.FileOffset - (long)diffLen); if (object.ReferenceEquals(phi, ph)) { if (remove) { long remPad = filePad - (phi.FileLength % filePad); if (remPad == filePad) { remPad = 0; } diffLen = phi.FileLength + remPad; //now cater for the difference in file size } else { diffLen = (long)((ph.FileLength + repPad) - (newLength + pad)); ph.FileLength = (uint)newLength; //0 for remove } } lastHeaderPos += PakHeaderItem.FullHeaderLength; if (!(remove && object.ReferenceEquals(phi, ph))) { writeHeaderItem(bwPakO, ph); } if ((ph.Flags & PakHeaderFlags.Filename) != PakHeaderFlags.Filename) { lastHeaderPos -= PakHeaderItem.FileNameMaxLength; } } //Move to the "last" header fsPakI.Seek(lastHeaderPos, SeekOrigin.Begin); //write out "last" HeaderType bwPakO.Write(brPakI.ReadBytes(4)); //Modify and write the offset of the "last" header's data uint lastOffset = brPakI.ReadUInt32(_pakFormat.EndianType); lastOffset = (uint)(lastOffset - (long)diffLen); //fix bad padding on last file if (nextOffset == 0 && ((lastOffset - (phi.FileOffset + phi.HeaderStart) % filePad) % filePad) != 0) { lastItemPad = (uint)filePad - (uint)(lastOffset % filePad); lastOffset += lastItemPad; } bwPakO.Write(lastOffset, _pakFormat.EndianType); //write out the end of the last header copyData(fsPakI, fsPakO, allHeadersLen - fsPakI.Position); } } } } //open input pak using (FileStream fsPakI = File.Open(_requiresPab ? _pakFormat.FullPabFilename : _pakFilename, FileMode.Open, FileAccess.Read)) { using (BinaryEndianReader brPakI = new BinaryEndianReader(fsPakI)) { //open output pak temp file using (FileStream fsPakO = _requiresPab ? File.Open(newPabFilename, FileMode.Create) : File.Open(newPakFilename, FileMode.Append)) { using (BinaryEndianWriter bwPakO = new BinaryEndianWriter(fsPakO)) { if (!_requiresPab) { fsPakI.Seek(allHeadersLen, SeekOrigin.Begin); } //Write out the data starting from the last header to the start of the file to be replaced (minus the length of the type and offset) copyData(fsPakI, fsPakO, fileReplacePos); //Write the new file into the pak file int pos = (int)fsPakO.Position; callback(fsPakO); if (pad != 0) { fsPakO.Write(new byte[pad], 0, (int)pad); } if (!_requiresPab) { fileAfterReplacePos += allHeadersLen; } if (lastItemPad != 0) { fileAfterReplacePos -= lastItemPad; // a bit of a hack as this was not applied when this var was set as we didn't know the values } //write the remainder of source the pak file fsPakI.Seek(fileAfterReplacePos, SeekOrigin.Begin); copyData(fsPakI, fsPakO, fsPakI.Length - fileAfterReplacePos); fsPakO.Flush(); } } } } fixUncompressedFileLengths(newPakFilename, newPabFilename); File.Delete(_pakFilename); File.Move(newPakFilename, _pakFilename); if (_requiresPab) { File.Delete(_pakFormat.FullPabFilename); File.Move(newPabFilename, _pakFormat.FullPabFilename); } _pakFormat.Compress(); } else { throw new ApplicationException(string.Format("'{0}' does not exist in '{1}'", qbFilename, _pakFilename)); } }
internal override void Write(BinaryEndianWriter bw) { base.StartLengthCheck(bw); base.Write(bw); foreach (uint i in _values) bw.Write(i, base.Root.PakFormat.EndianType); base.WriteEnd(bw); ApplicationException ex = base.TestLengthCheck(this, bw); if (ex != null) throw ex; }
private void xBoxCompress(string uncompFilename, string compFilename) { if (uncompFilename.ToLower() == compFilename.ToLower()) //nothing to do return; if (File.Exists(compFilename)) File.Delete(compFilename); try { if (this.CompressionType == CompressionType.ZLib) { using (FileStream outFileStream = new FileStream(compFilename, FileMode.Create)) { using (ZlibOutputStream outZStream = new ZlibOutputStream(outFileStream, true, JZlib.Z_BEST_COMPRESSION)) { using (FileStream inFileStream = new FileStream(uncompFilename, FileMode.Open, FileAccess.Read)) { copyStream(inFileStream, outZStream); } } } } else if (this.CompressionType == CompressionType.ZLibChunk) { List<uint> sizes = new List<uint>(); List<uint> offsets = new List<uint>(); byte[] header = new byte[ZlibFilePad]; int pad = 0; long lastUncompressedChunk; long endPos; EndianType et = this.EndianType; int part = 0; using (FileStream inFileStream = new FileStream(uncompFilename, FileMode.Open, FileAccess.Read)) { long pos; do { using (FileStream outFileStream = new FileStream(compFilename, inFileStream.Position == 0 ? FileMode.Create : FileMode.Append)) { part++; pad = (int)(outFileStream.Position % ZlibBlockPad); if (pad != 0 && outFileStream.Position != 0) outFileStream.Write(header, 0, (int)ZlibBlockPad - pad); pos = outFileStream.Position; outFileStream.Write(Encoding.ASCII.GetBytes("CHNK"), 0, 4); outFileStream.Write(header, 0, (int)_zLibHeaderLen - 4); lastUncompressedChunk = (long)_zLibChunkSize; if (inFileStream.Position + lastUncompressedChunk > inFileStream.Length) lastUncompressedChunk = inFileStream.Length - inFileStream.Position; using (ZlibOutputStream outZStream = new ZlibOutputStream(outFileStream, true, JZlib.Z_BEST_COMPRESSION)) { copyStream(inFileStream, outZStream, (int)lastUncompressedChunk); offsets.Add((uint)pos); sizes.Add((uint)(outFileStream.Position - pos) - _zLibHeaderLen); } } } while (inFileStream.Position < inFileStream.Length); using (FileStream outFileStream = new FileStream(compFilename, inFileStream.Position == 0 ? FileMode.Create : FileMode.Append)) { //find the end of the last file. endPos = (int)(outFileStream.Position % ZlibBlockPad); if (endPos != 0) endPos = ZlibBlockPad - endPos; endPos += outFileStream.Position; //pad the compressed file pad = (int)(outFileStream.Position % ZlibFilePad); if (pad != 0 && outFileStream.Position != 0) outFileStream.Write(header, 0, (int)ZlibFilePad - pad); } using (FileStream outFileStream = new FileStream(compFilename, FileMode.Open)) { using (BinaryEndianWriter bw = new BinaryEndianWriter(outFileStream)) { long uncompressedTotal = 0; EndianType e = this.EndianType; for (int i = 0; i < offsets.Count; i++) { outFileStream.Seek(offsets[i] + 4, SeekOrigin.Begin); bw.Write((uint)_zLibHeaderLen, e); //headerlen bw.Write((uint)sizes[i], e); //blocklen bw.Write((uint)(i != offsets.Count - 1 ? offsets[i + 1] - offsets[i] : 0xffffffff), e); //chunklen ffs if last item //next blocklen 00's if last block if (i == offsets.Count - 1) //last item bw.Write((uint)0x00000000, e); else if (i + 1 == offsets.Count - 1) //secondlast item bw.Write((uint)(endPos - offsets[i + 1]), e); else bw.Write((uint)offsets[i + 2] - offsets[i + 1], e); bw.Write((uint)(i != offsets.Count - 1 ? _zLibChunkSize : lastUncompressedChunk), e); //uncompressed size bw.Write((uint)uncompressedTotal, e); uncompressedTotal += (i != offsets.Count - 1 ? _zLibChunkSize : lastUncompressedChunk); } } } } } } catch (Exception ex) { throw new ApplicationException(string.Format("Compress Failed: {0}", ex)); } //using (FileStream sf = File.OpenRead(uncompFilename)) //{ // using (FileStream df = File.Create(compFilename)) // { // using (DeflateStream ds = new DeflateStream(df, CompressionMode.Compress)) // { // byte[] b = new byte[10000]; // int c = 0; // do // { // c = sf.Read(b, 0, b.Length); // ds.Write(b, 0, c); // } // while (c == b.Length); // } // } //} }
internal override void Write(BinaryEndianWriter bw) { base.StartLengthCheck(bw); base.Write(bw); if (base.QbItemType != QbItemType.StructHeader) bw.Write(_headerValue, base.Root.PakFormat.EndianType); bw.Write(_iniNextItemPointer, base.Root.PakFormat.EndianType); foreach (QbItemBase qib in base.Items) qib.Write(bw); base.WriteEnd(bw); ApplicationException ex = base.TestLengthCheck(this, bw); if (ex != null) throw ex; }
public static void BuildPartition(string partitionBinFilename, string mainDolFilename, string appLoaderImgFilename, string bi2BinFilename, string bootBinFilename, string sourceDirectory, string partitionFilename, bool deleteWhileBuilding) { ulong totalSize = 0; BinaryEndianReader brFst = null; BinaryEndianWriter bwFst = new BinaryEndianWriter(new MemoryStream()); BinaryEndianWriter bwStr = new BinaryEndianWriter(new MemoryStream()); BinaryEndianWriter bwBootBin = null; BinaryEndianWriter bwPartitionBin = null; BinaryEndianWriter bwB12Bin = null; try { DirectoryInfo inputFolder = new DirectoryInfo(sourceDirectory); //DateTime n = DateTime.Now; uint fileCount = recurseFiles(true, inputFolder, bwFst, bwStr, ref totalSize, 0, null, 0, deleteWhileBuilding); //System.Diagnostics.Debug.WriteLine((DateTime.Now - n).Ticks); // get the file sizes we need - apploader and main.dol FileInfo appLoaderImg = new FileInfo(appLoaderImgFilename); FileInfo mainDol = new FileInfo(mainDolFilename); // now calculate the relative offsets uint pad1Size = 0x100 - (((uint)appLoaderImg.Length + 0x2440) % 0x100); uint pad2Size = 0x100 - ((uint)mainDol.Length % 0x100); // just a pad out for no real reason :) uint pad3Size = 0x2000; uint mainDolOffset = 0x2440 + (uint)appLoaderImg.Length + pad1Size; uint fstOffset = mainDolOffset + pad2Size + (uint)mainDol.Length; // modify the data size in partition.bin // read in partition.bin bwPartitionBin = new BinaryEndianWriter(new MemoryStream(File.ReadAllBytes(partitionBinFilename))); // now Actual size = scaled up by sizes totalSize += pad1Size + 0x2440 + pad2Size + pad3Size + (uint)mainDol.Length + (uint)appLoaderImg.Length; ulong dataSize = (totalSize / 0x7c00) * 0x8000; if (dataSize % 0x7c00 != 0) dataSize += 0x8000; bwPartitionBin.Seek(0x2BC, SeekOrigin.Begin); bwPartitionBin.Write((uint)dataSize >> 2, EndianType.Big); // generate a boot.bin bwBootBin = new BinaryEndianWriter(new MemoryStream(File.ReadAllBytes(bootBinFilename))); // now the size offsets bwBootBin.Seek(0x420, SeekOrigin.Begin); bwBootBin.Write(mainDolOffset >> 2, EndianType.Big); bwBootBin.Write(fstOffset >> 2, EndianType.Big); bwBootBin.Write((uint)(bwFst.BaseStream.Length + bwStr.BaseStream.Length) >> 2, EndianType.Big); bwBootBin.Write((uint)(bwFst.BaseStream.Length + bwStr.BaseStream.Length) >> 2, EndianType.Big); // calculate what we need to modify the FST entries by ulong dataOffset = 0x2440 + pad1Size + (uint)appLoaderImg.Length + (uint)mainDol.Length + pad2Size + (uint)bwFst.BaseStream.Length + (uint)bwStr.BaseStream.Length + pad3Size; dataOffset = (dataOffset >> 2); // modify the fst.bin to include all the correct offsets brFst = new BinaryEndianReader(bwFst.BaseStream); brFst.BaseStream.Seek(8, SeekOrigin.Begin); uint fstEntries = brFst.ReadUInt32(EndianType.Big); for (int i = 1; i < fstEntries; i++) //1 as we've already skipped the root { if (brFst.ReadByte() == 0) //file { brFst.BaseStream.Seek(3, SeekOrigin.Current); //skip the rest of the uint uint temp = brFst.ReadUInt32(EndianType.Big); bwFst.BaseStream.Seek(-4, SeekOrigin.Current); //THE STREAMS ARE THE SAME (be careful of bugs when the position moves) bwFst.Write((uint)dataOffset + temp, EndianType.Big); brFst.BaseStream.Seek(4, SeekOrigin.Current); //skip the rest of the file } else brFst.BaseStream.Seek(0xc - 1, SeekOrigin.Current); //skip the rest of the directory } using (FileStream fs = new FileStream(partitionFilename, FileMode.Create)) { copyStream(bwPartitionBin.BaseStream, fs, 4); copyStream(bwBootBin.BaseStream, fs, 4); copyStream(bi2BinFilename, fs, 4); copyStream(appLoaderImgFilename, fs, 4); fs.Write(new byte[pad1Size], 0, (int)pad1Size); copyStream(mainDolFilename, fs, 4); fs.Write(new byte[pad2Size], 0, (int)pad2Size); copyStream(bwFst.BaseStream, fs, 4); copyStream(bwStr.BaseStream, fs, 4); fs.Write(new byte[pad3Size], 0, (int)pad3Size); //copy all the files to the end of the partition totalSize = dataOffset; //will give the offsets the correct value (not that it matters here heh) bwFst.BaseStream.Seek(0, SeekOrigin.Begin); bwStr.BaseStream.Seek(0, SeekOrigin.Begin); recurseFiles(true, inputFolder, bwFst, bwStr, ref totalSize, 0, fs, (ulong)fs.Position - dataOffset, deleteWhileBuilding); if (deleteWhileBuilding) { try { inputFolder.Delete(true); } catch { } } } } finally { if (brFst != null) brFst.Close(); bwFst.Close(); bwStr.Close(); if (bwBootBin != null) bwBootBin.Close(); if (bwPartitionBin != null) bwPartitionBin.Close(); if (bwB12Bin != null) bwB12Bin.Close(); } }