]> Sergey Matveev's repositories - btrtrc.git/blobdiff - metainfo/metainfo.go
Fix error unmarshalling bad metainfo nodes field
[btrtrc.git] / metainfo / metainfo.go
index 52ba9bf6fcf1d8a822702d22029839c83f648867..fbf48671d484a0e3342f855585a98a91975c42f2 100644 (file)
@@ -1,17 +1,27 @@
 package metainfo
 
 import (
-       "crypto/sha1"
        "io"
+       "net/url"
        "os"
+       "time"
 
-       "github.com/anacrolix/libtorgo/bencode"
+       "github.com/anacrolix/torrent/bencode"
 )
 
-// Information specific to a single file inside the MetaInfo structure.
-type FileInfo struct {
-       Length int64    `bencode:"length"`
-       Path   []string `bencode:"path"`
+type MetaInfo struct {
+       InfoBytes    bencode.Bytes `bencode:"info,omitempty"`                              // BEP 3
+       Announce     string        `bencode:"announce,omitempty"`                          // BEP 3
+       AnnounceList AnnounceList  `bencode:"announce-list,omitempty"`                     // BEP 12
+       Nodes        []Node        `bencode:"nodes,omitempty,ignore_unmarshal_type_error"` // BEP 5
+       // Where's this specified? Mentioned at
+       // https://wiki.theory.org/index.php/BitTorrentSpecification: (optional) the creation time of
+       // the torrent, in standard UNIX epoch format (integer, seconds since 1-Jan-1970 00:00:00 UTC)
+       CreationDate int64   `bencode:"creation date,omitempty,ignore_unmarshal_type_error"`
+       Comment      string  `bencode:"comment,omitempty"`
+       CreatedBy    string  `bencode:"created by,omitempty"`
+       Encoding     string  `bencode:"encoding,omitempty"`
+       UrlList      UrlList `bencode:"url-list,omitempty"` // BEP 19 WebSeeds
 }
 
 // Load a MetaInfo from an io.Reader. Returns a non-nil error in case of
@@ -36,110 +46,50 @@ func LoadFromFile(filename string) (*MetaInfo, error) {
        return Load(f)
 }
 
-// The info dictionary.
-type Info struct {
-       PieceLength int64      `bencode:"piece length"`
-       Pieces      []byte     `bencode:"pieces"`
-       Name        string     `bencode:"name"`
-       Length      int64      `bencode:"length,omitempty"`
-       Private     bool       `bencode:"private,omitempty"`
-       Files       []FileInfo `bencode:"files,omitempty"`
-}
-
-func (me *Info) TotalLength() (ret int64) {
-       if me.IsDir() {
-               for _, fi := range me.Files {
-                       ret += fi.Length
-               }
-       } else {
-               ret = me.Length
-       }
+func (mi MetaInfo) UnmarshalInfo() (info Info, err error) {
+       err = bencode.Unmarshal(mi.InfoBytes, &info)
        return
 }
 
-func (me *Info) NumPieces() int {
-       return len(me.Pieces) / 20
+func (mi MetaInfo) HashInfoBytes() (infoHash Hash) {
+       return HashBytes(mi.InfoBytes)
 }
 
-type Piece interface {
-       Hash() []byte
-       Length() int64
+// Encode to bencoded form.
+func (mi MetaInfo) Write(w io.Writer) error {
+       return bencode.NewEncoder(w).Encode(mi)
 }
 
-type piece struct {
-       Info *Info
-       i    int
+// Set good default values in preparation for creating a new MetaInfo file.
+func (mi *MetaInfo) SetDefaults() {
+       mi.CreatedBy = "github.com/anacrolix/torrent"
+       mi.CreationDate = time.Now().Unix()
 }
 
-func (me piece) Length() int64 {
-       if me.i == me.Info.NumPieces()-1 {
-               return me.Info.TotalLength() - int64(me.i)*me.Info.PieceLength
+// Creates a Magnet from a MetaInfo. Optional infohash and parsed info can be provided.
+func (mi MetaInfo) Magnet(infoHash *Hash, info *Info) (m Magnet) {
+       m.Trackers = append(m.Trackers, mi.UpvertedAnnounceList().DistinctValues()...)
+       if info != nil {
+               m.DisplayName = info.BestName()
        }
-       return me.Info.PieceLength
-}
-
-func (me *Info) Piece(i int) piece {
-       return piece{me, i}
-}
-
-func (i *Info) IsDir() bool {
-       return len(i.Files) != 0
-}
-
-// The files field, converted up from the old single-file in the parent info
-// dict if necessary. This is a helper to avoid having to conditionally handle
-// single and multi-file torrent infos.
-func (i *Info) UpvertedFiles() []FileInfo {
-       if len(i.Files) == 0 {
-               return []FileInfo{{
-                       Length: i.Length,
-                       // Callers should determine that Info.Name is the basename, and
-                       // thus a regular file.
-                       Path: nil,
-               }}
+       if infoHash != nil {
+               m.InfoHash = *infoHash
+       } else {
+               m.InfoHash = mi.HashInfoBytes()
        }
-       return i.Files
-}
-
-// The info dictionary with its hash and raw bytes exposed, as these are
-// important to Bittorrent.
-type InfoEx struct {
-       Info
-       Hash  []byte
-       Bytes []byte
+       m.Params = make(url.Values)
+       m.Params["ws"] = mi.UrlList
+       return
 }
 
-var (
-       _ bencode.Marshaler   = InfoEx{}
-       _ bencode.Unmarshaler = &InfoEx{}
-)
-
-func (this *InfoEx) UnmarshalBencode(data []byte) error {
-       this.Bytes = make([]byte, 0, len(data))
-       this.Bytes = append(this.Bytes, data...)
-       h := sha1.New()
-       _, err := h.Write(this.Bytes)
-       if err != nil {
-               panic(err)
+// Returns the announce list converted from the old single announce field if
+// necessary.
+func (mi *MetaInfo) UpvertedAnnounceList() AnnounceList {
+       if mi.AnnounceList.OverridesAnnounce(mi.Announce) {
+               return mi.AnnounceList
        }
-       this.Hash = h.Sum(nil)
-       return bencode.Unmarshal(data, &this.Info)
-}
-
-func (this InfoEx) MarshalBencode() ([]byte, error) {
-       if this.Bytes != nil {
-               return this.Bytes, nil
+       if mi.Announce != "" {
+               return [][]string{{mi.Announce}}
        }
-       return bencode.Marshal(&this.Info)
-}
-
-type MetaInfo struct {
-       Info         InfoEx      `bencode:"info"`
-       Announce     string      `bencode:"announce"`
-       AnnounceList [][]string  `bencode:"announce-list,omitempty"`
-       CreationDate int64       `bencode:"creation date,omitempty"`
-       Comment      string      `bencode:"comment,omitempty"`
-       CreatedBy    string      `bencode:"created by,omitempty"`
-       Encoding     string      `bencode:"encoding,omitempty"`
-       URLList      interface{} `bencode:"url-list,omitempty"`
+       return nil
 }