BEncoding编码及asp提取Torrent文件信息

BEncoding编码及asp提取Torrent文件信息

1、BEncoding编码
Bencoding编码是BT协议用来说明、组织信息的的一种数据格式,来源于PYTHON语言。主要数据结构为:
数  字 = < ascii码表示的0-9 >
字  符 = <任意单字节二进制字符>
整  数 = (字符”i”)<1-n>(数字)(字符”e”)
字符串 = <1-n>(数字)(字符”:”)<1-m>(字符)     *数字为后面字符串的长度
列  表 = (字符”l”)<1-n>(整数|字符串|列表|字典)(字符”e”)
字  典 = (字符”d”)<1-n>((字符串)(整数|字符串|列表|字典))(字符”e”)
Torrent文件 = (字典)
 
 大家可以看到,这种数据结构把信息分成东一块,西一块,以树状结构组成,更本没法顺序读取,但可以用递归方式解析成对象,在内存中形成一个和逻辑结构相当的对象树,然后通过逻辑位置读取。由于是二进制结构,由必须全部解析成对象才能读取,用asp来搞,代价很大。

2、Torrent文件
 Torrent文件即一个“单一”的字典文件,其信息以以层次结构存储在字典项中,字典关键字区分大小写。主要字典数据项为:
 announce:(字符串)种子服务器
    announce-list:(列表)备用种子服务器
 creation-date:(整数)unix时间
 created by:(字符串)创建人
 info:(字典)
  length:(整数)文件大小
  name:(字符串)最上层目录名
  piece length:(整数)下载结构信息,这里我们不管
  pieces:(字符串)下载结构信息,这里我们不管
  files:(字典)仅多文件时存在
      length:(整数)文件大小
   Path:(列表)文件路径,采用超JB烦人的方式列表逐层列出目录民,最后到文件名

 从逻辑结构,可以知道他们解析后的读取方式。

 例如:

 发布时间=Dictionary(“creation date”).readInteger
 某个节点=Dictionary(“nodes”).List(i).list(0).readString & ":" & Dictionary(“nodes”).List(i).list(0).readInteger
 列表中第3个文件的路径为
     假设tmp= Dictionary(“info”).Dictionary(“files”).List(3).Dictionary(“path”)
     strPath=tmp.list(0).readString & "/" & tmp.list(1).readString & "/"...
  

3、具体编程提要
    a、几点要注意的:
 Bencoding中的整数没有长度限制,应而最好用dbl储存,不过为为了避免溢出,可以设立一个限制,比方最大20位整数。
 解析过程调试很麻烦,最好主动设置错误信息,比方解析整数没有'i'头,就放一个err.raise vbobjectError,"readInteger()","'i' head missing",而不要等到脚本级数据转换错误时在找毛病。
 同是字符串类型,字典关键字是asc编码,而某些字符串字典的数据,例如name.utf-8,path.utf-8,通常用utf8编码,以防止乱码。因而建议字典关键字则用ascii直接转化。而全部字典数据项字符串都用byte()结构,使用时在具体处理。
 我看了一些asp的bencoding解析方式,采用instrb(bin,":")这类的办法寻找标志,然后直接midb->cdbl转换,个人觉得这违背词法分析原则,可能有不可预料后果,例如小数负数。最好采用while midb(bin,i,1)&chr(0)<="9" and .. >="0" 的方式
 信息保存为文件的后缀,由于Bencoding解析无法过滤<%%>,应而以asp等web应用程序后缀保存可能导致网站漏洞。
 要不要class_terminate时递归erase,setnoting清除对象呢?我觉得这些对象不需要反复用,不会在运行过程中膨胀,asp结束系统会自动回收,还是不要多事的号。

    b、Bencoding以层次组织,以递归解析,可以每种数据结构建立一个类,每次解析一个数据结构,即将其封为对象,返回上一层,通过递归,最终将返回倒跟节点。asp不支持静态过程,所以每种数据结构的解析过程最好放在类外面。

   主要过程如下
   
class CBencodingInteger
 public lngPosition '在文件中的位置
 public lngLength '其全部结构包括子数据的长度
 public dblValue  '值
end class
class CBencodingString
 public lngPosition '在文件中的位置
 public lngLength '其全部结构包括子数据的长度
 public binValue  '值
end class
Class CBencodingList
 Public lngPosition,lngLength
 Private m_aobj,m_intCount
 
 Private Sub class_initialize()
  ReDim m_aobj(0)
  m_intCount=0
 End Sub

 Public Property Get Count()
  Count=m_intCount
 End Property

 Public Default Function Item(intIndex)
  If intIndex<0 Or intIndex>=m_intCount Then Err.raise vbObjectError,"Item()","index overflow"
  Set Item=m_aobj(intIndex)
 End Function

 Public Function Add(objItem)
  ReDim preserve m_aobj(m_intCount)
  Set m_aobj(m_intCount)=objItem
  m_intCount=m_intCount+1
 End Function
End Class

Class CBencodingDictionary
 Public lngPosition,lngLength
 private m_objDict
 
 Public Sub class_initialize()
  Set m_objDict=CreateObject("scripting.dictionary")
 End Sub

 Public Default Function Item(strIndex)
  If m_objDict.Exists(strIndex) then
   Set Item=m_objDict.item(strIndex)
  else
   Err.raise vbObjectError,"Item()","not such key in dictionary."
  End If
 End Function

 Public Function Add(strKey,objItem)

  m_objDict.add strkey,objItem
 End Function

 Public Property Get Count()
  Count=mobjDict.count
 End Property
End Class 

'将byte()字符转化为vbString
Function PickBinChar(binSrc,lngPos)
 PickBinChar=midb(binSrc,lngPos,1)&Chrb(0)
End Function

'读取整数
'[in]binSrc
'[in,out]lngCurpos
'[in]lngMaxPos
'[out]objRet
Function readInteger(binSrc,lngCurPos,objRet)
 Dim i,j
 Dim chrBuf
 Dim strNum,dblNum
 Dim lngBakPos

 lngBakPos=lngCurPos '直接更改解析位置lngCurPos好处是发生err,可以知道错误的字符位置
 Set objRet=Nothing 

 If PickBinChar(binSrc,lngCurPos)<>"i" Then Err.raise vbObjectError,"readInteger()","'i' head missing."

 lngCurPos=lngCurPos+1

 i=0
 strNum=""
 chrBuf=PickBinChar(binSrc,lngCurPos)
 Do While chrBuf<="9" And chrBuf>="0"
  strNum=strNum & chrBuf
  lngCurPos=lngCurPos+1
  chrBuf=PickBinChar(binSrc,lngCurPos)
  i=i+1
  If i>MAX_INT_LEN Then Err.raise vbobjectError,"readInteger()","Integer overflow."
 Loop

 If chrBuf<>"e" Then Err.raise vbobjectError,"readInteger()","'e' rare missing."
 If strNum="" Then Err.raise vbObjectError,"readInteger()","empty between 'i' and 'e'."

 Set objRet=new CBencodingInteger
 objRet.lngPosition=lngBakPos
 objRet.lngLength=lngCurPos-lngBakPos
 objRet.dblValue=CDbl(strNum)

 lngCurPos=lngCurPos+1
End Function

'readString,readList,readDictionary我就不贴了,基本类似,就是dictionary和list的位置指针要小心一些


'测试


Function LoadFromFile(strPath,bin)  '也可以改成request.binaryread,不过要先处理一下multiform数据格式
 Dim objAdoStm

 Set objAdoStm=CreateObject("adodb.stream")
 objAdoStm.Type=1
 objAdoStm.Mode=3
 objAdoStm.Open

 objAdoStm.LoadFromFile strPath
 objAdoStm.Position=0
 bin=objAdoStm.Read(-1)

 objAdoStm.close
 Set objAdoStm=Nothing
End Function

Debug:Sub Debug()
 Dim bin
 LoadFromFile "test.torrent",bin

 Dim objTmp
 '解析根节点,以此递归解析全部文件
 readDictionary bin,1,0,objTmp 
 '显示第0个节点的IP位置
 
 MsgBox byte2Str(objTmp.item("nodes").item(0).item(0).binValue)
End Sub

============
真是遗憾啊,自己搞了几天终于搞定,确因为表达能力太烂无法写出体验,只能放些干巴巴的东西上来。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值