I want to present another solution which uses libcurl.dylib and imports the required functions. The libcurl.dylib doesn't need to be installed because it is contained in /usr/lib.
Code: Select all
EnableExplicit
#ServerFile = "http://purebasic.com/documentation/PureBasicSmall.pdf"
#CURL_ERROR_SIZE = 256
#CURLOPT_ERRORBUFFER = 10010
#CURLOPT_NOPROGRESS = 43
#CURLOPT_PROGRESSFUNCTION = 20056
#CURLOPT_URL = 10002
#CURLOPT_WRITEFUNCTION = 20011
ImportC "/usr/lib/libcurl.dylib"
curl_easy_cleanup(*CurlSession)
curl_easy_init()
curl_easy_setopt(*CurlSession, Option.I, Parameter.I)
curl_easy_strerror(ErrorNumber.I)
curl_easy_perform(*CurlSession)
EndImport
Define ClientFile.S = GetTemporaryDirectory() + "PureBasicSmall.pdf"
Define i.I
Define ReceivedData.S
Define ServerFile.S
ProcedureC DataReceivedCallback(*Data, Size.I, NMemb.I, *UserData)
WriteData(0, *Data, Size * NMemb)
ProcedureReturn Size * NMemb
EndProcedure
ProcedureC ProgressCallback(*ProgressData, DownloadTotal.D, DownloadNow.D,
UploadTotal.D, UploadNow.D)
Debug StrD(DownloadNow) + " Bytes from " + StrD(DownloadTotal) +
" Bytes have been downloaded"
EndProcedure
Procedure SetCurlOption(CurlSession.I, Option.I, Parameter.I)
CompilerSelect #PB_Compiler_Processor
CompilerCase #PB_Processor_x86
curl_easy_setopt(CurlSession, Option, Parameter)
CompilerCase #PB_Processor_x64
!EXTERN _curl_easy_setopt
!MOV RDI,QWORD [p.v_CurlSession]
!MOV RSI,QWORD [p.v_Option]
!MOV RDX,QWORD [p.v_Parameter]
!CALL _curl_easy_setopt
CompilerEndSelect
EndProcedure
Procedure DownloadFile(URL.S)
Shared ReceivedData.S
Protected CurlSession.I
Protected ErrorCode.I
Protected ErrorMsg.S = Space(#CURL_ERROR_SIZE)
Protected *ErrorMsgBuffer = AllocateMemory(#CURL_ERROR_SIZE)
Protected Result.I = #False
CurlSession = curl_easy_init()
If CurlSession
SetCurlOption(CurlSession, #CURLOPT_URL, @URL)
SetCurlOption(CurlSession, #CURLOPT_WRITEFUNCTION, @DataReceivedCallback())
SetCurlOption(CurlSession, #CURLOPT_ERRORBUFFER, *ErrorMsgBuffer)
SetCurlOption(CurlSession, #CURLOPT_PROGRESSFUNCTION, @ProgressCallback())
SetCurlOption(CurlSession, #CURLOPT_NOPROGRESS, #False)
ErrorCode = curl_easy_perform(CurlSession)
If ErrorCode = 0
Result = #True
Else
CompilerIf #PB_Compiler_Unicode
ErrorMsg = Space(StringByteLength(PeekS(*ErrorMsgBuffer, -1,
#PB_Ascii), #PB_Unicode))
PokeS(@ErrorMsg, PeekS(*ErrorMsgBuffer, -1, #PB_Ascii), -1, #PB_Unicode)
CompilerElse
ErrorMsg = PeekS(*ErrorMsgBuffer)
CompilerEndIf
If Trim(ErrorMsg) = ""
CompilerIf #PB_Compiler_Unicode
ErrorMsg = Space(StringByteLength(PeekS(curl_easy_strerror(ErrorCode),
-1, #PB_Ascii), #PB_Unicode))
PokeS(@ErrorMsg, PeekS(curl_easy_strerror(ErrorCode), -1, #PB_Ascii), -1,
#PB_Unicode)
CompilerElse
ErrorMsg = PeekS(curl_easy_strerror(ErrorCode))
CompilerEndIf
EndIf
MessageRequester("Error", ErrorMsg)
EndIf
FreeMemory(*ErrorMsgBuffer)
curl_easy_cleanup(CurlSession)
EndIf
ProcedureReturn Result
EndProcedure
If OpenFile(0, ClientFile)
If #PB_Compiler_Unicode
ServerFile = Space(StringByteLength(#ServerFile))
PokeS(@ServerFile, #ServerFile, -1, #PB_Ascii)
Else
ServerFile = #ServerFile
EndIf
If DownloadFile(ServerFile)
MessageRequester("HTTP-Download", "The file" + #CR$ + #CR$ + #ServerFile + #CR$ + #CR$ + "was downloaded successfully and stored as" + #CR$ + #CR$ + ClientFile)
EndIf
CloseFile(0)
EndIf
Update 1: I have modified the code to work in both ASCII and Unicode mode.
Update 2: I have added the new procedure SetCurlOption() which uses x64 assembly instructions (when compiled on a x64 processor) to correctly move the arguments into the correct registers and call curl_easy_setopt(). I have verified this code to successfully run on MacOS X Snow Leopard and Mavericks in x86 and x64 mode and in both ASCII and Unicode mode.