Beispiel #1
0
        /// <summary>
        /// Creates an item for testing.
        /// </summary>
        /// <param name="id">The item id.</param>
        /// <param name="dirId">The directory id.</param>
        /// <param name="fileName">The item name.</param>
        /// <param name="dataOffset">Data offset.</param>
        /// <param name="extractedSize">Extracted size.</param>
        /// <param name="chunkSizes">Compressed chunks sizes.</param>
        /// <param name="type">The item type.</param>
        /// <returns>The new item.</returns>
        internal static NefsItem CreateItem(
            uint id,
            uint dirId,
            string fileName,
            UInt64 dataOffset,
            UInt32 extractedSize,
            IReadOnlyList <UInt32> chunkSizes,
            NefsItemType type)
        {
            var attributes = new NefsItemAttributes(
                isDirectory: type == NefsItemType.Directory,
                v16IsTransformed: true);

            var transform  = TestTransform;
            var chunks     = NefsDataChunk.CreateChunkList(chunkSizes, transform);
            var size       = new NefsItemSize(extractedSize, chunks);
            var dataSource = new NefsFileDataSource(@"C:\source.txt", dataOffset, size, extractedSize != chunkSizes.LastOrDefault());

            return(new NefsItem(
                       Guid.NewGuid(),
                       new NefsItemId(id),
                       fileName,
                       new NefsItemId(dirId),
                       dataSource,
                       transform,
                       attributes));
        }
Beispiel #2
0
        /// <summary>
        /// Creates an item for testing.
        /// </summary>
        /// <param name="id">The item id.</param>
        /// <param name="dirId">The directory id.</param>
        /// <param name="fileName">The item name.</param>
        /// <param name="dataOffset">Data offset.</param>
        /// <param name="extractedSize">Extracted size.</param>
        /// <param name="chunkSizes">Compressed chunks sizes.</param>
        /// <param name="type">The item type.</param>
        /// <returns>The new item.</returns>
        internal static NefsItem CreateItem(
            uint id,
            uint dirId,
            string fileName,
            UInt64 dataOffset,
            UInt32 extractedSize,
            IReadOnlyList <UInt32> chunkSizes,
            NefsItemType type)
        {
            var size       = new NefsItemSize(extractedSize, chunkSizes);
            var dataSource = new NefsFileDataSource(@"C:\source.txt", dataOffset, size, extractedSize != chunkSizes.LastOrDefault());

            return(new NefsItem(
                       new NefsItemId(id),
                       fileName,
                       new NefsItemId(dirId),
                       type,
                       dataSource,
                       CreateUnknownData()));
        }
Beispiel #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NefsItem"/> class.
        /// </summary>
        /// <param name="id">The item id (index).</param>
        /// <param name="fileName">The file name within the archive.</param>
        /// <param name="directoryId">The directory id the item is in.</param>
        /// <param name="type">The type of item.</param>
        /// <param name="dataSource">The data source for the item's data.</param>
        /// <param name="unknownData">Unknown metadata.</param>
        /// <param name="state">The item state.</param>
        public NefsItem(
            NefsItemId id,
            string fileName,
            NefsItemId directoryId,
            NefsItemType type,
            INefsDataSource dataSource,
            NefsItemUnknownData unknownData,
            NefsItemState state = NefsItemState.None)
        {
            this.Id          = id;
            this.DirectoryId = directoryId;
            this.Type        = type;
            this.DataSource  = dataSource ?? throw new ArgumentNullException(nameof(dataSource));
            this.State       = state;

            // Unknown data
            this.Part6Unknown0x00 = unknownData.Part6Unknown0x00;
            this.Part6Unknown0x01 = unknownData.Part6Unknown0x01;
            this.Part6Unknown0x02 = unknownData.Part6Unknown0x02;
            this.Part6Unknown0x03 = unknownData.Part6Unknown0x03;

            // Save file name
            this.FileName = fileName ?? throw new ArgumentNullException(nameof(fileName));
        }
Beispiel #4
0
        /// <summary>
        /// Loads a NeFS item with the specified id from the archive.
        /// </summary>
        /// <param name="file">The file stream to load from.</param>
        /// <param name="archive">The NeFS archive this item is in.</param>
        /// <param name="id">The id of the item in the archive to load.</param>
        public NefsItem(FileStream file, NefsArchive archive, UInt32 id)
        {
            /* Validate inputs */
            if (file == null)
            {
                throw new ArgumentNullException("File stream required to load NeFS item.");
            }

            if (archive == null)
            {
                throw new ArgumentNullException("NeFS archive object required to load an item.");
            }

            _archive = archive;
            _id      = id;

            /* Get header entries related to this item */
            _pt1Entry = archive.Header.Part1.GetEntry(id);
            _pt2Entry = archive.Header.Part2.GetEntry(_pt1Entry);
            _pt5Entry = archive.Header.Part5.GetEntry(id);
            try
            {
                _pt6Entry = archive.Header.Part6.GetEntry(id);
            }
            catch (Exception ex)
            {
                try
                {
                    /* Some items share a part 2 entry, so try to find the corresponding part 6 entry */
                    _pt6Entry = archive.Header.Part6.GetEntry(_pt2Entry.Id);
                }
                catch (Exception ex2)
                {
                    // TODO : Handle when an item doesn't have a part 6 entry
                    _pt6Entry = archive.Header.Part6.GetEntry(0);
                }
            }

            /* Determine item type */
            _type = (_pt1Entry.OffsetToData == 0)
                ? NefsItemType.Directory
                : NefsItemType.File;

            /* Get the filename */
            _fileName = archive.Header.Part3.GetFilename(_pt2Entry.FilenameOffset);

            /* Hash the filename */
            _fileNameHash = FilePathHelper.HashStringMD5(_fileName);

            /* Get offsets */
            _dataOffset       = _pt1Entry.OffsetToData;
            _offsetIntoPt2Raw = _pt1Entry.OffsetIntoPt2Raw;
            _offsetIntoPt4Raw = _pt1Entry.OffsetIntoPt4Raw;

            /* Get extracted size */
            _extractedSize = _pt2Entry.ExtractedSize;

            /*
             * Build the file path inside this archive
             * for example: "rootDir/childDir/file.xml".
             */
            _filePathInArchive = _fileName;
            var currentItem = _pt2Entry;

            /* The root directory's id is equal to its parent directory id */
            while (currentItem.Id != currentItem.DirectoryId)
            {
                var pt1Entry = archive.Header.Part1.GetEntry(currentItem.DirectoryId);
                var dir      = archive.Header.Part2.GetEntry(pt1Entry);
                var dirName  = archive.Header.Part3.GetFilename(dir.FilenameOffset);
                _filePathInArchive = Path.Combine(dirName, _filePathInArchive);

                currentItem = dir;
            }

            /* Hash the file path in archive */
            _filePathInArchiveHash = FilePathHelper.HashStringMD5(_filePathInArchive);

            //
            // Get the compressed file chunk offsets
            //
            if (_pt1Entry.OffsetIntoPt4Raw == 0xFFFFFFFF)
            {
                // TODO : Not sure exactly what this value means yet
                // For now, just set compressed size as extracted size with not compressed chunk sizes
                _compressedSize = ExtractedSize;
            }
            else
            {
                var numChunks = (UInt32)Math.Ceiling(ExtractedSize / (double)CHUNK_SIZE);
                if (numChunks > 0)
                {
                    var        firstChunkSizeEntry = _archive.Header.Part4.Offset + _pt1Entry.OffsetIntoPt4;
                    UInt32Type chunkOffset;

                    for (int i = 0; i < numChunks; i++)
                    {
                        chunkOffset = new UInt32Type(i * 4);
                        chunkOffset.Read(file, firstChunkSizeEntry);
                        _chunkSizes.Add(chunkOffset.Value);
                    }

                    _compressedSize = _chunkSizes.Last();
                }
            }
        }