Esempio n. 1
0
        private unsafe Dictionary <DbPackage, IdxEntry[]> ReadDictionary(Int32 entriesCount, IdxStruct *idxPtr)
        {
            // Count files in packages
            Dictionary <Int32, Int32> fileNumbers = new Dictionary <Int32, Int32>(_mftContent.Packages.Count);

            for (Int32 i = 0; i < entriesCount; i++)
            {
                Int32 packageIndex = idxPtr[i].Package;
                if (fileNumbers.TryGetValue(packageIndex, out Int32 count))
                {
                    fileNumbers[packageIndex] = count + 1;
                }
                else
                {
                    fileNumbers[packageIndex] = 1;
                }
            }

            // Prepare dictionary
            Dictionary <DbPackage, IdxEntry[]> dic = new Dictionary <DbPackage, IdxEntry[]>(fileNumbers.Count);

            foreach (var pair in fileNumbers)
            {
                Int32 packageIndex = pair.Key;
                Int32 fileCount    = pair.Value;

                DbPackage  package    = _mftContent.Packages[packageIndex];
                IdxEntry[] idxEntries = new IdxEntry[fileCount];

                dic.Add(package, idxEntries);
            }

            // Fill dicrionary
            for (Int32 i = 0; i < entriesCount; i++)
            {
                IdxStruct  idxEntry   = idxPtr[i];
                DbPackage  package    = _mftContent.Packages[idxEntry.Package];
                IdxEntry[] idxEntries = dic[package];

                Int32 fileIndex = IndexInPackage(idxEntry.Package, idxEntries);
                idxEntries[fileIndex] = ToEntry(i, in idxEntry);
            }

            Int32 IndexInPackage(Int32 packageNumber, IdxEntry[] array)
            {
                return(array.Length - fileNumbers[packageNumber]--);
            }

            return(dic);
        }
Esempio n. 2
0
        public void Enqueue(DbPackage package, IdxEntry entry)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException("DbExtractor already disposed.");
            }

            if (_exceptions.Count > 0)
            {
                Dispose();
            }

            _semaphore.WaitOne();

            lock (_queue)
            {
                _queue.Enqueue(Tuple.Create(package, entry));
                Monitor.Pulse(_queue);
            }
        }
Esempio n. 3
0
        private void Extract(DbPackage package, IdxEntry entry, ThreadContext context)
        {
            if (context.Package != package)
            {
                context.Stream?.Dispose();
                context.Stream  = File.OpenRead(package.FullPath);
                context.Package = package;
            }

            Byte[] buff = context.Buffer;
            if (buff == null)
            {
                buff           = new Byte[entry.UncompressedSize];
                context.Buffer = buff;
            }
            else if (buff.Length < entry.UncompressedSize)
            {
                Array.Resize(ref buff, entry.UncompressedSize);
                context.Buffer = buff;
            }

            FileStream inputStream = context.Stream;

            if (inputStream.Position != entry.Offset)
            {
                inputStream.Position = entry.Offset;
            }

            if (entry.IsCompressed)
            {
                unsafe
                {
                    fixed(Byte *ptr = buff)
                    {
                        Int32 readedSize = context.Decompressor.ReadCompressedFile(entry.CompressedSize, ptr, inputStream);

                        if (readedSize != entry.UncompressedSize)
                        {
                            throw new EndOfStreamException($"Failed to decompress the file {package.Name}:{entry.Offset}");
                        }
                    }
                }
            }
            else
            {
                Int32 offset = 0;
                Int32 size   = entry.UncompressedSize;
                while (size > 0)
                {
                    Int32 readed = inputStream.Read(buff, offset, size);
                    if (readed == 0 && size > 0)
                    {
                        throw new EndOfStreamException($"Failed to copy the file {package.Name}:{entry.Offset}");
                    }

                    size   -= readed;
                    offset += readed;
                }
            }

            String directoryPath = Path.Combine(_outputDirectory, package.Name);

            if (entry.CompressedSize < 8)
            {
                throw new NotSupportedException($"Compressed size is too small: {entry.CompressedSize}");
            }

            UInt16 version = UInt16.MaxValue;

            void CheckVersion(String name, Int32 supported)
            {
                version = UInt16.Parse(Encoding.ASCII.GetString(buff, 2, 2), NumberStyles.Integer, CultureInfo.InvariantCulture);
                if (version != supported)
                {
                    throw new NotSupportedException($"Invalid {name} version: {version}. Expected: {supported}");
                }
            }

            String GetOutputPath(String tag)
            {
                DbRecordId recordId = new DbRecordId(entry.ResourceId);

                return(Path.Combine(directoryPath, Rename && DbNames.TryGetRecordName(recordId, out var name)
                    ? $"{recordId}_{name}.{tag.ToLowerInvariant()}"
                    : $"{recordId}.{tag.ToLowerInvariant()}"));
            }

            String outputPath;

            ITarget target;

            String magicTag = Encoding.ASCII.GetString(buff, 0, 2);

            switch (magicTag)
            {
            case "LV":
                CheckVersion(magicTag, _version.LV);
                outputPath = GetOutputPath(magicTag);
                target     = CopyTarget.Instance;
                break;

            case "AM":
                CheckVersion(magicTag, _version.AM);
                if (Convert)
                {
                    outputPath = GetOutputPath("tiff");
                    target     = ImageTarget.Instance;
                }
                else
                {
                    outputPath = GetOutputPath(magicTag);
                    target     = CopyTarget.Instance;
                }

                break;

            case "GV":
                CheckVersion(magicTag, _version.GV);
                outputPath = GetOutputPath(magicTag);
                target     = GVTarget.Instance;
                target     = CopyTarget.Instance;
                break;

            case "TX":
                CheckVersion(magicTag, _version.TX);
                if (Convert)
                {
                    outputPath = GetOutputPath("txt");
                    target     = TextTarget.Instance;
                }
                else
                {
                    outputPath = GetOutputPath(magicTag);
                    target     = CopyTarget.Instance;
                }
                break;

            case "CH":
                CheckVersion(magicTag, _version.CH);
                outputPath = GetOutputPath(magicTag);
                target     = CopyTarget.Instance;
                break;

            case "IL":
                CheckVersion(magicTag, _version.IL);
                outputPath = GetOutputPath(magicTag);
                target     = ILTarget.Instance;
                target     = CopyTarget.Instance;
                break;

            case "VS":
                outputPath = GetOutputPath("vssf");
                if (Convert)
                {
                    outputPath = GetOutputPath("mp3");
                    target     = SoundTarget.Instance;
                }
                else
                {
                    outputPath = GetOutputPath(magicTag);
                    target     = CopyTarget.Instance;
                }
                break;

            default:
            {
                if (Encoding.ASCII.GetString(buff, 4, 4) != "moov")
                {
                    throw new NotSupportedException($"Invalid magic number: {Encoding.ASCII.GetString(buff, 0, 8)}");
                }

                directoryPath = _outputDirectory;
                outputPath    = Path.Combine(directoryPath, $"{entry.ResourceId:X8}_{package.Name}.qt");
                target        = CopyTarget.Instance;
                break;
            }
            }

            if (!Convert)
            {
                target = CopyTarget.Instance;
            }

            Directory.CreateDirectory(directoryPath);

            ArraySegment <Byte> segment = new ArraySegment <Byte>(buff, 0, entry.UncompressedSize);

            target.Write(segment, outputPath, version);
        }