BEncoding編碼及asp提取Torrent檔案資訊

來源:互聯網
上載者:User

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

============
真是遺憾啊,自己搞了幾天終於搞定,確因為表達能力太爛無法寫出體驗,只能放些乾巴巴的東西上來。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.