//public IEnumerator GetEnumerator() { // foreach (object o in Nodes.Values.ToList()) { // if (o == null) { // break; // } // yield return o; // } // } #endregion "Accessors" /// <summary> /// Creates a virtual node to display, linking 'up' a level in the tree /// </summary> /// <param name="current">Current <PRTableNode>PRTableNode</PRTableNode> from which to generate the virtual 'up' node</param> /// <returns><PRTableNode>PRTableNode</PRTableNode></returns> public PRTableNode GetVirtualUpNode(PRTableNode current) { PRTableNode virtualUP = PRTableNode.CreateUp(new PRNode("Up", Guid.Empty)); virtualUP.GUID = GetPPGuid(current.GUID); virtualUP.Name = Utils.StringToBase("Up"); virtualUP.Node.Flags = NodeFlag.Directory; return(virtualUP); }
/// <summary> /// Adds an orphan <PRTableNode><PRTableNode></PRTableNode> to the FileTable /// </summary> /// <param name="node">PRTableNode to insert</param> /// <returns><ErrCode>ErrCode</ErrCode></returns> public ErrCode Add(PRTableNode node) { //Log($"Adding PRTNode {node.Name}", LogType.Info); if (Nodes.Values.Contains(node)) { return(ErrCode.APP_DUPLICATE_NODE); } else { Nodes.Add(node.GUID, node); return(ErrCode.SUCCESS); } }
/// <summary> /// Extract specified PRNode to specified file/path /// </summary> /// <param name="node">Node to extract</param> /// <param name="path"></param> /// <returns><errcode>Result</errcode></returns> private ErrCode ExFile(PRNode node, DirectoryInfo path, ProgressTracker pt, string altName = "") { Log($"Creating streams for IO ..", LogType.Init); PRTableNode prt = node.TableNode; string fName = altName == "" ? prt.DisplayName : altName; FileStream output = new FileStream(Path.Combine(path.FullName, fName), FileMode.Create); BinaryWriter bw = new BinaryWriter(output); PRXSwapFile.Seek(prt.Offset, 0); // create a hash algorithm to be used in the while(read) loop HashAlgorithm hasher = new MD5CryptoServiceProvider(); long bytesRead; long tbr = 0; long bytesToRead = prt.SizeUncompressed; var buffer = new byte[Utils.IO_BUFFER_SIZE]; Log($"Writing data..", LogType.IO); long bytesSoFar = 0; while (bytesToRead > 0) { long bytesLeft = prt.SizeUncompressed - bytesSoFar; long bufSize = bytesToRead > Utils.IO_BUFFER_SIZE ? Utils.IO_BUFFER_SIZE : bytesLeft; bytesRead = PRXSwapFile.Read(buffer, 0, (int)bufSize); bytesSoFar += bytesRead; hasher.TransformBlock(buffer, 0, (int)bufSize, null, 0); bytesToRead -= bytesRead; tbr += bytesRead; bw.Write(buffer, 0, (int)bytesRead); } hasher.TransformFinalBlock(new byte[0], 0, 0); byte[] hash = hasher.Hash; if (HashToHex(hash) == prt.Hash) { Log($"Ex OK [{prt.HashString}]", LogType.Info); pt[node] = ErrCode.SUCCESS; return(ErrCode.SUCCESS); } else { Log($"Fail! [{prt.Hash}]", LogType.Critical); pt[node] = ErrCode.APP_FAIL_HASH; return(ErrCode.APP_FAIL_HASH); } }
/// <summary> /// Initializes the MasterFileTable and instantiates a virtual 'root' from which all nodes are descended /// </summary> public PRTable() { Log("MasterFileTable initialize and set virtual toplevel node", LogType.FTable); Nodes = new Dictionary <Guid, PRTableNode>(); PRTableNode prt = PRTableNode.CreateUp(RootNode); Encoding enc = System.Text.Encoding.UTF8; prt.GUID = RootNode.GUID; prt.Parent = RootNode.GUID; prt.DateCreated = 0; prt.DateModified = 0; prt.Attribs = Attrib.Root; prt.NameLength = Convert.ToBase64String(enc.GetBytes("/")).Length; prt.Name = Convert.ToBase64String(enc.GetBytes("/")); Nodes.Add(prt.GUID, prt); }
/// <summary> /// Add a file to the prx archive beneath specified node /// </summary> /// <param name="file">File to be added</param> /// <param name="parent">Parent node of added file</param> /// <returns><errcode>Result</errcode></returns> private ErrCode AddFile(string file, ProgressTracker progress, PRNode parent) { ErrCode err = ErrCode.NULL; if (!File.Exists(file)) { err = ErrCode.APP_FAIL_TO_READ; return(err); } // forcefully demand read access to the target file, returning ErrCode.EX_ACCESS_DENIED if this fails try { new FileIOPermission(FileIOPermissionAccess.Read, file).Demand(); } catch (SecurityException se) { err = ErrCode.EX_ACCESS_DENIED; return(MapExceptionName(se)); } catch (NullReferenceException ex) { Log($"Ex: {MapExceptionName(ex)}", LogType.Error); } long startOfWrite = 0; FileInfo fi = new FileInfo(file); PRNode node = new PRNode(fi.Name, parent.GUID); PRTableNode prtn = new PRTableNode(fi, node, fi.Name, parent.GUID); FileStream fs = null; node.AssignTableNode(prtn); //TODO Refactor this to a BinaryWriter extension: BinaryWriter.Write(PRNode) try { BinaryWriter bw = new BinaryWriter(PRXSwapFile); fs = new FileStream(fi.FullName, FileMode.Open); // jump to the end of the swap file bw.Seek(0, SeekOrigin.End); startOfWrite = bw.BaseStream.Position; node.TableNode.SizeUncompressed = fi.Length; // write the data header bw.Write(node.GUID.ToByteArray()); bw.Write(new string('X', 16)); // we write a spacer for the hash that'll be inserted after we actually parse the data bw.Write((ulong)fi.Length); long dataOffset = bw.BaseStream.Position; node.TableNode.Offset = (long)dataOffset; // create a hash algorithm to be used in the while(read) loop HashAlgorithm hasher = new MD5CryptoServiceProvider(); int bytesRead; var buffer = new byte[Utils.IO_BUFFER_SIZE]; progress.BytesProcessedInFile = 0; progress.TotalBytesInFile = fi.Length; while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0) { progress.BytesProcessed += bytesRead; progress.BytesProcessedInFile += bytesRead; //TODO encrypt/compress data [optional] bw.Write(buffer, 0, bytesRead); hasher.TransformBlock(buffer, 0, bytesRead, null, 0); ProgressReport(progress); } hasher.TransformFinalBlock(new byte[0], 0, 0); byte[] hash = hasher.Hash; prtn.Hash = HashToHex(hash); PRXSwapFile.Seek(dataOffset - 24, SeekOrigin.Begin); //bw.Seek(dataOffset - 24, SeekOrigin.Begin); PRXSwapFile.Write(hash, 0, hash.Length); //bw.Write(hash); //Log($"Wrote {progress.BytesProcessedInFile}b [{prtn.HashString}] at offset: {dataOffset}, EOD: {bw.BaseStream.Position}", LogType.IO); // move back to the end of the stream just for safety bw.Seek(0, SeekOrigin.End); PRXSwapFile.Seek(0, SeekOrigin.End); //BUG Not properly inserting all files anymore.. WTF //INFO Have to close the BinaryWriter without colosing the underlying stream.. F**K. //bw.Dispose(); // supposedly the binarywriter is closed *WITHOUT* nuking PRXSwapFile.. } catch (Exception ex) { //TODO remove whatever may have been written in the event of a failure // this'll be added at a later date when I'm able to produce an error //Log($"EX: {MapExceptionName(ex)} on {fi.Name} in {fi.DirectoryName}", LogType.Exception); return(MapExceptionName(ex)); } finally { fs.Dispose(); //GC.Collect(1); //Cardinal sin, I know.. But I can't dispose of the binarywriter, has to be collected so it won't close PRXSwapFile } // increment the number of files processed in our tracker progress.FilesProcessed++; // finally, if and only if this is ErrCode.SUCCESS- add the node as a TableNode to our FileTable if (err == ErrCode.NULL) { FileTable.Add(prtn); } return(ErrCode.SUCCESS); }
/// <summary> /// Adds a directory entry to the archive /// </summary> /// <param name="dir">Directory to be added</param> /// <param name="progress">ProgressTracker</param> /// <param name="parent">Parent node of which this node belongs</param> /// <returns>ErrCode</returns> private PRNode AddDirectory(DirectoryInfo di, ProgressTracker progress, PRNode parent) { PRNode retVal = new PRNode(di, parent.GUID); PRTableNode prtn = new PRTableNode(di, retVal, di.Name, parent.GUID); FileTable.Add(prtn); //BUG Directories aren't actually written to the archive, dumbass. #region failure //long startOfWrite = 0; //retVal.AssignTableNode(prtn); //try { // BinaryWriter bw = new BinaryWriter(PRXSwapFile); // bw.Seek(0, SeekOrigin.End); // startOfWrite = bw.BaseStream.Position; // bw.Write(retVal.GUID.ToByteArray()); // bw.Write(new string('X', 16)); // we write a spacer for the hash that'll be inserted after we actually parse the data // bw.Write((short)retVal.TableNode.DisplayName.Length); // long dataOffset = bw.BaseStream.Position; // retVal.TableNode.Offset = (long)dataOffset; // // create a hash algorithm to be used in the while(read) loop // HashAlgorithm hasher = new MD5CryptoServiceProvider(); // int bytesRead; // var buffer = new byte[Utils.IO_BUFFER_SIZE]; // progress.BytesProcessedInFile = 0; // progress.TotalBytesInFile = fi.Length; // while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0) { // progress.BytesProcessed += bytesRead; // progress.BytesProcessedInFile += bytesRead; // //TODO encrypt/compress data [optional] // bw.Write(buffer, 0, bytesRead); // hasher.TransformBlock(buffer, 0, bytesRead, null, 0); // ProgressReport(progress); // } // hasher.TransformFinalBlock(new byte[0], 0, 0); // byte[] hash = hasher.Hash; // prtn.Hash = HashToHex(hash); // PRXSwapFile.Seek(dataOffset - 24, SeekOrigin.Begin); // //bw.Seek(dataOffset - 24, SeekOrigin.Begin); // PRXSwapFile.Write(hash, 0, hash.Length); // //bw.Write(hash); // //Log($"Wrote {progress.BytesProcessedInFile}b [{prtn.HashString}] at offset: {dataOffset}, EOD: {bw.BaseStream.Position}", LogType.IO); // // move back to the end of the stream just for safety // bw.Seek(0, SeekOrigin.End); // PRXSwapFile.Seek(0, SeekOrigin.End); // //BUG Not properly inserting all files anymore.. WTF // //INFO Have to close the BinaryWriter without colosing the underlying stream.. F**K. // //bw.Dispose(); // // supposedly the binarywriter is closed *WITHOUT* nuking PRXSwapFile.. // } //catch (Exception ex) { // //TODO remove whatever may have been written in the event of a failure // // this'll be added at a later date when I'm able to produce an error // //Log($"EX: {MapExceptionName(ex)} on {fi.Name} in {fi.DirectoryName}", LogType.Exception); // return MapExceptionName(ex); // } //finally { // fs.Dispose(); // //GC.Collect(1); //Cardinal sin, I know.. But I can't dispose of the binarywriter, has to be collected so it won't close PRXSwapFile // } #endregion failure return(retVal); }
public ErrCode AssignTableNode(PRTableNode prtn) { this._TableNode = prtn; return(ErrCode.SUCCESS); }
/// <summary> /// Creates a virtual UP table node for navigation purposes /// </summary> /// <param name="n">Virual PRNode from which to base this</param> /// <returns>Virtual PRTableNode (that doesn't exist in the file table)</returns> public static PRTableNode CreateUp(PRNode n) { PRTableNode prtn = new PRTableNode(n); return(prtn); }