zoukankan      html  css  js  c++  java
  • C# 解析torrent文件

    基础知识:

    torrent文件信息存储格式: 

    bencoding是一种以简洁格式指定和组织数据的方法。支持下列类型:字节串、整数、列表和字典。

    1 字符串存储格式:  <字符串的长度>:<字符串的内容> 
    例如:    4:abcd 表示abcd, 2:ab 表示ab

    2 数字的存储格式:  i<整数>e
    例如:    i32e 表示整数32, i1024e 表示整数1024

    3 列表的存储格式: l<子元素>e  其中:子元素可以是字符串,整数,列表和字典,或者是它们的组合体
    例如:    l4:asdf4:qwere    表示 [ "asdf", "qwer" ] 

    4 字典的存储格式: d<<key><value><key><value><key><value>...<key><value>>e 
    其中:key只能是字符串类型,value则可以是字符串,整数,列表和字典,或者是它们的组合体,key和value必须是成对出现的
    例如:    d3:cow3:moo4:spam4:eggse    表示 { "cow" => "moo", "spam" => "eggs" } 
            d4:spaml1:a1:bee            表示 { "spam" => [ "a", "b" ] } 
            d9:publisher3:bob4:spaml1:a1:be5:counti80ee  表示 { "publisher" => "bob", "spam" => [ "a", "b" ], "count" => 80 }

    代码:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.IO;
      4 using System.Text;
      5 using NPOI.OpenXmlFormats.Spreadsheet;
      6 using Newtonsoft.Json;
      7 
      8 namespace ConsoleApp
      9 {
     10     /// <summary>
     11     /// Summary description for Class1.-change wdq
     12     /// </summary>
     13     public class Class1
     14     {
     15         static void Main(string[] args)
     16         {
     17             if (args.Length != 1)
     18             {
     19                 Console.WriteLine("请指定torrent文件");
     20                 return;
     21             }
     22             string filename = args[0];
     23             var data = Torrent.DecodeFile(filename);
     24             //Console.WriteLine(JsonConvert.SerializeObject(data, Newtonsoft.Json.Formatting.Indented));
     25             ShowData(data);
     26         }
     27 
     28         private static void ShowData(ItemBase data)
     29         {
     30             if (data.ItemType == ItemType.Dictionary)
     31             {
     32                 foreach (var kv in (data as DictionaryItem).DictionaryData)
     33                 {
     34                     switch (kv.Value.ItemType)
     35                     {
     36                         case ItemType.Dictionary:
     37                             Console.WriteLine(kv.Key + ":");
     38                             ShowData(kv.Value);
     39                             break;
     40                         case ItemType.List:
     41                             Console.WriteLine(kv.Key + ":");
     42                             ShowData(kv.Value);
     43                             break;
     44                         case ItemType.String:
     45                             if (kv.Key == "pieces")
     46                             {
     47                                 break;
     48                             }
     49                             Console.WriteLine(kv.Key + "=" + (kv.Value as StringItem).StringData);
     50                             break;
     51                         case ItemType.Number:
     52                             Console.WriteLine(kv.Key + "=" + (kv.Value as NumberItem).NumberData);
     53                             break;
     54                     }
     55                 }
     56             }
     57             if (data.ItemType == ItemType.List)
     58             {
     59                 foreach (var i in (data as ListItem).ListData)
     60                 {
     61                     switch (i.ItemType)
     62                     {
     63                         case ItemType.Dictionary:
     64                         case ItemType.List:
     65                             ShowData(i);
     66                             break;
     67                         case ItemType.String:
     68                             Console.WriteLine((i as StringItem).StringData);
     69                             break;
     70                         case ItemType.Number:
     71                             Console.WriteLine((i as NumberItem).NumberData);
     72                             break;
     73                     }
     74                 }
     75             }
     76         }
     77     }
     78 
     79     public class Torrent
     80     {
     81         public static ItemBase DecodeFile(string filename)
     82         {
     83             using (var fs = new FileStream(filename, FileMode.Open))
     84             {
     85                 using (BinaryReader br = new BinaryReader(fs))
     86                 {
     87                     return DecodeData(br);
     88                 }
     89             }
     90         }
     91 
     92         private static ItemBase DecodeData(BinaryReader br, Stack<bool> st = null)
     93         {
     94             var flag = br.PeekChar(); 
     95             List<byte> ls = new List<byte>();
     96             byte b = 0;
     97             switch (flag)
     98             {
     99                 case 'e':
    100                     br.ReadByte();
    101                     return null;
    102                 case 'l'://列表
    103                     br.ReadByte();
    104                     var itemLs = new ListItem(); 
    105                     ItemBase i = null;
    106                     if (st == null)
    107                     {
    108                         st = new Stack<bool>();
    109                     }
    110                     st.Push(true);
    111                     do
    112                     {
    113                         i = DecodeData(br, new Stack<bool>());
    114                         if (i != null)
    115                         {
    116                             itemLs.ListData.Add(i);
    117                         }
    118                         else
    119                         {
    120                             st.Pop();
    121                         }
    122                     } while (st.Count != 0 && br.BaseStream.Position != br.BaseStream.Length);
    123 
    124                     return itemLs;                    
    125                 case 'd'://字典
    126                     br.ReadByte();
    127                     var itemDic = new DictionaryItem();
    128                     var key = DecodeData(br);
    129                     while (key != null && br.BaseStream.Position != br.BaseStream.Length)
    130                     {
    131                         var val = DecodeData(br);
    132                         itemDic.DictionaryData[(key as StringItem).StringData] = val;
    133                         key = DecodeData(br);
    134                     }
    135 
    136                     return itemDic; 
    137                 case 'i'://数字
    138                     br.ReadByte();
    139                     b = br.ReadByte();
    140                     while (b != 'e')
    141                     {
    142                         ls.Add(b);
    143                         b = br.ReadByte();
    144                     }
    145                     return new NumberItem(long.Parse(Encoding.UTF8.GetString(ls.ToArray()))) { RawBytes = ls.ToArray() };                    
    146                 default://字符串 
    147                     b = br.ReadByte();
    148                     while (b != ':')
    149                     {
    150                         ls.Add(b);
    151                         b = br.ReadByte();
    152                     }
    153                     var len = int.Parse(Encoding.UTF8.GetString(ls.ToArray()));
    154                     var bufStr = br.ReadBytes(len);
    155                     var data = Encoding.UTF8.GetString(bufStr);
    156                     return new StringItem(data) { RawBytes = bufStr };                    
    157             } 
    158         }
    159     }
    160 
    161     public class ItemBase
    162     {
    163         [JsonIgnore]
    164         public ItemType ItemType { get; set; }
    165         [JsonIgnore]
    166         public byte[] RawBytes { get; set; }
    167     }
    168 
    169     public class StringItem : ItemBase
    170     {
    171         public StringItem(string data)
    172         {
    173             StringData = data;
    174             ItemType = ItemType.String;
    175         }
    176         public string StringData { get; set; }
    177     }
    178     public class NumberItem : ItemBase
    179     {
    180         public NumberItem(long num)
    181         {
    182             NumberData = num;
    183             ItemType = ItemType.Number;
    184         }
    185         public long NumberData { get; set; }
    186     }
    187 
    188     public class ListItem : ItemBase
    189     {
    190         public ListItem()
    191         {
    192             ItemType = ItemType.List;
    193         }
    194         public List<ItemBase> ListData { get; set; } = new List<ItemBase>();
    195     }
    196 
    197     public class DictionaryItem : ItemBase
    198     {
    199         public DictionaryItem()
    200         {
    201             ItemType = ItemType.Dictionary;
    202         }
    203         public Dictionary<string, ItemBase> DictionaryData { get; set; } = new Dictionary<string, ItemBase>();
    204     }
    205 
    206     public enum ItemType
    207     {
    208         String, Number, List, Dictionary
    209     }
    210 }

    Github地址:https://github.com/a14907/AConsoleAppForFun.git

      效果:

  • 相关阅读:
    [20170706]SQL Server事务复制订阅端,job不小心被删,修复
    [20170629]带过滤的复制项UI操作导致订阅全部初始化问题
    自动创建数据库镜像,证书交换
    “RESOURCE MONITOR“CPU占用特别高
    索引视图导致死锁
    Percona TokuDB
    从MySQL 5.5迁移到Mariadb 10.1.14
    SQL Server 2014新特性:其他
    SQL Server 2014新特性:分区索引重建
    SQL Server 2012 新特性:其他
  • 原文地址:https://www.cnblogs.com/a14907/p/7593299.html
Copyright © 2011-2022 走看看