Esempio n. 1
0
        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);
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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));
        }