public Archive(MerkleTree tree, BigInteger size, ArchiveFlags flags, byte[] key) { this.MerkleTree = tree; this.Size = size; this.Flags = flags; this.Key = key; }
public void Open(string archivePathName, OpenMode openMode) { IntPtr zero = IntPtr.Zero; if (archiveHandle != IntPtr.Zero) { Close(); } ArchivePathName = archivePathName; RAROpenArchiveDataEx archiveData = default(RAROpenArchiveDataEx); archiveData.Initialize(); archiveData.ArcName = this.archivePathName + "\0"; archiveData.ArcNameW = this.archivePathName + "\0"; archiveData.OpenMode = (uint)openMode; if (retrieveComment) { archiveData.CmtBuf = new string('\0', 65536); archiveData.CmtBufSize = 65536u; } else { archiveData.CmtBuf = null; archiveData.CmtBufSize = 0u; } zero = RAROpenArchiveEx(ref archiveData); if (archiveData.OpenResult != 0) { switch (archiveData.OpenResult) { case 11u: throw new OutOfMemoryException("Insufficient memory to perform operation."); break; case 12u: throw new IOException("Archive header broken"); break; case 13u: throw new IOException("File is not a valid archive."); break; case 15u: throw new IOException("File could not be opened."); break; } } archiveHandle = zero; archiveFlags = (ArchiveFlags)archiveData.Flags; RARSetCallback(archiveHandle, callback, GetHashCode()); if (archiveData.CmtState == 1) { comment = archiveData.CmtBuf.ToString(); } if (password.Length != 0) { RARSetPassword(archiveHandle, password); } OnNewVolume(this.archivePathName); }
public Archive CreateArchive(MerkleTree merkleTree, ArchiveFlags flags) { var archive = FindArchive(merkleTree.Root); if (archive != null) { return(archive); } throw new NotImplementedException(); }
public void Open(string archivePathName, OpenMode openMode) { IntPtr zero = IntPtr.Zero; if (this.archiveHandle != IntPtr.Zero) { this.Close(); } this.ArchivePathName = archivePathName; RAROpenArchiveDataEx archiveData = new RAROpenArchiveDataEx(); archiveData.Initialize(); archiveData.ArcName = this.archivePathName + "\0"; archiveData.ArcNameW = this.archivePathName + "\0"; archiveData.OpenMode = (uint)openMode; if (this.retrieveComment) { archiveData.CmtBuf = new string('\0', 0x10000); archiveData.CmtBufSize = 0x10000; } else { archiveData.CmtBuf = null; archiveData.CmtBufSize = 0; } zero = RAROpenArchiveEx(ref archiveData); switch (archiveData.OpenResult) { case 11: throw new OutOfMemoryException("Insufficient memory to perform operation."); case 12: throw new IOException("Archive header broken"); case 13: throw new IOException("File is not a valid archive."); case 15: throw new IOException("File could not be opened."); } this.archiveHandle = zero; this.archiveFlags = (ArchiveFlags)archiveData.Flags; RARSetCallback(this.archiveHandle, this.callback, this.GetHashCode()); if (archiveData.CmtState == 1) { this.comment = archiveData.CmtBuf.ToString(); } if (this.password.Length != 0) { RARSetPassword(this.archiveHandle, this.password); } this.OnNewVolume(this.archivePathName); }
public Header(CompressionType compression = CompressionType.zlib, uint dataOffset = 0, uint tocEntrySize = 0x20, uint numFiles = 0, uint maxBlockSize = (1 << 16), ArchiveFlags flags = ArchiveFlags.Relative ) { this.magic = MAGIC; this.version = VERSION; this.compression = compression; this.dataOffset = dataOffset; this.tocEntrySize = tocEntrySize; this.numFiles = numFiles; this.maxBlockSize = maxBlockSize; this.flags = flags; }
public Archive CreateArchive(MerkleTree merkleTree, BigInteger size, ArchiveFlags flags, byte[] key) { var archive = FindArchive(merkleTree.Root); if (archive != null) { return(archive); } archive = new Archive(merkleTree, size, flags, key); var archiveHash = merkleTree.Root; _archiveEntries.Set(archiveHash, archive); return(archive); }
public Header(byte[] bytes, int bytesOffset = 0) { fileId = Encoding.UTF8.GetString(bytes, bytesOffset + 0, 4); version = BitConverter.ToUInt32(bytes, bytesOffset + 4); if (fileId != "BSA\0" || version != 105) { throw new Exception("Unsupported BSA Version or ID!"); } offset = BitConverter.ToUInt32(bytes, bytesOffset + 8); archiveFlags = (ArchiveFlags)BitConverter.ToUInt32(bytes, bytesOffset + 12); folderCount = BitConverter.ToUInt32(bytes, bytesOffset + 16); fileCount = BitConverter.ToUInt32(bytes, bytesOffset + 20); totalFolderNameLength = BitConverter.ToUInt32(bytes, bytesOffset + 24); totalFileNameLength = BitConverter.ToUInt32(bytes, bytesOffset + 28); fileFlags = (FileFlags)BitConverter.ToUInt32(bytes, bytesOffset + 32); }
/// <summary> /// Creates a new BSAReader instance from a path. /// </summary> /// <param name="path">Path to the .bsa file.</param> /// <exception cref="ArgumentException">The file does not exist.</exception> /// <exception cref="InvalidDataException">File is not a BSA archive.</exception> /// <exception cref="NotSupportedException">BSA archive is not for TES4.</exception> public BSAReader(string path) { if (!File.Exists(path)) { throw new ArgumentException("File does not exist!", nameof(path)); } var fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read); _br = new BinaryReader(fs, Encoding.UTF8); var magic = Encoding.ASCII.GetString(_br.ReadBytes(4)); if (magic != "BSA\0") { throw new InvalidDataException($"Archive at {path} is not a BSA!"); } HeaderType = (VersionType)_br.ReadUInt32(); if (HeaderType != VersionType.TES4) { throw new NotSupportedException($"OMODFramework only supports TES4 BSAs not {HeaderType}"); } _folderRecordOffset = _br.ReadUInt32(); ArchiveFlags = (ArchiveFlags)_br.ReadUInt32(); _folderCount = _br.ReadUInt32(); _fileCount = _br.ReadUInt32(); _totalFolderNameLength = _br.ReadUInt32(); _totalFileNameLength = _br.ReadUInt32(); FileFlags = (FileFlags)_br.ReadUInt32(); Folders = GetFolders(_br).ToList(); Files = new List <BSAFileInfo>(); foreach (var folder in Folders) { if (HasFolderNames) { folder.Name = new string(_br.ReadChars(_br.ReadByte())[..^ 1]);
internal static IEnumerable <RarVolume> GetParts(FileInfo fileInfo, string password, Options options) { FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, password, options); yield return(part); ArchiveFlags af = part.ArchiveHeader.ArchiveHeaderFlags; if (!af_HasFlag(af, ArchiveFlags.VOLUME)) { yield break; //if file isn't volume then there is no reason to look } ArchiveHeader ah = part.ArchiveHeader; fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault <RarFilePart>() as FileInfoRarFilePart); //we use fileinfo because rar is dumb and looks at file names rather than archive info for another volume while (fileInfo != null && fileInfo.Exists) { part = new FileInfoRarArchiveVolume(fileInfo, password, options); fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault <RarFilePart>() as FileInfoRarFilePart); yield return(part); } }
private static bool af_HasFlag(ArchiveFlags archiveFlags, ArchiveFlags archiveFlags2) { return((archiveFlags & archiveFlags2) == archiveFlags2); }
public bool CreateArchive(MerkleTree merkleTree, BigInteger size, ArchiveFlags flags, byte[] key) { return(Nexus.CreateArchive(this.RootStorage, merkleTree, size, flags, key)); }
public void UploadFile(Address sender, Address target, string fileName, BigInteger fileSize, byte[] contentMerkle, ArchiveFlags flags, byte[] key) { Runtime.Expect(Runtime.IsWitness(sender), "invalid witness"); Runtime.Expect(target.IsUser, "destination address must be user address"); Runtime.Expect(fileSize >= DomainSettings.ArchiveMinSize, "file too small"); Runtime.Expect(fileSize <= DomainSettings.ArchiveMaxSize, "file too big"); BigInteger requiredSize = CalculateRequiredSize(fileName, fileSize); var targetUsedSize = GetUsedSpace(target); var targetStakedAmount = Runtime.GetStake(target); var targetAvailableSize = CalculateStorageSizeForStake(targetStakedAmount); targetAvailableSize -= targetUsedSize; if (sender == target) { Runtime.Expect(targetAvailableSize >= requiredSize, "target account does not have available space"); } else // otherwise we need to run some extra checks in case the sender is not the target { var foreignSpace = GetForeignSpace(target); if (foreignSpace < targetAvailableSize) { targetAvailableSize = foreignSpace; // limit available space to max allocated space to foreign addresses } Runtime.Expect(targetAvailableSize >= requiredSize, "target account does not have available space"); if (sender.IsUser) { // note that here we require sender to have at least free space equal to msg size, mostly a protection against spam var senderUsedSize = GetUsedSpace(sender); var senderStakedAmount = Runtime.GetStake(sender); var senderAvailableSize = CalculateStorageSizeForStake(senderStakedAmount); senderAvailableSize -= senderUsedSize; Runtime.Expect(senderAvailableSize >= requiredSize, "sender account does not have available space"); } else { Runtime.Expect(sender.IsSystem, "invalid address type for sender"); } } var hashes = MerkleTree.FromBytes(contentMerkle); Runtime.CreateArchive(sender, target, hashes, fileSize, flags, key); var newEntry = new StorageEntry() { Name = fileName, Hash = hashes.Root, Creator = sender, }; var list = _storageMap.Get <Address, StorageList>(target); list.Add <StorageEntry>(newEntry); Runtime.Notify(EventKind.FileCreate, target, newEntry); }
private bool ArchiveHeaderFlags_HasFlag(ArchiveFlags archiveFlags) { return((this.ArchiveHeaderFlags & archiveFlags) == archiveFlags); }
private bool ArchiveHeader_HasFlag(ArchiveFlags ahf, ArchiveFlags archiveFlags) { return((ahf & archiveFlags) == archiveFlags); }
// this is an helper method to upload smaller files... public void UploadData(Address sender, Address target, string fileName, byte[] data, ArchiveFlags flags, byte[] key) { BigInteger fileSize = data.Length; Runtime.Expect(fileSize <= MerkleTree.ChunkSize, "data too big"); var merkle = new MerkleTree(data); var serializedMerkle = Serialization.Serialize(merkle); UploadFile(sender, target, fileName, fileSize, serializedMerkle, flags, key); var archive = Runtime.CreateArchive(sender, target, merkle, fileSize, flags, key); Runtime.Expect(archive != null, "failed to create archive"); Runtime.Expect(Runtime.WriteArchive(archive, 0, data), "failed to write archive content"); }
private bool ArchiveHeader_HasFlag(ArchiveFlags ahf, ArchiveFlags archiveFlags) { return (ahf&archiveFlags)==archiveFlags; }
/// <summary> /// Opens specified archive using the specified mode. /// </summary> /// <param name="archivePathName">Path of archive to open</param> /// <param name="openMode">Mode in which to open archive</param> public void Open(string archivePathName, OpenMode openMode) { IntPtr handle = IntPtr.Zero; // Close any previously open archives if (this.archiveHandle != IntPtr.Zero) { this.Close(); } // Prepare extended open archive struct this.ArchivePathName = archivePathName; RAROpenArchiveDataEx openStruct = new RAROpenArchiveDataEx(); openStruct.Initialize(); openStruct.ArcName = this.archivePathName + "\0"; openStruct.ArcNameW = this.archivePathName + "\0"; openStruct.OpenMode = (uint)openMode; if (this.retrieveComment) { openStruct.CmtBuf = new string((char)0, 65536); openStruct.CmtBufSize = 65536; } else { openStruct.CmtBuf = null; openStruct.CmtBufSize = 0; } // Open archive handle = Unrar.RAROpenArchiveEx(ref openStruct); // Check for success if (openStruct.OpenResult != 0) { switch ((RarError)openStruct.OpenResult) { case RarError.InsufficientMemory: throw new OutOfMemoryException("Insufficient memory to perform operation."); case RarError.BadData: throw new IOException("Archive header broken"); case RarError.BadArchive: throw new IOException("File is not a valid archive."); case RarError.OpenError: throw new IOException("File could not be opened."); } } // Save handle and flags this.archiveHandle = handle; this.archiveFlags = (ArchiveFlags)openStruct.Flags; // Set callback Unrar.RARSetCallback(this.archiveHandle, this.callback, this.GetHashCode()); // If comment retrieved, save it if (openStruct.CmtState == 1) { this.comment = openStruct.CmtBuf.ToString(); } // If password supplied, set it if (this.password.Length != 0) { Unrar.RARSetPassword(this.archiveHandle, this.password); } // Fire NewVolume event for first volume this.OnNewVolume(this.archivePathName); }
public void CreateArchive(Address from, MerkleTree merkleTree, BigInteger size, ArchiveFlags flags, byte[] key) { // TODO validation Nexus.CreateArchive(this.RootStorage, merkleTree, size, flags, key); }
protected override void DoOpen() { using (CustomBinaryReader reader = new CustomBinaryReader(new FileStream(ArchivePath, FileMode.Open, FileAccess.Read))) { uint signature = reader.ReadUInt32(); if (signature != 0x415342) { throw new InvalidDataException("File is not BSA"); } uint version = reader.ReadUInt32(); uint folderOffset = reader.ReadUInt32(); flags = (ArchiveFlags)reader.ReadUInt32(); uint folderCount = reader.ReadUInt32(); uint fileCount = reader.ReadUInt32(); uint totalFolderNameLength = reader.ReadUInt32(); uint totalFileNameLength = reader.ReadUInt32(); uint fileExtensions = reader.ReadUInt32(); FolderInfo[] folders = new FolderInfo[(int)folderCount]; // Read folders reader.BaseStream.Position = folderOffset; for (int i = 0; i < folderCount; i++) { ulong hash = reader.ReadUInt64(); uint count = reader.ReadUInt32(); uint offset = reader.ReadUInt32() - totalFileNameLength; folders[i] = new FolderInfo() { FileCount = count, ContentOffset = offset }; } // Read folder content (name and files) foreach (var folder in folders) { byte folderNameLength = reader.ReadByte(); folder.Path = Encoding.UTF8.GetString(reader.ReadBytes(folderNameLength - 1)); byte zero = reader.ReadByte(); folder.Files = new FileInfo[folder.FileCount]; for (int i = 0; i < folder.FileCount; i++) { ulong hash = reader.ReadUInt64(); uint size = reader.ReadUInt32(); bool compressed = flags.HasFlag(ArchiveFlags.DefaultCompressed); if ((size & 0xf0000000) != 0) { size &= 0xfffffff; compressed = !compressed; } uint offset = reader.ReadUInt32(); folder.Files[i] = new FileInfo() { Size = size, DataOffset = offset, IsCompressed = compressed }; } } long total = fileCount; long loaded = 0; string filename = Path.GetFileName(ArchivePath); // Read file names foreach (var folder in folders) { foreach (var file in folder.Files) { file.Filename = reader.ReadStringZeroTerminated(); loaded++; } } // Convert to nested sorted dictionary for fast search for (int i = 0; i < folderCount; i++) { var files = new SortedDictionary<string, FileInfo>(); for (int j = 0; j < folders[i].FileCount; j++) { files.Add(folders[i].Files[j].Filename, folders[i].Files[j]); } sorted.Add(folders[i].Path, files); } return; } }
protected override void DoOpen() { using (CustomBinaryReader reader = new CustomBinaryReader(new FileStream(ArchivePath, FileMode.Open, FileAccess.Read))) { uint signature = reader.ReadUInt32(); if (signature != 0x415342) { throw new InvalidDataException("File is not BSA"); } uint version = reader.ReadUInt32(); uint folderOffset = reader.ReadUInt32(); flags = (ArchiveFlags)reader.ReadUInt32(); uint folderCount = reader.ReadUInt32(); uint fileCount = reader.ReadUInt32(); uint totalFolderNameLength = reader.ReadUInt32(); uint totalFileNameLength = reader.ReadUInt32(); uint fileExtensions = reader.ReadUInt32(); FolderInfo[] folders = new FolderInfo[(int)folderCount]; // Read folders reader.BaseStream.Position = folderOffset; for (int i = 0; i < folderCount; i++) { ulong hash = reader.ReadUInt64(); uint count = reader.ReadUInt32(); uint unknown = reader.ReadUInt32(); ulong offset = reader.ReadUInt64() - totalFileNameLength; folders[i] = new FolderInfo() { FileCount = count, ContentOffset = offset }; } // Read folder content (name and files) foreach (var folder in folders) { byte folderNameLength = reader.ReadByte(); folder.Path = Encoding.UTF8.GetString(reader.ReadBytes(folderNameLength - 1)); byte zero = reader.ReadByte(); folder.Files = new FileInfo[folder.FileCount]; for (ulong i = 0; i < folder.FileCount; i++) { ulong hash = reader.ReadUInt64(); uint size = reader.ReadUInt32(); bool compressed = flags.HasFlag(ArchiveFlags.DefaultCompressed); if ((size & 0xf0000000) != 0) { size &= 0xfffffff; compressed = !compressed; } uint offset = reader.ReadUInt32(); folder.Files[i] = new FileInfo() { Size = size, DataOffset = offset, IsCompressed = compressed }; } } long total = fileCount; long loaded = 0; string filename = Path.GetFileName(ArchivePath); // Read file names foreach (var folder in folders) { foreach (var file in folder.Files) { file.Filename = reader.ReadStringZeroTerminated(); loaded++; } } // Convert to nested sorted dictionary for fast search for (int i = 0; i < folderCount; i++) { var files = new SortedDictionary <string, FileInfo>(); for (ulong j = 0; j < folders[i].FileCount; j++) { files.Add(folders[i].Files[j].Filename, folders[i].Files[j]); } sorted.Add(folders[i].Path, files); } return; } }
public void UploadFile(Address from, string name, BigInteger contentSize, byte[] contentMerkle, ArchiveFlags flags, byte[] key) { Runtime.Expect(Runtime.IsWitness(from), "invalid witness"); Runtime.Expect(from.IsUser, "address must be user address"); Runtime.Expect(contentSize >= DomainSettings.ArchiveMinSize, "file too small"); Runtime.Expect(contentSize <= DomainSettings.ArchiveMaxSize, "file too big"); BigInteger requiredSize = CalculateRequiredSize(name, contentSize); var usedSize = GetUsedSpace(from); var stakedAmount = Runtime.GetStake(from); var availableSize = CalculateStorageSizeForStake(stakedAmount); availableSize -= usedSize; Runtime.Expect(availableSize >= requiredSize, "account does not have available space"); var hashes = MerkleTree.FromBytes(contentMerkle); Runtime.CreateArchive(from, hashes, contentSize, flags, key); var newEntry = new StorageEntry() { Name = name, hash = hashes.Root, }; var list = _storageMap.Get <Address, StorageList>(from); list.Add <StorageEntry>(newEntry); Runtime.Notify(EventKind.FileCreate, from, name); }
private bool ArchiveHeaderFlags_HasFlag(ArchiveFlags archiveFlags) { return ((this.ArchiveHeaderFlags & archiveFlags) == archiveFlags); }
private static bool af_HasFlag(ArchiveFlags archiveFlags, ArchiveFlags archiveFlags2) { return ((archiveFlags & archiveFlags2) == archiveFlags2); }
public static void Create(System.IO.Stream output, IEnumerable <ArchiveCreateEntry> files, ArchiveFlags flags, CompressType compress, Action <double, string> onProgress) { if (!files.Any()) { throw new IrosArcException("Can't create an archive that contains no files"); } var sw = new System.Diagnostics.Stopwatch(); sw.Start(); double total = files.Count() + 2; int count = 0; onProgress(count / total, ""); ArcHeader h = new ArcHeader() { Flags = flags, Version = MAX_VERSION, Directory = 16 }; List <DirectoryEntry> entries = files.Select(f => new DirectoryEntry() { Filename = f.Filename, Flags = 0, }).ToList(); int dsize = entries.Select(e => (int)e.GetSize()).Sum(); h.Save(output); output.WriteInt(entries.Count); long position = h.Directory + dsize + 4; onProgress(++count / total, "Wrote header"); int index = 0; var combined = entries.Zip(files, (d, e) => new { Dir = d, ACE = e }).ToList(); var cw = new CompressWork() { Input = new System.Collections.Concurrent.ConcurrentBag <CompressEntry>(), Compressed = new System.Collections.Concurrent.BlockingCollection <CompressEntry>(8), Compress = compress }; foreach (var comb in combined) { cw.Input.Add(new CompressEntry() { ACE = comb.ACE, Dir = comb.Dir }); } foreach (int _ in Enumerable.Range(0, 8)) { System.Threading.ThreadPool.QueueUserWorkItem(CompressWorkThread, cw); } int filesDone = 0; while (filesDone < combined.Count) { var entry = cw.Compressed.Take(); entry.Dir.Offset = position; var data = entry.DataRec.Data; if (entry.DataRec.Compressed) { entry.Dir.Flags |= FileFlags.CompressLZMA; } entry.Dir.Length = data.Length; output.Position = position; output.Write(data, 0, data.Length); position += entry.Dir.Length; onProgress(++count / total, "Written " + entry.ACE.Filename); index++; filesDone++; } output.Position = h.Directory + 4; foreach (var entry in entries) { entry.Save(output); } sw.Stop(); onProgress(++count / total, String.Format("Complete: {0} files, {1:0.0}MB in {2} seconds", entries.Count, output.Length / (1024f * 1024f), sw.Elapsed.TotalSeconds)); }
/// <summary> /// Opens specified archive using the specified mode. /// </summary> /// <param name="archivePathName">Path of archive to open</param> /// <param name="openMode">Mode in which to open archive</param> public void Open(string archivePathName, OpenMode openMode) { IntPtr handle=IntPtr.Zero; // Close any previously open archives if(this.archiveHandle!=IntPtr.Zero) this.Close(); // Prepare extended open archive struct this.ArchivePathName=archivePathName; RAROpenArchiveDataEx openStruct=new RAROpenArchiveDataEx(); openStruct.Initialize(); openStruct.ArcName=this.archivePathName+"\0"; openStruct.ArcNameW=this.archivePathName+"\0"; openStruct.OpenMode=(uint)openMode; if(this.retrieveComment) { openStruct.CmtBuf=new string((char)0,65536); openStruct.CmtBufSize=65536; } else { openStruct.CmtBuf=null; openStruct.CmtBufSize=0; } // Open archive handle=Unrar.RAROpenArchiveEx(ref openStruct); // Check for success if(openStruct.OpenResult!=0) { switch((RarError)openStruct.OpenResult) { case RarError.InsufficientMemory: throw new OutOfMemoryException("Insufficient memory to perform operation."); case RarError.BadData: throw new IOException("Archive header broken"); case RarError.BadArchive: throw new IOException("File is not a valid archive."); case RarError.OpenError: throw new IOException("File could not be opened."); } } // Save handle and flags this.archiveHandle=handle; this.archiveFlags=(ArchiveFlags)openStruct.Flags; // Set callback Unrar.RARSetCallback(this.archiveHandle, this.callback, this.GetHashCode()); // If comment retrieved, save it if(openStruct.CmtState==1) this.comment=openStruct.CmtBuf.ToString(); // If password supplied, set it if(this.password.Length!=0) Unrar.RARSetPassword(this.archiveHandle, this.password); // Fire NewVolume event for first volume this.OnNewVolume(this.archivePathName); }
public static string FlagsToString(this ArchiveFlags flags) { bool isArchiveRelative = (flags & ArchiveFlags.Absolute) == 0; return((isArchiveRelative ? $"{ArchiveFlags.Relative} | " : "") + flags.ToString().Replace(", ", " | ")); }