Code archives/Networking/Remote File Engine
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| Use the commands as you would reading local files :) Except that RemoteFileSize%(file%) can be used only on opened files. Supports HTTP and FTP protocols. Function list: file% = OpenRemoteFile%(url$[, port%, PostVariables$/FTPusername$, HTTPHeader$/FTPpassword$]) CloseRemoteFile(file%) EORF(file%) RemoteFileSize%(file%) - if no size known then it's -1 RemoteFileName$(file%) RemoteFileCode%(file%) - HTTP protocol only RemoteFileProtocol$(file%) ReadRemoteLine$(file%) ReadRemoteString$(file%) ReadRemoteInt%(file%) ReadRemoteShort%(file%) ReadRemoteByte%(file%) WriteRemoteBytes(file%, save%, offset%, count%) RemoteReadAvail(file%) Example:
Include "transporter.bb"
file% = OpenRemoteFile("http://battleempire.kylm.com/files/clip.avi")
save% = WriteFile("received.avi")
Graphics 400, 60, 32, 2
SetBuffer BackBuffer()
While Not KeyHit(1)
Cls
Text 10, 10, "Downloaded: " + total% + "/" + RemoteFileSize(file%) + "(" + (Int 100 * (Float total% / RemoteFileSize(file%))) + "%)"
If Not EORF(file%)
N% = WriteRemoteBytes(file%, save%, 0, RemoteReadAvail(file%))
total% = total% + N%
Else
Text 10, 30, "FINISHED!"
EndIf
Flip
Wend
CloseFile save%
CloseRemoteFile(file%)
| |||||
Global UserAgent$ = "Transporter" ; What ever you'd like to name your application
Global ResponseDelay% = 2000 ; How many millisecs to wait for HTTP response
Global NewLine$ = Chr(13) + Chr(10) ; Line break may differ
Const RFDebugMode% = False ; Debug mode
Type transporter
Field id%
Field code%
Field filename$
Field protocol$
End Type
Function OpenRemoteFile%(path$, port% = 80, variables$ = "", httpheader$ = "")
Local protocol$ = Lower(Sector$(path$, ":", 0))
Local host$ = Sector$(path$, "/", 2)
Local ip$ = "www." + Sector$(host$, ".", Sectors%(host$, ".") - 1) + "." + Sector$(host$, ".", Sectors%(host$, "."))
path$ = "/" + Sector$(path$, "/", 3, True)
Local header%, bank%, tim%, occ%
Local Stream% = OpenTCPStream(host$, port%)
If Not Stream% Then Stream% = OpenTCPStream(ip$, port%)
If Stream
Select protocol$
Case "http", "https" ; ---------------------------------------------------------------------------------------------------------------------------------------
; Send request
If Not Len(variables$) Then
WriteLine(Stream, "GET " + path$ + " HTTP/1.1")
Else
WriteLine(Stream, "POST " + path$ + " HTTP/1.1")
EndIf
WriteLine(Stream, "Host: " + host$)
WriteLine(Stream, "User-Agent: " + UserAgent$)
If Len(variables$) Then
WriteLine(Stream, "Content-Type: application/x-www-form-urlencoded")
WriteLine(Stream, "Content-Length: " + Len(variables$))
EndIf
If Len(httpheader$) Then WriteLine(Stream, httpheader$)
WriteLine(Stream, "Connection: Close")
WriteLine(Stream, "")
If Len(variables$) Then WriteLine(Stream, variables$)
; Debug mode
If RFDebugMode% Then
If Not Len(variables$) Then DebugLog ">>> GET " + path$ + " HTTP/1.1" Else DebugLog ">>> POST " + path$ + " HTTP/1.1"
DebugLog ">>> Host: " + host$
DebugLog ">>> User-Agent: " + UserAgent$
If Len(variables$) Then
DebugLog ">>> Content-Type: application/x-www-form-urlencoded"
DebugLog ">>> Content-Length: " + Len(variables$)
EndIf
If Len(httpheader$) Then DebugLog ">>> " + httpheader$
DebugLog ">>> Connection: Close"
DebugLog ">>> "
If Len(variables$) Then DebugLog ">>> " + variables$
EndIf
; Wait for response
tim = MilliSecs()
Repeat
Until (MilliSecs() - tim) => ResponseDelay% Or ReadAvail(Stream)
txt$ = ReadLine$(Stream%)
If RFDebugMode Then DebugLog "<<< " + txt$
If Sector$(txt$, " ", 0) = "HTTP/1.1" Or Sector$(txt$, " ", 0) = "HTTP/1.0"
code% = Int Sector$(txt$, " ", 1)
If (code% => 300) Then
CloseTCPStream Stream%
Return False
EndIf
EndIf
occ% = 0
header% = CreateBank(0)
bank% = CreateBank(12); Bank Int, Stream Int, Size Int
PokeInt(bank%, 0, header%)
PokeInt(bank%, 4, Stream%)
PokeInt(bank%, 8, -1)
this.transporter = New transporter
this\id% = bank%
this\code% = code%
this\filename$ = Sector$(path$, "/", Sectors%(path$, "/"))
this\protocol$ = "http"
; Received HTTP Header
Repeat
txt$ = ReadRemoteLine$(bank%)
value$ = Mid$(Sector$(txt$, ":", 1, True), 2)
If RFDebugMode Then DebugLog "<<< " + txt$
Select Sector$(txt$, ":", 0)
Case ""
Return bank%
Case "Content-Disposition"
For i = 0 To Sectors(value$, ";")
subtxt$ = Trim$(Sector$(value$, ";", i))
subvalue$ = Sector$(subtxt$, "=", 1)
Select Sector$(subtxt$, "=", 0)
Case "filename"
this\filename$ = subvalue$
DebugLog "[" + this\filename$ + "]"
End Select
Next
Case "Content-Length"
PokeInt bank%, 8, Int(value$)
End Select
Forever
Case "ftp" ; ---------------------------------------------------------------------------------------------------------------------------------------
header% = CreateBank(1)
bank% = CreateBank(16); Bank Int, Stream Int, Size Int
PokeInt(bank%, 0, header%)
PokeInt(bank%, 4, Stream%)
PokeInt(bank%, 8, -1)
PokeInt(bank%, 12, stream%)
this.transporter = New transporter
this\id% = bank%
this\code% = "0"
this\filename$ = Sector$(path$, "/", Sectors(path$, "/"))
this\protocol$ = "ftp"
; Wait for response
tim = MilliSecs()
Repeat
Until (MilliSecs() - tim) => ResponseDelay% Or ReadAvail(Stream)
Repeat
If ReadAvail(stream%)
txt$ = ReadLine(stream%)
code% = Int Sector$(txt$, " ", 0)
value$ = Mid$(Sector$(txt$, " ", 1, True), 1)
If RFDebugMode Then DebugLog "<<< " + txt$
Else
txt$ = "":code% = 0:value$ = "":cmd$ = ""
EndIf
If Not ReadAvail(stream%)
Select code%
Case 220
cmd$ = "USER " + variables$
Case 331
cmd$ = "PASS " + httpheader$
Case 230
cmd$ = "SIZE " + path$
Case 213
PokeInt(bank%, 8, Int value$)
cmd$ = "PASV"
Case 227
; Connect to PASV mode
txt$ = Sector(txt$, "(", 1)
host$ = Sector(txt$, ",", 0) + "." + Sector(txt$, ",", 1) + "." + Sector(txt$, ",", 2) + "." + Sector(txt$, ",", 3)
port% = (Int Sector(txt$, ",", 4)) * 256 + (Int Left$(Sector(txt$, ",", 5), Len(Sector(txt$, ",", 5)) - 1))
pasv_stream% = OpenTCPStream(host$, port%)
; Update stream
PokeInt(bank%, 4, pasv_stream%)
cmd$ = "RETR " + path$
Case 150
Return bank%
End Select
; ERROR
If code% => 400
If stream% Then CloseTCPStream stream%
If pasv_stream% Then CloseTCPStream pasv_stream%
If header% Then FreeBank header%
If bank% Then FreeBank bank%
Return 0
EndIf
EndIf
If Len(cmd$) Then
If RFDebugMode% Then DebugLog ">>> " + cmd$
WriteLine stream%, cmd$
EndIf
Forever
Return bank%
End Select
EndIf
End Function
Function CloseRemoteFile(bank%)
If PeekInt(bank%, 0) Then FreeBank PeekInt(bank%, 0)
If PeekInt(bank%, 4) Then CloseTCPStream PeekInt(bank%, 4)
If BankSize(bank%) = 18 Then If PeekInt(bank%, 12)
WriteLine PeekInt(bank%, 12), "BYE"
If RFDebugMode% Then DebugLog ">>> BYE"
CloseTCPStream PeekInt(bank%, 12)
EndIf
FreeBank bank%
For this.transporter = Each transporter
If this\id% = bank%
Delete this
Exit
EndIf
Next
End Function
Function EORF(bank%)
If Not PeekInt(bank%, 4)
If BankSize(PeekInt(bank%, 0)) = 0 Then Return True
Else
If Eof(PeekInt(bank%, 4)) Then Return True
EndIf
End Function
Function RemoteFileSize%(bank%)
Return PeekInt(bank%, 8)
End Function
Function RemoteFileName$(bank%)
For this.transporter = Each transporter
If this\id% = bank% Return this\filename$
Next
End Function
Function RemoteFileCode%(bank%)
For this.transporter = Each transporter
If this\id% = bank% Return this\code%
Next
End Function
Function RemoteFileProtocol$(bank%)
For this.transporter = Each transporter
If this\id% = bank% Return this\protocol$
Next
End Function
Function ReadRemoteLine$(bank%)
Local avail%, rbank% = PeekInt(bank%, 0), stream% = PeekInt(bank%, 4)
; Update bank
UpdateRemoteFile(bank%)
; Read line
txt$ = ""
For i = 0 To BankSize(rbank%) - 1
char% = PeekByte(rbank%, i)
txt$ = txt$ + Chr(char%)
If Right$(txt$, Len(NewLine$)) = NewLine$ Then Exit
Next
If Right$(txt$, 2) = NewLine$ Then
txt$ = Mid$(txt$, 1, Len(txt$) - Len(NewLine$))
ElseIf Right$(txt$, 1) = Right$(NewLine$, 1) Then
txt$ = Mid$(txt$, 1, Len(txt$) - (Len(NewLine$) - 1))
EndIf
; Resize bank
size% = BankSize(rbank%) - (Len(txt$) + Len(NewLine$))
If size% < 0 Then size% = 0
ResizeRemoteBank(bank%, size%)
Return txt$
End Function
Function ReadRemoteString$(bank%)
Local rbank% = PeekInt(bank%, 0)
UpdateRemoteFile(bank%)
a% = PeekInt(rbank%, 0)
txt$ = ""
For i = 0 To a% - 1
txt$ = txt$ + Chr(PeekByte(rbank%, 4 + i))
Next
ResizeRemoteBank(bank%, BankSize(rbank%) - (4 + a%))
Return txt$
End Function
Function ReadRemoteInt%(bank%)
Local rbank% = PeekInt(bank%, 0)
UpdateRemoteFile(bank%)
a% = PeekInt(rbank%, 0)
ResizeRemoteBank(bank%, BankSize(rbank%) - 4)
Return a%
End Function
Function ReadRemoteShort%(bank%)
Local rbank% = PeekInt(bank%, 0)
UpdateRemoteFile(bank%)
a% = PeekShort(rbank%, 0)
ResizeRemoteBank(bank%, BankSize(rbank%) - 2)
Return a%
End Function
Function ReadRemoteByte%(bank%)
Local rbank% = PeekInt(bank%, 0)
UpdateRemoteFile(bank%)
a% = PeekByte(rbank%, 0)
ResizeRemoteBank(bank%, BankSize(rbank%) - 1)
Return a%
End Function
Function WriteRemoteBytes(bank%, file%, offset%, count%)
Local rbank% = PeekInt(bank%, 0)
UpdateRemoteFile(bank%)
Local N% = WriteBytes(rbank%, file%, offset%, count%)
ResizeRemoteBank(bank%, BankSize(rbank%) - N%)
Return N%
End Function
Function RemoteReadAvail(bank%)
UpdateRemoteFile(bank%)
received% = BankSize(PeekInt(bank%, 0))
If PeekInt(bank%, 4) Then waiting% = ReadAvail(PeekInt(bank%, 4)) Else waiting% = 0
Return received% + waiting%
End Function
Function UpdateRemoteFile(bank%)
Local rbank% = PeekInt(bank%, 0), stream% = PeekInt(bank%, 4)
If stream% And rbank%
avail% = ReadAvail(stream%)
offset% = BankSize(rbank%)
ResizeBank(rbank%, offset% + avail%)
ReadBytes(rbank%, stream%, offset%, avail%)
If Eof(stream%) Then
CloseTCPStream stream%
PokeInt bank%, 4, 0
EndIf
EndIf
End Function
Function ResizeRemoteBank(bank%, size%)
Local rbank% = PeekInt(bank%, 0), start% = BankSize(rbank%) - size%
If BankSize(rbank%)
CopyBank(rbank%, start%, rbank%, 0, size%)
ResizeBank(rbank%, size%)
EndIf
End Function
Function Sector$(txt$, separator$, sector%, toend% = False)
Local result$ = "", occ
For i = 1 To Len(txt$)
If Mid$(txt$, i, 1) = separator$
occ = occ + 1
If toend% And occ% > sector% Then result$ = result$ + Mid$(txt$, i, 1)
Else
If occ => sector Then result$ = result$ + Mid$(txt$, i, 1)
EndIf
If Not toend% Then If occ > sector Then Exit
Next
Return result$
End Function
Function Sectors%(txt$, needle$)
occ% = 0
For i = 1 To Len(txt$) Step 1
If Instr(txt$, needle$, i)
occ% = occ% + 1
i = Instr(txt$, needle$, i)
Else
Exit
EndIf
Next
Return occ%
End Function |
Comments
| ||
| Good code. Works fine for me! |
| ||
| Fine and useful :) Keeper. |
| ||
| I get an error: "Invalid bank handle" when using the code you provided. |
Code Archives Forum