PureBasic - форум

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » PureBasic - форум » OpenSource » Создание и редактирование torrent файлов.


Создание и редактирование torrent файлов.

Сообщений 1 страница 7 из 7

1

Функции для работы с торрент файлом:

Код:
; Создание торрент файла и работа с ним.
; Автор - Пётр
; https://purebasic.mybb.ru/viewtopic.php?id=249

EnableExplicit

;- Создание torrent-файла

Structure TorrentFiles_CreateInfo
  FileName.s         ; Путь к торрент-файлу.
  Path.s             ; Путь к файлам.
  ClientName.s       ; Название торрент-клиента (добавляется в торрент-файл).
  ProgName.s         ; Название торрент-клиента (для вывода сообщений).
  BreakThread.b      ; Признак того, что нужно завершить поток.
  Directory.b        ; 0 - файл; 1- папка.
  
  List announce.s()  ; Список анонс-серверов.
  Publisher.s
  Publisher_Url.s
  comment.s          ; Комментарий к торренту.
  pieceLength.l      ; Размер сегмента в байтах.
  private.b          ; Если 1, то торрент приватный.
  *PiecesCB          ; Адрес процедуры, в котрой будут передаватся данные о обрабатываемом файле и проценте обработки частей при создании torrent-файла.
  ErrorCode.b        ; Код ошибки создания torrent-файла.
  ErrorString.s
  Result.b           ; 1 - ОК; 0 - Ошибка.
EndStructure

Structure TorrentFiles_FindFile
  Path.s
  FileSize.q
EndStructure

Procedure TorrentFiles_Bencoding_W_String(File, String.s)
  Protected Bytes
  If String<>""
    Bytes = StringByteLength(String, #PB_UTF8)
    If Bytes>0
      WriteString(File, Str(Bytes)+":"+String, #PB_UTF8)
    EndIf
  EndIf
EndProcedure

Procedure TorrentFiles_Bencoding_W_Int(File, Number.q)
  WriteByte(File,'i')
  WriteString(File, Str(Number))
  WriteByte(File,'e')
EndProcedure

Procedure.l TorrentFiles_W_CalcPieces(AllSize.q) ; Вычисление требуемого числа частей, исходя из общего размера файлов.
  Protected Result.l
  Result = 65536 ; 64 КБ.
  If AllSize>0
    If AllSize / 65536 <= 1000         ; 64 КБ.
      Result = 65536
    ElseIf AllSize / 131072 <= 1000    ; 128 КБ.
      Result = 131072
    ElseIf AllSize / 262144 <= 1000    ; 256 КБ.
      Result = 262144
    ElseIf AllSize / 524288 <= 1000    ; 512 КБ.
      Result = 524288
    ElseIf AllSize / 1048576 <= 1000   ; 1024 КБ.
      Result = 1048576
    ElseIf AllSize / 2097152 <= 1000   ; 2048 КБ.
      Result = 2097152
    ElseIf AllSize / 4194304 <= 4000   ; 4096 КБ.
      Result = 4194304
    ElseIf AllSize / 8388608 <= 4000   ; 8 МБ.
      Result = 8388608
    ElseIf AllSize / 16777216 <=8000   ; 16 МБ.
      Result = 16777216
    ElseIf AllSize / 33554432 <=10000  ; 32 МБ.
      Result = 33554432
    Else                               ; 64 МБ..
      Result = 67108864
    EndIf
  EndIf
  ProcedureReturn Result
EndProcedure


Procedure.q TorrentFiles_SizeFiles(List ListFiles.TorrentFiles_FindFile())
  Protected Result.q
  Result = 0
  ForEach ListFiles()
    Result + ListFiles()\FileSize
  Next
  ProcedureReturn Result
EndProcedure

Prototype TorrentFiles_W_GetPieces_CB(File.s, Pos.f) ; Прогресс обработки частей. Имя файла и процент обработаного (0 - 100).

Procedure.b TorrentFiles_W_GetPieces(File_torrent, Piece_Length, Path.s, List ListFiles.TorrentFiles_FindFile(), List SHA1data.s(), *ProcCB, *BreakThread)
  Protected FileID, Result.b, *mem, ReadByte
  Protected SHA1.s, Err.b, FileName.s
  Protected SizeList, Count, MemPos, t_Piece_Length
  Protected CB_Piece.f, CB_Piece_Plus.f, Pieces_CB
  
  Result = #False
  Err    = #False
  
  ClearList(SHA1data())
  t_Piece_Length = Piece_Length
  *mem = AllocateMemory(Piece_Length+1000)
  
  CB_Piece_Plus = 100 / (TorrentFiles_SizeFiles(ListFiles())/Piece_Length)
  CB_Piece = 0
  If *ProcCB
    Pieces_CB.TorrentFiles_W_GetPieces_CB = *ProcCB
    Pieces_CB("",0)
  EndIf
  
  If *mem
    SizeList = ListSize(ListFiles()) - 1
    Count = 0
    MemPos = 0
    ForEach ListFiles()
      
      If PeekB(*BreakThread)=1 ; Принудительное прекращение создания торрент-файла.
        FreeMemory(*mem)
        ProcedureReturn 0
      EndIf
      
      FileName=Path+ListFiles()\Path
      FileID = ReadFile(#PB_Any, FileName)
      If FileID
        
        While Eof(FileID) = 0
          ReadByte = ReadData(FileID, *mem+MemPos, t_Piece_Length)
          If ReadByte+MemPos>=Piece_Length Or (ReadByte>0 And Count>=SizeList And Eof(FileID) <> 0)
            SHA1=SHA1Fingerprint(*mem, ReadByte+MemPos)
            If Len(SHA1) = 40
              If AddElement(SHA1data())
                SHA1data() = SHA1
              Else
                Err = #True
                Break
              EndIf
            Else
              Err = #True
              Break
            EndIf
            MemPos = 0
            t_Piece_Length = Piece_Length
            
            If *ProcCB
              CB_Piece + CB_Piece_Plus
              Pieces_CB(FileName, CB_Piece)
            EndIf
          Else
            t_Piece_Length - ReadByte
            MemPos + ReadByte
            If ReadByte<=0
              Break
            EndIf
          EndIf
          
          
          If PeekB(*BreakThread)=1 ; Принудительное прекращение создания торрент-файла.
            CloseFile(FileID)
            FreeMemory(*mem)
            ProcedureReturn 0
          EndIf
          
        Wend 
        Count + 1
        CloseFile(FileID)
      EndIf
      
      If Err = #True
        Break
      EndIf
    Next
    
    If Err = #False
      Result = #True
      If *ProcCB
        CB_Piece + CB_Piece_Plus
        Pieces_CB("", 100)
      EndIf
    EndIf
    
    FreeMemory(*mem)
  EndIf
  
  ProcedureReturn Result
EndProcedure


Procedure TorrentFiles_FindFiles(Path.s, SubPath.s, Count, List ListFiles.TorrentFiles_FindFile(), *BreakThread) ; Сканирование выбранной папки для добавления файлов в torrent-файл.
  Protected Directory, Type, Name.s
  
  If PeekB(*BreakThread)=1 ; Принудительное прекращение создания торрент-файла.
    ProcedureReturn
  EndIf
  
  If Right(Path,1)<>"\":Path + "\":EndIf
  
  If Count<100
    Directory = ExamineDirectory(#PB_Any, Path, "*.*") ; Начало сканирования папки.
    If Directory
      While NextDirectoryEntry(Directory) ; Следующий файл / папка.
        If PeekB(*BreakThread)=1 ; Принудительное прекращение создания торрент-файла.
          Break
        EndIf
        Type   = DirectoryEntryType(Directory) ; Тип объекта (файл или папка).
        Name.s = DirectoryEntryName(Directory) ; Имя объекта.
        If Name="." Or Name=".."
          Continue
        EndIf
        If Type = #PB_DirectoryEntry_File ; Найден файл.
          InsertElement(ListFiles()) 
          ListFiles()\Path = SubPath + Name
          ListFiles()\FileSize = DirectoryEntrySize(Directory)
        ElseIf Type = #PB_DirectoryEntry_Directory ; Найдена папка.
          TorrentFiles_FindFiles(Path+Name, SubPath+Name+"\", Count+1, ListFiles(), *BreakThread)
        EndIf
      Wend
      FinishDirectory(Directory) ; Завершение сканирования папки.
    EndIf
  EndIf
  
EndProcedure


Procedure.b TorrentFiles_CreateTorrent(*TorrentInfo.TorrentFiles_CreateInfo)
  Protected File_t, Result.b, Piece_Length, Err
  Protected NewList SHA1_Data.s(), ListSize
  Protected NewList ListFiles.TorrentFiles_FindFile();, 
  Protected *SHA1_mem, i, Count, Char_b.a
  Protected String.s, SHA1_FilePath.s, sTemp.s, Pos
  Protected GMT, tzi.TIME_ZONE_INFORMATION, Pieces_CB
  Protected FileName.s, AddFile.s, Directory.b, TorrentClientName.s, ProgName.s
   
  ClearList(SHA1_Data())
  ClearList(ListFiles())
  
  If *TorrentInfo\PiecesCB
    Pieces_CB.TorrentFiles_W_GetPieces_CB = *TorrentInfo\PiecesCB
    Pieces_CB("",0)
  EndIf
  
  FileName = *TorrentInfo\FileName
  AddFile = *TorrentInfo\Path
  Directory = *TorrentInfo\Directory
  TorrentClientName = *TorrentInfo\ClientName
  ProgName = *TorrentInfo\ProgName
  
  Piece_Length = *TorrentInfo\pieceLength
  
  *TorrentInfo\ErrorCode = 0
  *TorrentInfo\ErrorString = ""
  *TorrentInfo\Result = 0
  *TorrentInfo\BreakThread = 0
    
  Result = #False
  Err    = #False
  
  If Directory = #True
    If FileSize(AddFile) <> -2
      *TorrentInfo\ErrorCode = 1
      *TorrentInfo\ErrorString = AddFile
      ProcedureReturn 0
    EndIf
  Else
    If FileSize(AddFile)<=0
      *TorrentInfo\ErrorCode = 2
      *TorrentInfo\ErrorString = AddFile
      ProcedureReturn 0
    EndIf
  EndIf
  
  *SHA1_mem = AllocateMemory(32)
  If *SHA1_mem = 0
    *TorrentInfo\ErrorCode = 3
    ProcedureReturn 0
  EndIf
  
  File_t = CreateFile(#PB_Any, FileName)
  If File_t
    
    WriteByte(File_t,'d')
    
    ListSize = ListSize(*TorrentInfo\announce())
    If ListSize>0
      TorrentFiles_Bencoding_W_String(File_t, "announce")
      SelectElement(*TorrentInfo\announce(),0)
      TorrentFiles_Bencoding_W_String(File_t, *TorrentInfo\announce())
      If ListSize > 1
        TorrentFiles_Bencoding_W_String(File_t, "announce-list")
        WriteByte(File_t,'l')
        WriteByte(File_t,'l')
        ForEach *TorrentInfo\announce()
          TorrentFiles_Bencoding_W_String(File_t, *TorrentInfo\announce())
        Next
        WriteByte(File_t,'e')
        WriteByte(File_t,'e')
      EndIf
    EndIf
    
    If *TorrentInfo\comment<>""
      TorrentFiles_Bencoding_W_String(File_t, "comment")
      TorrentFiles_Bencoding_W_String(File_t, *TorrentInfo\comment)
    EndIf
    
    If TorrentClientName<>""
      TorrentFiles_Bencoding_W_String(File_t, "created by")
      TorrentFiles_Bencoding_W_String(File_t, TorrentClientName)
    EndIf
    
    TorrentFiles_Bencoding_W_String(File_t, "creation date")
    If GetTimeZoneInformation_(@tzi) = 2 ; значит время летнее 
      GMT = tzi\Bias/(-60)+1 ; Например в Лондоне 12 часов, в Москве 15, разница tzi\Bias = 12-15 = -180 минут 
    Else 
      GMT = tzi\Bias/(-60)   ; Иначе - стандартное время 
    EndIf 
    TorrentFiles_Bencoding_W_Int(File_t, AddDate(Date(),#PB_Date_Hour,-GMT))
    
    TorrentFiles_Bencoding_W_String(File_t, "encoding")
    TorrentFiles_Bencoding_W_String(File_t, "UTF-8")
    
    TorrentFiles_Bencoding_W_String(File_t, "info")
    
    WriteByte(File_t,'d')
    
    If *TorrentInfo\BreakThread = 1 ; Принудительное прекращение создания торрент-файла.
      CloseFile(File_t)
      FreeMemory(*SHA1_mem)
      ProcedureReturn 0
    EndIf

    If Directory = #True ; Добавляем папку
      
      sTemp=ReverseString(AddFile)
      Pos=FindString(sTemp,"\",2)
      If Pos>0
        sTemp = Right(AddFile, Pos-1)
        sTemp = RemoveString(sTemp,"\")
        If sTemp=""
          *TorrentInfo\ErrorCode = 4 ; Нет папки.
        EndIf
      Else
        *TorrentInfo\ErrorCode = 4 ; Странно, выбрана папка, а слеша нет.
        *TorrentInfo\ErrorString = AddFile
        Err = #True
      EndIf
      
      If Err = #False
        
        If *TorrentInfo\PiecesCB
          Pieces_CB("Сбор информации о файлах.",0)
        EndIf
        
        TorrentFiles_FindFiles(AddFile, "", 0, ListFiles(), @*TorrentInfo\BreakThread) ; Получаем список файлов для добавления в торрент.
        
        If *TorrentInfo\BreakThread = 1 ; Принудительное прекращение создания торрент-файла.
          CloseFile(File_t)
          FreeMemory(*SHA1_mem)
          ProcedureReturn 0
        EndIf
        
        ListSize = ListSize(ListFiles())
        If ListSize>0 And TorrentFiles_SizeFiles(ListFiles())>0
          TorrentFiles_Bencoding_W_String(File_t, "files")
          WriteByte(File_t,'l')
          ForEach ListFiles()
            WriteByte(File_t,'d')
            TorrentFiles_Bencoding_W_String(File_t, "length")
            TorrentFiles_Bencoding_W_Int(File_t, ListFiles()\FileSize)
            TorrentFiles_Bencoding_W_String(File_t, "path")
            WriteByte(File_t,'l')
            String = ListFiles()\Path
            String = ReplaceString(String, "/","\") 
            Count  = CountString(String, "\")
            If Count>0
              For i=1 To Count
                TorrentFiles_Bencoding_W_String(File_t, StringField(String, i, "\"))
              Next i
            EndIf
            String = GetFilePart(String)
            TorrentFiles_Bencoding_W_String(File_t, String)
            WriteByte(File_t,'e')
            WriteByte(File_t,'e')
            
            If *TorrentInfo\BreakThread = 1 ; Принудительное прекращение создания торрент-файла.
              CloseFile(File_t)
              FreeMemory(*SHA1_mem)
              ProcedureReturn 0
            EndIf
            
          Next
          WriteByte(File_t,'e')
          
          TorrentFiles_Bencoding_W_String(File_t, "name")
          TorrentFiles_Bencoding_W_String(File_t, sTemp)
        Else
          *TorrentInfo\ErrorCode = 5
          Err = #True
        EndIf
      EndIf
      
      SHA1_FilePath = AddFile
      
    Else ; Добавляем только один файл
      If FileSize(AddFile)>0
        
        TorrentFiles_Bencoding_W_String(File_t, "length")
        TorrentFiles_Bencoding_W_Int(File_t, FileSize(AddFile))
        
        TorrentFiles_Bencoding_W_String(File_t, "name")
        TorrentFiles_Bencoding_W_String(File_t, GetFilePart(AddFile))
        
        If AddElement(ListFiles())
          ListFiles()\Path = GetFilePart(AddFile)
          ListFiles()\FileSize = FileSize(AddFile)
        Else
          *TorrentInfo\ErrorCode = 6
          Err = #True
        EndIf
        SHA1_FilePath = GetPathPart(AddFile)
        
      Else
        *TorrentInfo\ErrorCode = 7 ; Файл пустой.
        Err = #True
      EndIf
    EndIf 
    
    If Err = #False
      
      If Piece_Length < 16*1024
        Piece_Length = TorrentFiles_W_CalcPieces(TorrentFiles_SizeFiles(ListFiles())) ; Автоматический рассчет размера частей.
      EndIf
      
      If *TorrentInfo\BreakThread = 1 ; Принудительное прекращение создания торрент-файла.
        CloseFile(File_t)
        FreeMemory(*SHA1_mem)
        ProcedureReturn 0
      EndIf
      
      TorrentFiles_Bencoding_W_String(File_t, "piece length") ; Размер сегмента в байтах
      TorrentFiles_Bencoding_W_Int(File_t, Piece_Length)
      
      TorrentFiles_Bencoding_W_String(File_t, "pieces")
      
      If SHA1_FilePath<>"" And Right(SHA1_FilePath,1)<>"\":SHA1_FilePath + "\":EndIf
      ; Создание хешей.
      If TorrentFiles_W_GetPieces(File_t, Piece_Length, SHA1_FilePath, ListFiles(), SHA1_Data(), *TorrentInfo\PiecesCB, @*TorrentInfo\BreakThread) = #True
        ListSize = ListSize(SHA1_Data())
        If ListSize>0
          WriteString(File_t, Str(ListSize*20)+":")
          ForEach SHA1_Data()
            FillMemory(*SHA1_mem, 20, 0)
            Count=0
            String = SHA1_Data()
            For i=1 To 40 Step 2
              Char_b = Val("$"+Mid(String, i, 2))
              PokeA(*SHA1_mem+Count, Char_b)
              Count + 1
            Next i
            WriteData(File_t, *SHA1_mem, 20)
            
            If *TorrentInfo\BreakThread = 1 ; Принудительное прекращение создания торрент-файла.
              CloseFile(File_t)
              FreeMemory(*SHA1_mem)
              ProcedureReturn 0
            EndIf
            
          Next
        Else
          *TorrentInfo\ErrorCode = 8
          Err = #True
        EndIf
      Else
        *TorrentInfo\ErrorCode = 9
        Err = #True
      EndIf
      
      If *TorrentInfo\private = 1
        TorrentFiles_Bencoding_W_String(File_t, "private")
        TorrentFiles_Bencoding_W_Int(File_t, 1)
      EndIf
      
      WriteByte(File_t,'e')

      
      If *TorrentInfo\Publisher<>""
        TorrentFiles_Bencoding_W_String(File_t, "publisher")
        TorrentFiles_Bencoding_W_String(File_t, *TorrentInfo\Publisher)
      EndIf
      
      If *TorrentInfo\Publisher_Url<>""
        TorrentFiles_Bencoding_W_String(File_t, "publisher-url")
        TorrentFiles_Bencoding_W_String(File_t, *TorrentInfo\Publisher_Url)
      EndIf
      
      WriteByte(File_t,'e')
      If Err = #False
        Result = #True
      EndIf
    EndIf
    
    CloseFile(File_t)
    
  Else
    *TorrentInfo\ErrorCode = 10
    *TorrentInfo\ErrorString = FileName
  EndIf
  
  If Err = #True
    If FileSize(FileName)>=0
      DeleteFile(FileName)
    EndIf
  EndIf
  
  FreeMemory(*SHA1_mem)
  FreeList(ListFiles())
  FreeList(SHA1_Data())
  
  *TorrentInfo\Result = Result
  
  ProcedureReturn Result
EndProcedure

Procedure TorrentFiles_CreateTorrent_ShowError(ErrorCode.b, Err_String.s="", ProgName.s="") ; Отображение ошибок, произошедших при создании torrent-файла.
  Protected ErrorString.s
  If ErrorCode>0
    If ProgName<>"" : ProgName + " —  " : EndIf
    Select ErrorCode
      Case 1
        ErrorString = "Не найдена папка с файлами."+Chr(10)+Err_String
      Case 2
        ErrorString = "Не найден добавляемый файл."+Chr(10)+Err_String
      Case 3
        ErrorString = "Ошибка выделения памяти под SHA1 хеш."
      Case 4
        ErrorString = "Ошибка в пути к папке с файлами."+Chr(10)+"ВНИМАНИЕ! Нельзя указывать в раздаче корневую папку диска!"+Chr(10)+Err_String
      Case 5
        ErrorString = "Выбранные файлы или папки пустые!"+Chr(10)+"Выберите другое место с файлами."
      Case 6
        ErrorString = "Ошибка при добавлении элемента в список!"+Chr(10)+"Возможно заканчивается свободная память."
      Case 7
        ErrorString = "Выбранный файл пустой (0 байт)!"+Chr(10)+"Выберите другй файл."
      Case 8
        ErrorString = "Отсутсвуют SHA1 хеши файлов."
      Case 9
        ErrorString = "Ошибка при генерации SHA1 хешей файлов."
      Case 10
        ErrorString = "Не удалось создать torrent-файл."+Chr(10)+Err_String
    EndSelect
    MessageRequester(ProgName + "создание torrent-файла.", ErrorString, #MB_ICONWARNING)
  EndIf
EndProcedure




;- Расшифровка torrent-файла.

Structure TorrentFiles_TorrentInfo_pieces ; Описание частей.
  SHA1_string.s        ; SHA1 хеш в виде строки (нижний регистр).
  SHA1_bin.a[20]       ; SHA1 хеш в бинарном виде (20 байт).
EndStructure

Structure TorrentFiles_TorrentInfo_file ; Информация о файлах торрента.
  length.q             ; Размер файла.
  List path.s()        ; Путь, (все папки по отдельности и в конце имя файла).
EndStructure

Structure TorrentFiles_TorrentInfo ; Информация из torrent-файла.
  announce.s           ; Адрес трекера.
  List  announce_list.s()  ; Если есть еще адреса трекеров, то они будут здесь.
  Publisher.s
  Publisher_Url.s
  comment.s            ; Комментарий в torrent-файле.
  created_by.s         ; Информация о создавшем torrent-файл.
  creation_date.l      ; Дата создания torrent-файла по Гринвичу (UTC).
  encoding.b           ; Кодировка файла.
  INFO_Hash.s          ; SHA1 хеш-сумма области "info" torrent-файла.
  TypeDir.b            ; Тип торрента. 1 - папка; любое другое значение - файл.
  CurrentDir_Name.s    ; Имя корневой папки с файлами торрента (только если TypeDir = 1). 
  List files.TorrentFiles_TorrentInfo_file() ; Список всех файлов торрента.
  All_Size.q           ; Размер всех файлов торрента в байтах.
  piece_length.l       ; Размер части.
  Array pieces.TorrentFiles_TorrentInfo_pieces(0) ; SHA1 хеш-суммы частей.
  private.b            ; 1 - торрент приватный; 0 не приватный.
  ErrorCode.b          ; Признак ошбки при расшифровке torrent-файла.
  ErrorString.s        ; Описание ошибки (чаще всего - имя файла, при работе с которым произошла ошибка).
EndStructure


Procedure.s TorrentFiles_GetBencoding_String(*TorrentMem, *M_Pos, MaxSize, encoding, *ErrFlag)
  Protected MemPos, Bytes, i
  Protected Err.b, Char.a, String.s
  
  String=""
  Err = #False
  MemPos = PeekI(*M_Pos)
  
  For i=MemPos To MemPos+18
    Char = PeekA(*TorrentMem+i)
    If Char=':'
      i+1
      Break
    ElseIf Char<'0' Or Char>'9'
      Err = #True
      Break
    EndIf
  Next i
  
  If Err = #False And Char=':' And i>MemPos+1 And i<=MemPos+18
    Bytes = Val(PeekS(*TorrentMem+MemPos, i-MemPos, #PB_Ascii))
    If Bytes>=0 And Bytes <= MaxSize-i
      MemPos + (i-MemPos)
      If Bytes>0
        String = PeekS(*TorrentMem+MemPos, Bytes, encoding)
      Else
        String = ""
      EndIf
      MemPos + Bytes
      PokeI(*M_Pos, MemPos)
    Else
      Err = #True
    EndIf
  Else
    Err = #True
  EndIf
  
  If Err = #True
    PokeB(*ErrFlag, 1)
  EndIf
    
  ProcedureReturn String
EndProcedure

Procedure.q TorrentFiles_GetBencoding_Int(*TorrentMem, *M_Pos, MaxSize, *ErrFlag)
  Protected MemPos, Int.q, i
  Protected Err.b, Char.a
  
  Int = 0
  Err = #False
  MemPos = PeekI(*M_Pos)
  Char = PeekA(*TorrentMem+MemPos)
  If Char='i' Or Char='I'
    MemPos+1
    For i=MemPos To MemPos+18
      Char = PeekA(*TorrentMem+i)
      If Char='e' Or Char='E'
        i+1
        Break
      ElseIf (Char<'0' Or Char>'9') And Char<>'-'
        Err = #True
        Break
      EndIf
    Next i
    
    If Err = #False And i-MemPos-1 > 0 And (Char='e' Or Char='E') And i<=MemPos+18
      Int = Val(PeekS(*TorrentMem+MemPos, i-MemPos-1, #PB_Ascii))
      MemPos = i
      PokeI(*M_Pos, MemPos)
    Else
      Err = #True
    EndIf
  EndIf
  
  If Err = #True
    PokeB(*ErrFlag, 1)
  EndIf
  
  ProcedureReturn Int
EndProcedure

Procedure.a TorrentFiles_GetBencoding_Pieces(*Torrent.TorrentFiles_TorrentInfo, *TorrentMem, *M_Pos, MaxSize)
  Protected MemPos, String.s, i
  Protected Bytes, Result.a, Char.a, EndData
  Protected x, y
  
  String=""
  
  Result = #True
  MemPos = PeekI(*M_Pos)
  
  For i=MemPos To MemPos+18
    Char = PeekA(*TorrentMem+i)
    If Char=':'
      i+1
      Break
    ElseIf Char<'0' Or Char>'9'
      Result = #False
      Break
    EndIf
  Next i
  
  If Result = #True And i>MemPos+1 And Char=':' And i<=MemPos+18
    Bytes = Val(PeekS(*TorrentMem+MemPos, i-MemPos, #PB_Ascii))
    If Bytes>0 And Bytes < MaxSize-i
      If Bytes % 20 = 0
        ReDim *Torrent\pieces(Bytes/20)
        MemPos + (i-MemPos)
        EndData = MemPos + Bytes - 20
        
        x = 0
        For i=MemPos To EndData Step 20
          CopyMemory(*TorrentMem+i, @*Torrent\pieces(x)\SHA1_bin, 20)
          String=""
          For y=i To i+19
            String+RSet(Hex(PeekA(*TorrentMem+y),#PB_Ascii), 2, "0")
          Next y
          *Torrent\pieces(x)\SHA1_string = LCase(String)
          x+1
        Next i
        
        PokeI(*M_Pos, MemPos + Bytes)
      Else
        Result = #False
      EndIf
    Else
     Result = #False
    EndIf
  Else
    Result = #False
  EndIf
  
  ProcedureReturn Result
EndProcedure


Procedure.b TorrentFiles_Bencode_D_Decoder(Comand.s, *Parameter, *Torrent.TorrentFiles_TorrentInfo, *Temp_f)
  Protected Result.b
  
  Result = #True
  
  If Comand<>""
    Select LCase(Comand)
      Case "created by"
        *Torrent\created_by = PeekS(*Parameter)
        
      Case "creation date"
        *Torrent\creation_date = PeekL(*Parameter)
        
      Case "encoding"
        Select LCase(PeekS(*Parameter))
          Case "ascii", "ansi"
            *Torrent\encoding = #PB_Ascii
          Case "utf-8", "utf 8"
            *Torrent\encoding = #PB_UTF8
          Case "unicode"
            *Torrent\encoding = #PB_Unicode
        EndSelect
        
      Case "comment"
        *Torrent\comment = PeekS(*Parameter)
        
      Case "announce"
        *Torrent\announce = PeekS(*Parameter)
        
      Case "announce-list"
        AddElement(*Torrent\announce_list())
        *Torrent\announce_list() = PeekS(*Parameter)
        
      Case "length"
        If PeekB(*Temp_f)=0
          
          If ListSize(*Torrent\files())>0
            LastElement(*Torrent\files())
          EndIf
          
          If AddElement(*Torrent\files()) = 0
            *Torrent\ErrorCode = 5
            Result = #False
            ProcedureReturn Result
          EndIf
          PokeB(*Temp_f, 1)
        EndIf
        *Torrent\files()\length = PeekQ(*Parameter)
        
      Case "path"
        If *Torrent\TypeDir = #True
          If ListSize(*Torrent\files())>0
            LastElement(*Torrent\files())
            If AddElement(*Torrent\files()\path())
              *Torrent\files()\path() = PeekS(*Parameter)
            Else
              *Torrent\ErrorCode = 5
              Result = #False
            EndIf
          Else
            Result = #False
          EndIf
        Else
          Result = #False ; Если это не папка, то чего присутсвует "path"? Значит ошибка.
        EndIf
 
      Case "name"
        If *Torrent\TypeDir = #True ; Много файлов (папка).
          *Torrent\CurrentDir_Name = PeekS(*Parameter)
        Else                       ; Один файл.
          If PeekB(*Temp_f)=0
            If AddElement(*Torrent\files()) = 0
              *Torrent\ErrorCode = 5
              Result = #False
              ProcedureReturn Result
            EndIf
            PokeB(*Temp_f, 1)
          EndIf
          
          If AddElement(*Torrent\files()\path())
            *Torrent\files()\path() = PeekS(*Parameter)
          Else
            *Torrent\ErrorCode = 5
            Result = #False
          EndIf
        EndIf
        
      Case "piece length"
        *Torrent\piece_length = PeekL(*Parameter)
        
      Case "private"
        If PeekQ(*Parameter) = 1
          *Torrent\private = 1
        EndIf
        
      Case "publisher"
        *Torrent\Publisher = PeekS(*Parameter)

      Case "publisher-url"
        *Torrent\Publisher_Url = PeekS(*Parameter)
        
    EndSelect
  EndIf

ProcedureReturn Result
EndProcedure

Procedure TorrentFiles_LoadTorrent_CheckErr(*Torrent.TorrentFiles_TorrentInfo) ; Проверка на ошибки данных torrent-файла.
  Protected Result, F_Size.q, A_size, l_size
  
  Result = #False
  F_Size = 0
  l_size=ListSize(*Torrent\files())
  If l_size>0
    If ListSize(*Torrent\files()\path())>0
      If *Torrent\INFO_Hash<>""
        A_size = ArraySize(*Torrent\pieces())
        If A_size > 0
          ForEach *Torrent\files()
            F_Size + *Torrent\files()\length
          Next
          
          If *Torrent\piece_length >= 16384 And F_Size =< *Torrent\piece_length*A_size And F_Size >= *Torrent\piece_length*(A_size-1)
            *Torrent\All_Size = F_Size
            If *Torrent\TypeDir = #True ; В торренте папка.
              Result = #True
            Else                        ; В торренте файл.
              *Torrent\TypeDir = #False
              If l_size = 1 And ListSize(*Torrent\files()\path()) = 1 ; Поскольку в торренте файл, то должна быть только одна запись о файле.
                Result = #True
              EndIf
            EndIf
          EndIf
        EndIf
      EndIf
    EndIf
  EndIf

  ProcedureReturn Result
EndProcedure

Procedure TorrentFiles_BencodeParser(deep.l, Command.a,  MaxSize, ComString.s, *TorrentMem, *Torrent.TorrentFiles_TorrentInfo, *PosMem, *ErrState)
  Protected Char.a, State_D.b, Temp_f.b, MemPos
  Protected qVar.q, String.s, SubErr.b, Info_pos
  
  If deep>=20 Or PeekB(*ErrState)<>0
    ProcedureReturn
  EndIf
  
  State_D=0
  MemPos = PeekI(*PosMem)
  Temp_f = 0
  SubErr = 0
  Info_pos = 0
  
  Repeat 
    Char = PeekA(*TorrentMem + MemPos)
   
    Select Char
      Case 'd', 'D' ; Найдена директива.
        MemPos + 1     
        TorrentFiles_BencodeParser(deep+1, 'd',  MaxSize, ComString, *TorrentMem, *Torrent, @MemPos, *ErrState)
        State_D = 0 : Temp_f = 0 
        
        If Info_pos>0 And LCase(ComString) = "info"
          If Info_pos < MemPos
            *Torrent\INFO_Hash = SHA1Fingerprint(*TorrentMem+Info_pos, MemPos-Info_pos)
          Else
            PokeB(*ErrState, 1)
          EndIf
        EndIf

      Case 'l', 'L' ; Найден список.
        MemPos + 1
        TorrentFiles_BencodeParser(deep+1, 'l',  MaxSize, ComString, *TorrentMem, *Torrent, @MemPos, *ErrState)
        State_D = 0 : Temp_f = 0 
          
      Case 'i', 'I' ; Найдено число (в символьном виде).
        If Command='d'
          SubErr = 0
          qVar = TorrentFiles_GetBencoding_Int(*TorrentMem, @MemPos, MaxSize, @SubErr)
          If SubErr = 0
            If State_D <> 0 
              State_D = 0
              If TorrentFiles_Bencode_D_Decoder(ComString, @qVar, *Torrent, @Temp_f) = #False
                PokeB(*ErrState, 1)
              EndIf
            EndIf
          Else
            PokeB(*ErrState, 1)
          EndIf
          
        ElseIf Command='l'
          If TorrentFiles_Bencode_D_Decoder(ComString, @qVar, *Torrent, @Temp_f) = #False
            PokeB(*ErrState, 1)
          EndIf
        EndIf
        
      Case '0' To '9' ; Найдена строка.
        If State_D = 0 Or  LCase(ComString)<>"pieces"
          
          SubErr = 0
          String=TorrentFiles_GetBencoding_String(*TorrentMem, @MemPos, MaxSize, *Torrent\encoding, @SubErr)
          If SubErr = 0
            If Command='d'
              
              If LCase(String)="files" And LCase(ComString)="info"
                *Torrent\TypeDir = #True
                State_D = 0
              Else  
                If State_D = 0 And String<>""
                  State_D = 1
                  ComString = String
                  If LCase(ComString)="info"
                    Info_pos = MemPos
                  EndIf              
                Else
                  State_D = 0
                  If TorrentFiles_Bencode_D_Decoder(ComString, @String, *Torrent, @Temp_f) = #False
                    PokeB(*ErrState, 1)
                  EndIf
                                    
                  ComString = ""
                EndIf
              EndIf
              
            ElseIf Command='l'
              If TorrentFiles_Bencode_D_Decoder(ComString, @String, *Torrent, @Temp_f) = #False
                PokeB(*ErrState, 1)
              EndIf
            EndIf
          Else
            PokeB(*ErrState, 1)
          EndIf
          
        Else  ; SHA1 хеши.
          State_D = 0
          If TorrentFiles_GetBencoding_Pieces(*Torrent, *TorrentMem, @MemPos, MaxSize) = #False
            PokeB(*ErrState, 1)
          EndIf
                  
        EndIf
      
      Case 'e', 'E' ; Найдена завершающая команда.
        PokeI(*PosMem, MemPos+1)
        ProcedureReturn 
        
      Default
        MemPos + 1
        PokeB(*ErrState, 1)
    EndSelect
    
    If PeekB(*ErrState)<>0
      PokeI(*PosMem, MemPos)
      ProcedureReturn
    EndIf
 
  Until deep>=20 Or MemPos>MaxSize
  
  If deep>=20
    PokeI(*PosMem, MemPos)
  ElseIf MemPos>MaxSize And deep>0
    PokeI(*PosMem, MemPos)
  EndIf
  
EndProcedure

Procedure TorrentFiles_LoadTorrentFile(TorrentFile.s, *Torrent.TorrentFiles_TorrentInfo)
  Protected Result.b, Err.b, File_t, FileSize.q
  Protected *TorrentMem,MemPos, Char.a, FileSize_t.q
  Protected NewList CommandInfo.a(), deep
  
  Result = #False
  Err    = #False
  deep = 0       ; Глубина рекурсии.
  
  ClearStructure(*Torrent, TorrentFiles_TorrentInfo)
  ClearList(CommandInfo())
  NewList *Torrent\announce_list()
  NewList *Torrent\files()
  Dim *Torrent\pieces(0)
  
  *Torrent\ErrorCode = 0
  *Torrent\encoding = #PB_UTF8
  *Torrent\TypeDir = #False
  *TorrentMem = 0
  File_t = 0
  
  File_t = ReadFile(#PB_Any, TorrentFile)
  If File_t
    FileSize = Lof(File_t)
    If FileSize>0 And FileSize<20000000
      *TorrentMem = AllocateMemory(FileSize+10)
      If *TorrentMem
        FillMemory(*TorrentMem, FileSize+8, 0)
        If ReadData(File_t, *TorrentMem, FileSize) <> FileSize
          Err = #True
          *Torrent\ErrorCode = 1 ; Число считанных байт не равно размеру файла.
        EndIf
      Else
        Err = #True
        *Torrent\ErrorCode = 2 ; Ошибка выделения памяти.
      EndIf
    Else
      Err = #True
      *Torrent\ErrorCode = 3 ; Некорректный размер torrent-файла.
    EndIf
    CloseFile(File_t)
    File_t = 0
  Else
    Err = #True
    *Torrent\ErrorCode = 4 ; Не получилось открыть для чтения torrent-файл.
  EndIf
  
  If Err = #True
    *Torrent\ErrorString  = TorrentFile
    
    If *TorrentMem
      FreeMemory(*TorrentMem)
    EndIf
    
    If File_t
      CloseFile(File_t)
    EndIf
    
    FreeList(CommandInfo())
    ProcedureReturn 0
  EndIf
  
  MemPos=0
  FileSize_t = FileSize - 1
    
  TorrentFiles_BencodeParser(0, 0, FileSize_t, "", *TorrentMem, *Torrent, @MemPos, @Err)
  
  If Err = #False
    If TorrentFiles_LoadTorrent_CheckErr(*Torrent) = #True
      Result = #True
      If *Torrent\announce<>""
         Char=0
         ForEach *Torrent\announce_list()
           If *Torrent\announce_list() = *Torrent\announce
             Char=1
             Break
           EndIf
         Next
         
         If Char=0
           FirstElement(*Torrent\announce_list())
           If InsertElement(*Torrent\announce_list())
             *Torrent\announce_list() = *Torrent\announce
           EndIf
         EndIf
         
      EndIf
    EndIf
  EndIf
  
  If Result <> #True 
    *Torrent\ErrorString  = TorrentFile 
    If *Torrent\ErrorCode <> 5 : *Torrent\ErrorCode = 6 : EndIf
  EndIf
    
  If *TorrentMem
    FreeMemory(*TorrentMem)
  EndIf
  
  FreeList(CommandInfo())
    
  ProcedureReturn Result
EndProcedure

Procedure TorrentFiles_LoadTorrentFile_ShowEror(ErrorCode.a, Err_String.s="", ProgName.s="")
  Protected ErrorString.s
  If ErrorCode>0
    If ProgName<>"" : ProgName + " —  " : EndIf
    Select ErrorCode
      Case 1
        ErrorString = "Ошибка при чтении torrent-файла."+Chr(10)+Err_String
      Case 2
        ErrorString = "Ошибка при чтении torrent-файла (память)."+Chr(10)+Err_String
      Case 3
        ErrorString = "Некорректный размер torrent-файла."+Chr(10)+Err_String
      Case 4
        ErrorString = "Не получилось открыть для чтения torrent-файл."+Chr(10)+Err_String
      Case 5
        ErrorString = "Ошибка при выделении памяти под данные."+Chr(10)+Err_String
      Case 6
        ErrorString = "Ошибка в структуре torrent-файла."+Chr(10)+Err_String
    EndSelect
    MessageRequester(ProgName + "декодирование torrent-файла.", ErrorString, #MB_ICONWARNING)
  EndIf
EndProcedure



; Эта процедура вызывается для создания тррент файла по уже известным данным.
Procedure.b TorrentFiles_CreateSysFile_Torrent(FileName.s, *TorrentInfo.TorrentFiles_TorrentInfo)
  Protected File_t, Result.b, Err, SizeArray
  Protected *SHA1_mem, i, Count, Char_b.a
  Protected String.s, Pos
  Protected Pieces_CB, ListSize
    
  Result = #False
  Err    = #False
  
  *SHA1_mem = AllocateMemory(32)
  If *SHA1_mem = 0
    *TorrentInfo\ErrorCode = 3
    ProcedureReturn 0
  EndIf
  
  File_t = CreateFile(#PB_Any, FileName)
  If File_t
    
    WriteByte(File_t,'d')
    
    If *TorrentInfo\announce<>""
      TorrentFiles_Bencoding_W_String(File_t, "announce")
      TorrentFiles_Bencoding_W_String(File_t, *TorrentInfo\announce)
    EndIf
    
    ListSize = ListSize(*TorrentInfo\announce_list())
    If ListSize>0
        TorrentFiles_Bencoding_W_String(File_t, "announce-list")
        WriteByte(File_t,'l')
        WriteByte(File_t,'l')
        ForEach *TorrentInfo\announce_list()
          TorrentFiles_Bencoding_W_String(File_t, *TorrentInfo\announce_list())
        Next
        WriteByte(File_t,'e')
        WriteByte(File_t,'e')
    EndIf
    
    If *TorrentInfo\comment<>""
      TorrentFiles_Bencoding_W_String(File_t, "comment")
      TorrentFiles_Bencoding_W_String(File_t, *TorrentInfo\comment)
    EndIf
    
    If *TorrentInfo\created_by<>""
      TorrentFiles_Bencoding_W_String(File_t, "created by")
      TorrentFiles_Bencoding_W_String(File_t, *TorrentInfo\created_by)
    EndIf
    
    TorrentFiles_Bencoding_W_String(File_t, "creation date") 
    TorrentFiles_Bencoding_W_Int(File_t, *TorrentInfo\creation_date)
    
    TorrentFiles_Bencoding_W_String(File_t, "encoding")
    TorrentFiles_Bencoding_W_String(File_t, "UTF-8")
    
    TorrentFiles_Bencoding_W_String(File_t, "info")
    
    WriteByte(File_t,'d')
        
    If *TorrentInfo\TypeDir = #True ; Добавляем папку
      
      If Err = #False
        ListSize = ListSize(*TorrentInfo\files())
        If ListSize>0
          TorrentFiles_Bencoding_W_String(File_t, "files")
          WriteByte(File_t,'l')
          ForEach *TorrentInfo\files()
            WriteByte(File_t,'d')
            TorrentFiles_Bencoding_W_String(File_t, "length")
            TorrentFiles_Bencoding_W_Int(File_t, *TorrentInfo\files()\length)
            TorrentFiles_Bencoding_W_String(File_t, "path")
            WriteByte(File_t,'l')
            ForEach *TorrentInfo\files()\path()
              TorrentFiles_Bencoding_W_String(File_t, *TorrentInfo\files()\path())
            Next
            WriteByte(File_t,'e')
            WriteByte(File_t,'e')
            
          Next
          WriteByte(File_t,'e')
          
          TorrentFiles_Bencoding_W_String(File_t, "name")
          TorrentFiles_Bencoding_W_String(File_t, *TorrentInfo\CurrentDir_Name)

        EndIf
      EndIf
      
    Else ; Добавляем только один файл
      
        SelectElement(*TorrentInfo\files(),0)
        TorrentFiles_Bencoding_W_String(File_t, "length")
        TorrentFiles_Bencoding_W_Int(File_t, *TorrentInfo\files()\length)
        
        SelectElement(*TorrentInfo\files()\path(),0)
        TorrentFiles_Bencoding_W_String(File_t, "name")
        TorrentFiles_Bencoding_W_String(File_t, *TorrentInfo\files()\path())

    EndIf 
    
    If Err = #False
      
      TorrentFiles_Bencoding_W_String(File_t, "piece length") ; Размер сегмента в байтах
      TorrentFiles_Bencoding_W_Int(File_t, *TorrentInfo\Piece_Length)
      
      TorrentFiles_Bencoding_W_String(File_t, "pieces")
      
      ; Создание хешей.
      SizeArray = ArraySize(*TorrentInfo\pieces())-1
      If SizeArray>=0
        WriteString(File_t, Str((SizeArray+1)*20)+":")
        For i=0 To SizeArray
          FillMemory(*SHA1_mem, 20, 0)
          For Pos=0 To 19
            PokeA(*SHA1_mem+Pos, *TorrentInfo\pieces(i)\SHA1_bin[Pos])
          Next Pos
          WriteData(File_t, *SHA1_mem, 20)
        Next i
      EndIf
      
      If *TorrentInfo\private = 1
        TorrentFiles_Bencoding_W_String(File_t, "private")
        TorrentFiles_Bencoding_W_Int(File_t, 1)
      EndIf
      
      WriteByte(File_t,'e')
      
      If *TorrentInfo\Publisher<>""
        TorrentFiles_Bencoding_W_String(File_t, "publisher")
        TorrentFiles_Bencoding_W_String(File_t, *TorrentInfo\Publisher)
      EndIf
      
      If *TorrentInfo\Publisher_Url<>""
        TorrentFiles_Bencoding_W_String(File_t, "publisher-url")
        TorrentFiles_Bencoding_W_String(File_t, *TorrentInfo\Publisher_Url)
      EndIf
      
      WriteByte(File_t,'e')
      If Err = #False
        Result = #True
      EndIf
    EndIf
    
    CloseFile(File_t)
    
  EndIf
  
  If Err = #True
    If FileSize(FileName)>=0
      DeleteFile(FileName)
    EndIf
  EndIf
  
  FreeMemory(*SHA1_mem)
 
  ProcedureReturn Result
EndProcedure

DisableExplicit

Создание торрент файла:

http://s004.radikal.ru/i205/1109/f1/c7b50b34bd65.png

Код:
; Создание торрент файла.
; Автор - Пётр
; https://purebasic.mybb.ru/viewtopic.php?id=249

XIncludeFile "TorrentFiles.pbi"

; Идентификаторы окон.
Enumeration
  #CreateTorrent_Win
EndEnumeration

; Идентификаторы гаджетов.
Enumeration
  ; Гаджеты окна "Создание торрента".
  
  #CreateTorrent_Text_0
  #CreateTorrent_Radio_File
  #CreateTorrent_Radio_Dir
  #CreateTorrent_String_Path
  #CreateTorrent_Button_Path
  #CreateTorrent_Text_5
  #CreateTorrent_String_TorrentFile
  #CreateTorrent_Button_TorrentFile
  #CreateTorrent_Frame3D_0
  #CreateTorrent_Text_1
  #CreateTorrent_String_Treker
  #CreateTorrent_Text_2
  #CreateTorrent_String_Comment
  #CreateTorrent_Text_3
  #CreateTorrent_CheckBox_Private
  #CreateTorrent_Combo_Piece
  #CreateTorrent_ProgressBar
  #CreateTorrent_Button_Start
  #CreateTorrent_CurrentFile
EndEnumeration

; Идентификаторы таймеров
Enumeration
  #CreateTorrent_Timer
EndEnumeration

Procedure CreateTorrentCB(File.s, Pos.f)
  Static Old_File.s, Old_Pos
  Protected Count, Temp
  
  If Old_File <> File
    Old_File = File
    If Len(File) > 40
      Count = CountString(File, "\")
      If Count > 2
        Temp=FindString(File, "\", 1)
        If Temp > 0
          Temp = FindString(File, "\", Temp+1)
          If Temp > 0
            File.s = Left(File, Temp)+"...\"+GetFilePart(File)
          EndIf
        EndIf
      EndIf
    EndIf 
    If IsGadget(#CreateTorrent_CurrentFile)
      SetGadgetText(#CreateTorrent_CurrentFile, File)
    EndIf
  EndIf
  
  If Round(Pos,#PB_Round_Down) <> Old_Pos
    Old_Pos = Pos ;Round(Pos,#PB_Round_Up)
    If IsGadget(#CreateTorrent_ProgressBar)
      SetGadgetState(#CreateTorrent_ProgressBar, Old_Pos)
    EndIf
  EndIf
EndProcedure


Path.s : String.s : Dir.s
Torrent.TorrentFiles_CreateInfo
S_Temp.s


If OpenWindow(#CreateTorrent_Win, 277, 288, 384, 374, "Cоздание торрента.",  #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered | #PB_Window_Invisible)
  TextGadget(#CreateTorrent_Text_0, 10, 10, 200, 15, "Путь к файлам:")
  OptionGadget(#CreateTorrent_Radio_File, 220, 10, 65, 15, "Файл")
  OptionGadget(#CreateTorrent_Radio_Dir, 295, 10, 75, 15, "Папка")
  StringGadget(#CreateTorrent_String_Path, 10, 30, 335, 20, "", #PB_String_ReadOnly)
  ButtonGadget(#CreateTorrent_Button_Path, 350, 30, 30, 20, "...")
  TextGadget(#CreateTorrent_Text_5, 10, 65, 335, 15, "Торрент файл:")
  StringGadget(#CreateTorrent_String_TorrentFile, 10, 85, 335, 20, "", #PB_String_ReadOnly)
  ButtonGadget(#CreateTorrent_Button_TorrentFile, 350, 85, 30, 20, "...")
  Frame3DGadget(#CreateTorrent_Frame3D_0, 15, 120, 355, 205, "Свойства торрента")
  TextGadget(#CreateTorrent_Text_1, 25, 140, 335, 15, "Трекеры:")
  StringGadget(#CreateTorrent_String_Treker, 25, 160, 335, 74, "", #ES_MULTILINE|#WS_VSCROLL|#ES_AUTOVSCROLL)
  TextGadget(#CreateTorrent_Text_2, 25, 245, 330, 15, "Комментарий:")
  StringGadget(#CreateTorrent_String_Comment, 25, 265, 335, 20, "")
  TextGadget(#CreateTorrent_Text_3, 165, 300, 110, 15, "Размер частей:", #PB_Text_Right)
  CheckBoxGadget(#CreateTorrent_CheckBox_Private, 25, 300, 120, 15, "Частный торрент")
  ComboBoxGadget(#CreateTorrent_Combo_Piece, 280, 295, 80, 22)
  ProgressBarGadget(#CreateTorrent_ProgressBar, 15, 350, 265, 15, 0, 100, #PB_ProgressBar_Smooth)
  ButtonGadget(#CreateTorrent_Button_Start, 295, 340, 75, 25, "Создать")
  TextGadget(#CreateTorrent_CurrentFile, 15, 335, 265, 15, "")
  
  SetWindowLongPtr_(GadgetID(#CreateTorrent_CurrentFile),#GWL_STYLE, GetWindowLongPtr_(GadgetID(#CreateTorrent_CurrentFile),#GWL_STYLE)|#SS_LEFTNOWORDWRAP)
  SetGadgetState(#CreateTorrent_Radio_File, 1)
  
  AddGadgetItem(#CreateTorrent_Combo_Piece, -1, "Авто")
  AddGadgetItem(#CreateTorrent_Combo_Piece, -1, "16 КБ")
  AddGadgetItem(#CreateTorrent_Combo_Piece, -1, "32 КБ")
  AddGadgetItem(#CreateTorrent_Combo_Piece, -1, "64 КБ")
  AddGadgetItem(#CreateTorrent_Combo_Piece, -1, "128 КБ")
  AddGadgetItem(#CreateTorrent_Combo_Piece, -1, "256 КБ")
  AddGadgetItem(#CreateTorrent_Combo_Piece, -1, "512 КБ")
  AddGadgetItem(#CreateTorrent_Combo_Piece, -1, "1 МБ")
  AddGadgetItem(#CreateTorrent_Combo_Piece, -1, "2 МБ")
  AddGadgetItem(#CreateTorrent_Combo_Piece, -1, "4 МБ")
  AddGadgetItem(#CreateTorrent_Combo_Piece, -1, "8 МБ")
  SetGadgetState(#CreateTorrent_Combo_Piece, 0)
  
  SetActiveGadget(#CreateTorrent_Radio_File)
  SendMessage_(WindowID(#CreateTorrent_Win), #WM_UPDATEUISTATE, $30002,0)
  
  HideWindow(#CreateTorrent_Win, 0)
  Thread_ID = 0
  
  Repeat
    Event = WaitWindowEvent()
    
    If Event = #PB_Event_Gadget And Thread_ID=0
      Select EventGadget()
        Case #CreateTorrent_Button_Path
          
          If GetGadgetState(#CreateTorrent_Radio_File) ; Файл
            Path = OpenFileRequester("","","Все файлы|*.*",0)
            If Path<>"" And FileSize(Path)>0
              SetGadgetText(#CreateTorrent_String_Path, Path)
            EndIf
          Else  ; Папка
            Path = PathRequester("Укажите путь к папке с файлами торрента.",Dir)
            If Path<>"" And FileSize(Path)= -2
              SetGadgetText(#CreateTorrent_String_Path, Path)
            EndIf
          EndIf
          
        Case #CreateTorrent_Button_TorrentFile
          Path = SaveFileRequester("","","Торрент-файлы (*.torrent)|*.torrent|Все файлы|*.*",0)
          If Path<>"" And SelectedFilePattern()>-1
            If SelectedFilePattern() = 0 And GetExtensionPart(Path)="" : Path+".torrent" : EndIf
            SetGadgetText(#CreateTorrent_String_TorrentFile, Path)
          EndIf
          
        Case #CreateTorrent_Radio_File, #CreateTorrent_Radio_Dir
          SetGadgetText(#CreateTorrent_String_Path, "")
          
        Case #CreateTorrent_Button_Start
          SetGadgetState(#CreateTorrent_ProgressBar, 0)
          
          ClearStructure(@Torrent, TorrentFiles_CreateInfo)
          NewList Torrent\announce()
          
          Torrent\Path = GetGadgetText(#CreateTorrent_String_Path)
          Torrent\FileName = GetGadgetText(#CreateTorrent_String_TorrentFile)
          If Torrent\Path<>"" And Torrent\FileName<>""
            
            String=GetGadgetText(#CreateTorrent_String_Treker)
            If String<>""
              String = ReplaceString(String, Chr(13), Chr(10))
              String = ReplaceString(String, Chr(10)+Chr(10), Chr(10))
              If String<>""
                String + Chr(10)
                Temp = CountString(String, Chr(10))
                For i=1 To Temp
                  S_Temp = StringField(String, i, Chr(10))
                  If S_Temp<>""
                    S_Temp=Trim(S_Temp)
                    S_Temp=RemoveString(S_Temp, Chr(9))
                    If S_Temp<>""
                      If AddElement(Torrent\announce())
                        Torrent\announce() =  S_Temp
                      Else
                        MessageRequester("Создание торрента.", "Ошибка выделения памяти!", #MB_OK|#MB_ICONERROR)
                        Break
                      EndIf
                    EndIf
                  EndIf
                Next i
              EndIf
            EndIf
            String="" : S_Temp=""
            
            Torrent\BreakThread = 0 ; Признак того, что не нужно прерывать создание торрент-файла.
            Torrent\ClientName = "MyTorrent 2.0"
            Torrent\comment = GetGadgetText(#CreateTorrent_String_Comment)
            Torrent\Directory = GetGadgetState(#CreateTorrent_Radio_Dir) & 1
            Torrent\ErrorCode = 0
            Torrent\ErrorString = ""
            Torrent\Result = 0
            Temp = GetGadgetState(#CreateTorrent_Combo_Piece)
            If Temp>0 And Temp<12
              Torrent\pieceLength = 16384 << (Temp-1)
            Else
              Torrent\pieceLength = 0
            EndIf
            Torrent\PiecesCB = @CreateTorrentCB()
            Torrent\private = GetGadgetState(#CreateTorrent_CheckBox_Private) & 1
            Torrent\ProgName = "MyTorrent 2.0"
            
            Thread_ID = CreateThread(@TorrentFiles_CreateTorrent(), @Torrent)
            If Thread_ID
              AddWindowTimer(#CreateTorrent_Win, #CreateTorrent_Timer, 400)
            Else
              MessageRequester("Создание торрента.", "Ошибка при создании потока.", #MB_OK|#MB_ICONWARNING)
            EndIf
            
          Else
            MessageRequester("Создание торрента.", "Укажите путь к файлам.", #MB_OK|#MB_ICONWARNING)
          EndIf
      EndSelect
      
      
    ElseIf Event = #PB_Event_CloseWindow
      If Thread_ID <> 0 And IsThread(Thread_ID)
        If MessageRequester("Создание торрента.", "Торрент файл в процессе создания."+Chr(10)+"Прервать?", #MB_YESNO|#MB_ICONQUESTION|#MB_DEFBUTTON2) = #IDYES
          Torrent\BreakThread = 1 ; Прерываем создание файла.
          RemoveWindowTimer(#CreateTorrent_Win, #CreateTorrent_Timer)
          For i=1 To 100
            Delay(100)
            WindowEvent()
            If IsThread(Thread_ID)=0
              Break
            EndIf
          Next i
          
          If IsThread(Thread_ID)
            KillThread(Thread_ID)
          EndIf
          Thread_ID = 0
          
          If FileSize(Torrent\FileName)>=0
            DeleteFile(Torrent\FileName)
          EndIf
          SetGadgetText(#CreateTorrent_CurrentFile, "")
          SetGadgetState(#CreateTorrent_ProgressBar, 0)
          MessageRequester("Создание торрента.", "Торрент файл не был создан - прервано по запросу пользователя.", #MB_OK|#MB_ICONWARNING)
        EndIf
      Else
        Break
      EndIf
      
    ElseIf Event = #PB_Event_Timer
      If EventTimer() = #CreateTorrent_Timer
        If IsThread(Thread_ID) = 0 ; Поток завершился.
          RemoveWindowTimer(#CreateTorrent_Win, #CreateTorrent_Timer)
          Thread_ID = 0
          If Torrent\Result = 1 And Torrent\ErrorCode=0
            MessageRequester("Создание торрента.", "Торрент-файл успешно создан.", #MB_OK|#MB_ICONINFORMATION)
          ElseIf Torrent\ErrorCode>0
            TorrentFiles_CreateTorrent_ShowError(Torrent\ErrorCode, Torrent\ErrorString, "MyTorrent 2.0")              
          EndIf
        EndIf
      EndIf
    EndIf
    
    
    
  ForEver 
  CloseWindow(#CreateTorrent_Win)
Else
  MessageRequester("", "Ошибка при создании окна", #MB_OK|#MB_ICONWARNING)
EndIf

Редактирование торрент-файла:

http://s52.radikal.ru/i136/1109/79/1f58a284c48f.png

Код:
; Загрузка и редактирование торрент файла.
; Автор - Пётр
; https://purebasic.mybb.ru/viewtopic.php?id=249

Enumeration
  #Window_0
EndEnumeration

;- Gadget Constants
;
Enumeration
  #Text_0
  #String_0
  #Button_0
  #Text_1
  #Editor_0
  #Text_2
  #String_1
  #Text_3
  #String_2
  #Text_6
  #String_3
  #Text_7
  #String_5
  #Text_8
  #String_6
  #Text_9
  #String_7
  #Text_10
  #String_8
  #Frame3D_0
  #Text_12
  #String_10
  #CheckBox_0
  #Text_14
  #String_11
  #ListIcon_0
  #Button_1
EndEnumeration

XIncludeFile "TorrentFiles.pbi"

Torrent.TorrentFiles_TorrentInfo
FileName.s

Procedure Open_Window_0()
  If OpenWindow(#Window_0, 243, 174, 428, 490, "Редактирование Torrent файла",  #PB_Window_SystemMenu | #PB_Window_Invisible | #PB_Window_TitleBar | #PB_Window_ScreenCentered )
    TextGadget(#Text_0, 5, 15, 40, 15, "Файл:")
    StringGadget(#String_0, 50, 10, 330, 20, "")
    ButtonGadget(#Button_0, 385, 10, 30, 20, "...")
    TextGadget(#Text_1, 5, 40, 75, 15, "Трекеры:")
    EditorGadget(#Editor_0, 5, 55, 410, 65)
    TextGadget(#Text_2, 5, 135, 110, 15, "Публикатор:")
    StringGadget(#String_1, 120, 130, 295, 20, "")
    TextGadget(#Text_3, 5, 160, 110, 15, "Адрес публикатора")
    StringGadget(#String_2, 120, 155, 295, 20, "")
    TextGadget(#Text_6, 5, 185, 110, 15, "Комментарий")
    StringGadget(#String_3, 120, 180, 295, 20, "")
    TextGadget(#Text_7, 5, 210, 110, 15, "Создано:")
    StringGadget(#String_5, 120, 205, 90, 20, "")
    TextGadget(#Text_8, 225, 210, 90, 15, "Дата создания:", #PB_Text_Right)
    StringGadget(#String_6, 320, 205, 95, 20, "", #PB_String_ReadOnly)
    TextGadget(#Text_9, 5, 235, 110, 15, "Размер, байт:")
    StringGadget(#String_7, 120, 230, 90, 20, "", #PB_String_ReadOnly)
    TextGadget(#Text_10, 225, 235, 90, 15, "Размер части:", #PB_Text_Right)
    StringGadget(#String_8, 320, 230, 95, 20, "", #PB_String_ReadOnly)
    Frame3DGadget(#Frame3D_0, 5, 255, 410, 194, "При редактировании изменится идентификатор торрента 'INFO Hash'!")
    TextGadget(#Text_12, 10, 280, 65, 15, "INFO Hash:")
    StringGadget(#String_10, 80, 275, 330, 20, "", #PB_String_ReadOnly)
    CheckBoxGadget(#CheckBox_0, 300, 304, 110, 15, "Частный торрент")
    TextGadget(#Text_14, 10, 306, 94, 15, "Корневая папка:")
    StringGadget(#String_11, 108, 300, 180, 20, "")
    ListIconGadget(#ListIcon_0, 10, 330, 400, 110, "Файл", 290, #PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect)
    SendMessage_(GadgetID(#ListIcon_0), #LVM_SETEXTENDEDLISTVIEWSTYLE, #LVS_EX_LABELTIP, #LVS_EX_LABELTIP)  
    AddGadgetColumn(#ListIcon_0, 1, "Размер", 80)
    ButtonGadget(#Button_1, 330, 457, 80, 24, "Сохранить")
    
    SetActiveGadget(#Button_0)
    SendMessage_(WindowID(#Window_0), #WM_UPDATEUISTATE, $30002,0)
    
    HideWindow(#Window_0, 0)
  EndIf
EndProcedure


Procedure LoadTorrent(FileName.s, *Torrent.TorrentFiles_TorrentInfo)
  SetGadgetText(#String_0, FileName)
  If TorrentFiles_LoadTorrentFile(FileName, *Torrent) <> #True
    TorrentFiles_LoadTorrentFile_ShowEror(*Torrent\ErrorCode, *Torrent\ErrorString, "")
  Else
    ClearGadgetItems(#Editor_0)
    ForEach *Torrent\announce_list()
      AddGadgetItem(#Editor_0, -1, *Torrent\announce_list())
    Next
    SetGadgetText(#String_1, *Torrent\Publisher)
    SetGadgetText(#String_2, *Torrent\Publisher_Url)
    SetGadgetText(#String_3, *Torrent\comment)
    SetGadgetText(#String_5, *Torrent\created_by)
    SetGadgetText(#String_6, FormatDate("%dd.%mm.%yyyy %hh:%ii", *Torrent\creation_date))
    SetGadgetText(#String_7, Str(*Torrent\All_Size))
    SetGadgetText(#String_8, Str(*Torrent\piece_length))
    SetGadgetText(#String_10, *Torrent\INFO_Hash)
    SetGadgetText(#String_11, *Torrent\CurrentDir_Name)
    DisableGadget(#String_11, *Torrent\TypeDir!1)
    SetGadgetState(#CheckBox_0,*Torrent\private)
    ClearGadgetItems(#ListIcon_0)
    ForEach *Torrent\files()
      Count = ListSize(*Torrent\files()\path())
      If Count>0
        File.s=""
        x=0
        ForEach *Torrent\files()\path()
          x + 1
          File + *Torrent\files()\path()
          If x<Count
            File + "\"
          EndIf
        Next
        AddGadgetItem(#ListIcon_0, -1, File+Chr(10)+Str(*Torrent\files()\length))
      EndIf
    Next
  EndIf
EndProcedure

Procedure.b SeveTorrent(FileName.s, *Torrent.TorrentFiles_TorrentInfo)
  Protected Result.b=#False
  ClearList(*Torrent\announce_list())
  *Torrent\announce = ""
  Count = CountGadgetItems(#Editor_0)-1
  x=0
  For i=0 To Count
    String.s = GetGadgetItemText(#Editor_0, i)
    If String<>"" And RemoveString(String, " ")<>""
      If x=0
        x=1
        *Torrent\announce = String
      EndIf
      If AddElement(*Torrent\announce_list())
        *Torrent\announce_list() = String
      EndIf
    EndIf
  Next i
  *Torrent\Publisher = GetGadgetText(#String_1)
  *Torrent\Publisher_Url = GetGadgetText(#String_2)
  *Torrent\comment = GetGadgetText(#String_3)
  *Torrent\created_by = GetGadgetText(#String_5)
  If *Torrent\TypeDir = #True
    *Torrent\CurrentDir_Name = GetGadgetText(#String_11)
  EndIf
  *Torrent\private = GetGadgetState(#CheckBox_0)
  
  If TorrentFiles_CreateSysFile_Torrent(FileName, *Torrent) = #True
    Result=#True
    MessageRequester("", "Торрент файл успешно модифицирован.", #MB_OK|#MB_ICONINFORMATION)
  Else
    MessageRequester("", "Ошибка при модификации торрент файла.", #MB_OK|#MB_ICONWARNING)
  EndIf
  
  ProcedureReturn Result
EndProcedure

Open_Window_0()

Repeat
  Event = WaitWindowEvent()
  
  If Event = #PB_Event_Gadget
    Select EventGadget()
      Case #Button_0 ; Открытть торрент файл.
        FileName = OpenFileRequester("","","Торрент-файлы (*.torrent)|*.torrent|Все файлы|*.*",0)
        If FileName<>"" And FileSize(FileName)>0
          LoadTorrent(FileName, @Torrent)
        EndIf
        
        
      Case #Button_1 ; Сохранить торрент файл.
        
        If FileName<>"" And FileSize(FileName)>0
          If SeveTorrent(FileName, @Torrent) = #True
            LoadTorrent(FileName, @Torrent)
          EndIf
        Else
          MessageRequester("", "Укажите путь к торрент-файлу", #MB_OK|#MB_ICONWARNING)
        EndIf
        
    EndSelect
  EndIf
  
Until Event = #PB_Event_CloseWindow

Скачать файлы.

0

2

А скачать с торрент?

0

3

mirashic написал(а):

А скачать с торрент?

Это не просто скачивание с сервера как обычно, а обмен межу пирами.
Там очень много нюансов.
Смотри http://netall.ucoz.ru/publ/specifikacij … i/1-1-0-25
http://ru-torrents.com/faq/-BitTorrent-.php #entities

0

4

Я в курсе, пробовал вникнуть, читал, есть исходники на С+ а на PB не осилил и бросил до лучших времён, у буржуев тоже вроде нет ничего...

0

5

Одна из ссылок криво вставилась.
http://ru-torrents.com/faq/ спецификация-BitTorrent-протокола.php#entities

0

6

А сделайте в программе для создания торрентов поле для редактирования названия корневой папки. И поле сортировки файлов.

0

7

Переименовать папку перед созданием торрента, не вариант?

0


Вы здесь » PureBasic - форум » OpenSource » Создание и редактирование torrent файлов.