/// <summary>Constructs a MetainfoFile</summary> /// <param name="istream">Stream to read data from</param> public MetainfoFile(IO.Stream istream) { BEncode.Dictionary mainDictionary = (BEncode.Dictionary)BEncode.NextElement(istream); this.announceUrl = mainDictionary.GetString(new BEncode.String("announce")); if (mainDictionary.Contains("comment")) this.comment = mainDictionary.GetString("comment"); if (mainDictionary.Contains("created by")) this.createdBy = mainDictionary.GetString("created by"); if (mainDictionary.Contains("creation date")) { int creation = mainDictionary.GetInteger("creation date"); this.creationDate = new System.DateTime(1970, 1, 1, 0, 0, 0); this.creationDate = this.creationDate.AddSeconds(creation); } BEncode.Dictionary infoDictionary = mainDictionary.GetDictionary("info"); this.name = infoDictionary.GetString("name"); this.pieceLength = infoDictionary.GetInteger("piece length"); this.pieceFileName = this.name.ToLower().Replace(' ', '_'); // Get SHA digests byte[] pieces = infoDictionary.GetBytes("pieces"); int numPieces = pieces.Length / 20; this.shaDigestList.Capacity = numPieces; for (int i=0; i<numPieces; ++i) { this.shaDigestList.Add( new ByteField20(pieces, i*20) ); } // Get filenames and lengths if (infoDictionary.Contains("length")) { // one file this.fileList.Add(name); int fileLength = infoDictionary.GetInteger("length"); this.fileLengthList.Add(fileLength); this.totalSize = fileLength; } else { // multiple files - a list of dictionaries containing the filename and length BEncode.List files = infoDictionary.GetList("files"); this.fileList.Capacity = this.fileLengthList.Capacity = files.Count; this.totalSize = 0; foreach (BEncode.Dictionary fileDic in files) { BEncode.List pathList = fileDic.GetList("path"); string path = this.name + IO.Path.DirectorySeparatorChar; for (int i=0; i<pathList.Count-1; ++i) { path += pathList[i].ToString() + IO.Path.DirectorySeparatorChar; } path += pathList[ pathList.Count-1 ]; this.fileList.Add(path); int fileLength = fileDic.GetInteger("length"); this.fileLengthList.Add(fileLength); this.totalSize += fileLength; } } // calculate the SHA-1 digest of the info dictionary - this is required for the tracker protocol istream.Seek(infoDictionary.Position, IO.SeekOrigin.Begin); byte[] infoData = new byte[ infoDictionary.Length ]; istream.Read(infoData, 0, infoData.Length); this.infoDigest = ByteField20.ComputeSHAHash(infoData); }
public BitField ReadBitfieldMessage(IO.Stream stream, int length) { byte[] bitfield = new byte[ length ]; stream.Read(bitfield, 0, bitfield.Length); return new BitField(bitfield, 0, bitfield.Length); }
public static void ReceiveHandshake(IO.Stream stream, ref ByteField20 infoDigest) { // read in protocol string byte[] protocolVersionLength = new byte[1]; if ( stream.Read( protocolVersionLength, 0, protocolVersionLength.Length ) != protocolVersionLength.Length ) throw new System.Exception( "Invalid handshake protocol" ); if ( protocolVersionLength[0] != 19 ) throw new System.Exception( "Invalid handshake protocol" ); byte[] protocolBytes = new byte[ protocolVersionLength[ 0 ] ]; if ( stream.Read( protocolBytes, 0, protocolBytes.Length ) != protocolBytes.Length ) throw new System.Exception( "Invalid handshake protocol" ); string protocol = System.Text.ASCIIEncoding.ASCII.GetString(protocolBytes, 0, protocolBytes.Length); if (protocol != protocolString) throw new System.Exception( "Invalid handshake protocol" ); // 8 zeros byte[] zeroes = new byte[ 8 ]; if ( stream.Read( zeroes, 0, zeroes.Length ) != zeroes.Length ) throw new System.Exception( "Invalid handshake protocol" ); // SHA digest stream.Read(infoDigest.Data, 0, infoDigest.Data.Length); }
public static bool ReceivePeerId(IO.Stream stream, ref ByteField20 peerId) { return stream.Read(peerId.Data, 0, peerId.Data.Length) > 0; }
public void SendPiece(IO.Stream ostream, int pieceId, int begin, int length, IO.Stream istream, PeerFinishedPieceTransfer callback, object state) { SendMessageHeader(ostream, PeerMessage.Piece, 8 + length); WriteInt(ostream, pieceId); WriteInt(ostream, begin); byte[] writeData = new byte[length]; istream.Read(writeData, 0, length); object[] objs = new object[4]; objs[0] = ostream; objs[1] = callback; objs[2] = state; objs[3] = length; ostream.BeginWrite(writeData, 0, writeData.Length, new System.AsyncCallback(OnWriteFinished), (object)objs); }
/// <summary> /// Saves the stream to the torrent. /// </summary> /// <param name="pieceId">Piece index to save to</param> /// <param name="istream">Stream to read data from</param> /// <returns>True if the data saved checks out correctly with the SHA-1 digest, false otherwise. The bitfield /// property is automatically updated if true</returns> public bool SaveToFile(int pieceId, IO.Stream istream) { // it starts in this file, as it could be spread across several files keep looping till we finish int dataWritten = 0; int positionInFile = 0; int fileNum = 0; Crypto.SHA1 sha = new Crypto.SHA1CryptoServiceProvider(); WhichFileIsPieceIn(pieceId, out fileNum, out positionInFile); while (dataWritten < this.infofile.GetPieceLength(pieceId) && fileNum < this.infofile.FileCount) { int fileLength = this.infofile.GetFileLength(fileNum); int dataToWrite = System.Math.Min(fileLength - positionInFile, this.infofile.GetPieceLength(pieceId) - dataWritten); IO.FileStream fstream = new IO.FileStream(this.infofile.GetFileName(fileNum), IO.FileMode.Open); // write data to file fstream.Seek(positionInFile, IO.SeekOrigin.Begin); byte[] data = new byte[ dataToWrite ]; istream.Read(data, 0, data.Length); fstream.Write(data, 0, data.Length); dataWritten += dataToWrite; if (dataWritten >= this.infofile.GetPieceLength(pieceId)) sha.TransformFinalBlock(data, 0, data.Length); else sha.TransformBlock(data, 0, data.Length, data, 0); fstream.Close(); fileNum++; // move onto next file positionInFile = 0; } if (this.infofile.GetSHADigest(pieceId).Equals(new ByteField20(sha.Hash))) { this.piecesDownloaded.Set(pieceId, true); this.numBytesLeft -= dataWritten; if (this.PercentChanged != null) this.PercentChanged(this, this.PercentComplete); if (this.piecesDownloaded.AllTrue) Config.LogDebugMessage("Torrent finished!"); return true; } else return false; }
/// <summary>Constructs a string from the bEncoded stream</summary> /// <param name="istream">Stream to construct string from</param> public String(IO.Stream istream, int firstchar) { if (istream.CanSeek) this.position = (int)istream.Position - 1; string numstr = new string((char)firstchar, 1); while (true) { int c = istream.ReadByte(); if (c != ':') numstr += (char)c; else break; } int length = System.Int32.Parse(numstr); if (length < 0) throw new System.Exception("Invalid string length"); this.data = new byte[length]; istream.Read(this.data, 0, length); if (istream.CanSeek) this.length = (int)(istream.Position - this.position); // System.Diagnostics.Debugger.Log(0, "BEncode", "String: " + this.ToString() + "\n"); }
private void Scan(IO.TextReader input) { while (input.Peek() != -1) { char ch = (char)input.Peek(); // Scan individual tokens if (char.IsWhiteSpace(ch)) { // eat the current char and skip ahead! input.Read(); } else if (char.IsLetter(ch) || ch == '_') { // keyword or identifier Text.StringBuilder accum = new Text.StringBuilder(); while (char.IsLetter(ch) || ch == '_') { accum.Append(ch); input.Read(); if (input.Peek() == -1) { break; } else { ch = (char)input.Peek(); } } this.result.Add(accum.ToString()); } else if (ch == '"') { // string literal Text.StringBuilder accum = new Text.StringBuilder(); input.Read(); // skip the '"' if (input.Peek() == -1) { throw new System.Exception("unterminated string literal"); } while ((ch = (char)input.Peek()) != '"') { accum.Append(ch); input.Read(); if (input.Peek() == -1) { throw new System.Exception("unterminated string literal"); } } // skip the terminating " input.Read(); this.result.Add(accum); } else if (char.IsDigit(ch)) { // numeric literal Text.StringBuilder accum = new Text.StringBuilder(); while (char.IsDigit(ch)) { accum.Append(ch); input.Read(); if (input.Peek() == -1) { break; } else { ch = (char)input.Peek(); } } this.result.Add(int.Parse(accum.ToString())); } else switch (ch) { case '+': input.Read(); this.result.Add(Scanner.Add); break; case '-': input.Read(); this.result.Add(Scanner.Sub); break; case '*': input.Read(); this.result.Add(Scanner.Mul); break; case '/': input.Read(); this.result.Add(Scanner.Div); break; case '=': input.Read(); this.result.Add(Scanner.Equal); break; case ';': input.Read(); this.result.Add(Scanner.Semi); break; default: throw new System.Exception("Scanner encountered unrecognized character '" + ch + "'"); } } }
private void Scan(IO.TextReader input) { while (input.Peek() != -1) { char caracter = (char)input.Peek(); // Scan individual tokens if (char.IsWhiteSpace(caracter)) { // eat the current char and skip ahead! input.Read(); } else if (char.IsLetter(caracter) || caracter == '_') { // keyword or identifier Text.StringBuilder accum = new Text.StringBuilder(); while (char.IsLetter(caracter) || caracter == '_') { accum.Append(caracter); input.Read(); if (input.Peek() == -1) { break; } else { caracter = (char)input.Peek(); } } this.resultado.Add(accum.ToString()); } else if (caracter == '"') { // string literal Text.StringBuilder accum = new Text.StringBuilder(); input.Read(); // skip the '"' if (input.Peek() == -1) { throw new System.Exception("Cadena sin terminar"); } while ((caracter = (char)input.Peek()) != '"') { accum.Append(caracter); input.Read(); if (input.Peek() == -1) { throw new System.Exception("Cadena sin terminar"); } } // skip the terminating " input.Read(); this.resultado.Add(accum); } else if (char.IsDigit(caracter)) { // numeric literal Text.StringBuilder accum = new Text.StringBuilder(); while (char.IsDigit(caracter)) { accum.Append(caracter); input.Read(); if (input.Peek() == -1) { break; } else { caracter = (char)input.Peek(); } } this.resultado.Add(int.Parse(accum.ToString())); } else switch (caracter) { case '+': input.Read(); this.resultado.Add(Scanner.Sum); break; case '-': input.Read(); this.resultado.Add(Scanner.Res); break; case '*': input.Read(); this.resultado.Add(Scanner.Mul); break; case '/': input.Read(); this.resultado.Add(Scanner.Div); break; case '=': input.Read(); if (input.Peek() == '=') { input.Read(); this.resultado.Add(Scanner.Eq); } else this.resultado.Add(Scanner.Igual); break; case ';': input.Read(); this.resultado.Add(Scanner.PyC); break; case '>': input.Read(); if (input.Peek() == '=') { input.Read(); this.resultado.Add(Scanner.Gte); } else this.resultado.Add(Scanner.Gt); break; case '<': input.Read(); if (input.Peek() == '=') { input.Read(); this.resultado.Add(Scanner.Lte); } else this.resultado.Add(Scanner.Lt); break; case '!': input.Read(); if (input.Peek() == '=') { input.Read(); this.resultado.Add(Scanner.Neq); } else throw new System.Exception("No se reconoce el siguiente caracter: '" + caracter + "'"); break; default: throw new System.Exception("No se reconoce el siguiente caracter: '" + caracter + "'"); } } }
/// <summary>Writes data to the piece</summary> /// <param name="stream">Data to write</param> /// <param name="length">Amount of data to write</param> /// <param name="poffset">Offset within the piece to write data to</param> public void Write(IO.Stream stream, int length, int poffset) { byte[] tdata = new byte[length]; stream.Read(tdata, 0, length); this.Write(tdata, 0, length, poffset); }