public long ReallocateFileData(int dataOffset, int length) { var offset = mMapper.Reallocate(DataBaseOffset + dataOffset, length); var oldVirtualFileSize = VirtualFileSize; VirtualFileSize = Math.Max(VirtualFileSize, offset + length); if (VirtualFileSize > MAX_FILE_SIZE) { mLogger.Error("Out of available memory! 4GB address space exhausted"); } else if (VirtualFileSize > oldVirtualFileSize) { mLogger.Info($"{FileName} Virtual size increased to 0x{VirtualFileSize:X8}"); } return(( long )(offset - DataBaseOffset)); }
public long AllocateSectionMemory(WaveBankSegmentIndex segmentIndex, int length) { var segment = Native.Header->Segments + (int)segmentIndex; var origVirtualSize = VirtualFileSize; var offset = AlignmentHelper.Align(VirtualFileSize, 0x10000); VirtualFileSize = offset + length; var segmentOffset = offset - segment->Offset; if (segmentOffset > uint.MaxValue) { mLogger.Error("Out of available memory! 4GB address space exhausted"); } segment->Length += ( int )(VirtualFileSize - origVirtualSize); return(segmentOffset); }
public bool Redirect(string filePath) { if (IsCompact) { mLogger.Error($"Compact wave format not implemented, unable to redirect to {filePath}"); return(false); } var fileSize = 0L; using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) fileSize = stream.Length; if (fileSize == 0) { mLogger.Error($"{filePath} is empty"); return(false); } var txthPath = filePath + ".txth"; if (!File.Exists(txthPath)) { mLogger.Error($"{filePath} Missing .txth file! Expected location: {txthPath}"); return(false); } if (!ParseTxth(txthPath)) { mLogger.Error($"{txthPath} Failed to parse. Make sure the file is formatted correctly."); return(false); } if (!IsCompact) { var originalLength = Native->PlayRegion.Length; // Try to recalculate the actual size based on the duration if (!WaveBankFormatHelper.TryGetSamplesToByteOffset(Native->Format.FormatTag.Get(), Native->Format.BitsPerSample.Get(), Native->FlagsAndDuration.Duration, Native->Format.CalculatedBlockAlign, Native->Format.Channels, out Native->PlayRegion.Length)) { // In case we can't, just accept the file size Native->PlayRegion.Length = (int)fileSize; } if (Native->PlayRegion.Length > originalLength) { // If the new size exceeds that of the old, allocate new memory for it Native->PlayRegion.Offset = ( int )(WaveBank.AllocateSectionMemory(WaveBankSegmentIndex.EntryWaveData, ( int )Native->PlayRegion.Length)); } } else { mLogger.Error($"Compact wave format not implemented, unable to redirect to {filePath}"); return(false); } FilePath = filePath; FileName = Path.GetFileNameWithoutExtension(FilePath); FileSize = fileSize; IsRedirected = true; return(true); }
public override Native.NtStatus NtCreateFileImpl(string newFilePath, out IntPtr handle, FileAccess access, ref Native.OBJECT_ATTRIBUTES objectAttributes, ref Native.IO_STATUS_BLOCK ioStatus, ref long allocSize, uint fileAttributes, FileShare share, uint createDisposition, uint createOptions, IntPtr eaBuffer, uint eaLength) { var result = mHooks.NtCreateFileHook.OriginalFunction(out handle, access, ref objectAttributes, ref ioStatus, ref allocSize, fileAttributes, share, createDisposition, createOptions, eaBuffer, eaLength); var fileName = Path.GetFileNameWithoutExtension(newFilePath); var ext = Path.GetExtension(newFilePath); var isWaveBank = ext.Equals(".xwb", StringComparison.OrdinalIgnoreCase); VirtualWaveBank waveBank = null; VirtualSoundBank soundBank = null; if (isWaveBank && !mWaveBankByName.TryGetValue(fileName, out waveBank)) { // Try get sound bank for cue names mSoundBankByName.TryGetValue(fileName, out soundBank); // Wave bank mWaveBankByName[fileName] = waveBank = new VirtualWaveBank(mLogger); // Load wave bank using (var fileStream = new FileStream(new SafeFileHandle(handle, true), FileAccess.Read, 1024 * 1024)) waveBank.LoadFromFile(newFilePath, fileStream); // Reopen file to reset it result = mHooks.NtCreateFileHook.OriginalFunction(out handle, access, ref objectAttributes, ref ioStatus, ref allocSize, fileAttributes, share, createDisposition, createOptions, eaBuffer, eaLength); ProcessWaveBankEntries(newFilePath, soundBank, waveBank); mLogger.Debug($"{newFilePath} registered"); } else if (!mSoundBankByName.TryGetValue(fileName, out soundBank)) { // Sound bank mSoundBankByName[fileName] = soundBank = new VirtualSoundBank(mLogger); // Load wave bank using (var fileStream = new FileStream(new SafeFileHandle(handle, true), FileAccess.Read, 1024 * 1024)) soundBank.LoadFromFile(newFilePath, fileStream); // Reopen file to reset it result = mHooks.NtCreateFileHook.OriginalFunction(out handle, access, ref objectAttributes, ref ioStatus, ref allocSize, fileAttributes, share, createDisposition, createOptions, eaBuffer, eaLength); // Find associated wave bank if (!mWaveBankByName.TryGetValue(soundBank.Native.WaveBankNames[0].Name, out waveBank)) { mLogger.Error($"{newFilePath} Can't find wavebank!"); } else { ProcessWaveBankEntries(newFilePath, soundBank, waveBank); } } if (isWaveBank) { mWaveBankByHandle.Add(handle, waveBank); mLogger.Debug($"{waveBank.FileName} Hnd {handle} registered"); } else { mSoundBankByHandle.Add(handle, soundBank); } return(result); }
private NtStatus ReadFile(IntPtr handle, IntPtr hEvent, IntPtr *apcRoutine, IntPtr *apcContext, ref Native.IO_STATUS_BLOCK ioStatus, byte *buffer, uint length, LARGE_INTEGER *byteOffset, IntPtr key, VirtualDwPack pack, long offset, long effOffset) { // File data read NtStatus result = NtStatus.Success; for (int i = 0; i < pack.Entries.Count; i++) { var entry = pack.Entries[i]; var dataOffset = (pack.Native.Data + entry.Native->DataOffset) - pack.Native.Ptr; if (effOffset < dataOffset || effOffset >= (dataOffset + entry.Native->CompressedSize)) { continue; } var fileDataOffset = effOffset - dataOffset; var readEndOffset = fileDataOffset + length; if (readEndOffset > entry.Native->CompressedSize) { continue; } // Make sure the file has been redirected // This is done as late as possible to improve startup times if (!entry.IsRedirected) { mLogger.Info($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Data access Offset: 0x{effOffset:X8} Length: 0x{length:X8}"); result = mHooks.NtReadFileHook.OriginalFunction(handle, hEvent, apcRoutine, apcContext, ref ioStatus, buffer, length, byteOffset, key); } else { mLogger.Info($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Data access Offset: 0x{effOffset:X8} Length: 0x{length:X8} redirected to {entry.RedirectedFilePath}"); result = NtStatus.Success; if (fileDataOffset < 0) { mLogger.Error($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Offset is before start of data!!!"); } else if (fileDataOffset > entry.RedirectedFileSize) { mLogger.Error($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Offset is after end of data!!!"); } mLogger.Debug($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Reading 0x{length:X8} bytes from redirected file at offset 0x{fileDataOffset:X8}"); // Get cached file stream if the file was previously opened or open a new file Stream redirectedStream; if (mCachedFile == entry) { redirectedStream = mCachedFileStream; } else { mCachedFileStream?.Close(); mCachedFile = entry; mCachedFileStream = redirectedStream = entry.OpenRead(); } // Read from redirected file into the buffer try { redirectedStream.Seek(fileDataOffset, SeekOrigin.Begin); var readBytes = redirectedStream.Read(new Span <byte>(( void * )buffer, ( int )length)); SetBytesRead(handle, ( int )offset, ( int )length, ref ioStatus); if (readBytes != length) { mLogger.Error($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) File read length doesnt match requested read length!! Expected 0x{length:X8}, Actual 0x{readBytes:X8}"); } mLogger.Debug($"{pack.FileName} Hnd: {handle} {entry.Native->Path} Idx: ({i}) Wrote redirected file to buffer"); } catch (Exception e) { mLogger.Debug($"{pack.FileName} Hnd: {handle} Idx: {i} {entry.Native->Path} Unhandled exception thrown during reading {entry.RedirectedFilePath}: {e}"); } } // Return early, we're done here return(result); } mLogger.Error($"{pack.FileName} Hnd: {handle} Unhandled file data read request!! Offset: 0x{effOffset:X8} Length: 0x{length:X8}"); return(mHooks.NtReadFileHook.OriginalFunction(handle, hEvent, apcRoutine, apcContext, ref ioStatus, buffer, length, byteOffset, key)); }