libcurl

Übersicht BlitzBasic DLLs und Userlibs

Neue Antwort erstellen

Thunder

Betreff: libcurl

BeitragFr, Nov 13, 2015 1:16
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo alle miteinander Very Happy

ich glaube das ist mein erster Eintrag hier. Eigentlich tu ich nichts mehr mit BB, aber heute hatte ich irgendwie (nicht ganz zufällig) Lust, ein libcurl Binding zu schreiben.
Also eine kleine feine API für BlitzBasic mit der man mit libcurl Sachen herunterladen kann.

Ich habe es gerade getestet und es _scheint_ zu funktionieren. Verbesserungsvorschläge, Fehlerreports etc sind gerne willkommen, Änderungen und eigene Versionen explizit erlaubt.

Starten wir Mal: Ich verwende das curl_easy_* interface. Leider braucht man da eine Callback-Funktion und BB unterstützt ja keine function pointer. Also habe ich die libcurl 7.45.0 geladen, selber etwas dazu programmiert und sie kompiliert.
Mein hinzugefügter Code ist folgender:
Code: [AUSKLAPPEN]
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <curl/curl.h>

struct Download {

   enum {
      DOWNLOAD_DEST_BUFFER,
      DOWNLOAD_DEST_FILE
   } dst;

   union {
      struct {
         char *buffer;
         size_t buffer_i, buffer_len;
      };
      struct {
         FILE *stream;
         const char *filename;
      };
   };
};

static size_t write_callback(void *buffer, size_t size, size_t nmemb, void *stream)
{
   if(stream == NULL)
      assert(0);

   struct Download *out = (struct Download *)stream;
   
   if (out->dst == DOWNLOAD_DEST_FILE){
      if(out->stream == NULL) {
         out->stream = fopen(out->filename, "wb");
         if (out->stream == NULL)
            return 0;
      }
      return fwrite(buffer, size, nmemb, out->stream);
   }else if(out->dst == DOWNLOAD_DEST_BUFFER){
      if(out->buffer == NULL){
         out->buffer_len = 4096;
         out->buffer = malloc(out->buffer_len);
         out->buffer_i = 0;
      }
      const size_t nlen = size*nmemb;
      if (nlen + out->buffer_i > out->buffer_len) {
         const size_t plus = nlen + 4096;
         char *nb = realloc(out->buffer, out->buffer_len + plus);
         if(nb == NULL)
            return 0;
         out->buffer = nb;
         out->buffer_len += plus;
      }
      memcpy(out->buffer+out->buffer_i, buffer, nlen);
      out->buffer_i += nlen;
      return nmemb;
   }else {
      assert(0);
   }
   
}

__declspec(dllexport) int curl_easy_download_file(CURL *handle, const char *url, const char *filename)
{
   struct Download dl = {
      .dst = DOWNLOAD_DEST_FILE,
      .filename = filename,
      .stream = NULL
   };
   curl_easy_setopt(handle, CURLOPT_URL, url);
   curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_callback);
   curl_easy_setopt(handle, CURLOPT_WRITEDATA, &dl);
   const int status = curl_easy_perform(handle) == 0 ? 1 : 0;
   fclose(dl.stream);

   return status;
}

__declspec(dllexport) int curl_easy_download_bank(CURL *handle, const char *url, void **dlptr)
{
   struct Download dl = {
      .dst = DOWNLOAD_DEST_BUFFER,
      .buffer = NULL,
   };
   curl_easy_setopt(handle, CURLOPT_URL, url);
   curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_callback);
   curl_easy_setopt(handle, CURLOPT_WRITEDATA, &dl);
   const int status = curl_easy_perform(handle) == 0 ? 1 : 0;
   
   *dlptr = malloc(sizeof(dl));
   if(*dlptr == NULL)
      return 0;
   memcpy(*dlptr, &dl, sizeof(dl));

   return status;
}

__declspec(dllexport) int32_t curl_easy_bank_size(struct Download *dlptr)
{
   return dlptr->buffer_i;
}

__declspec(dllexport) void curl_easy_move_bank(struct Download *dlptr, char *newbank)
{
   memcpy(newbank, dlptr->buffer, dlptr->buffer_i);
   free(dlptr->buffer);
   free(dlptr);
}


Decls:
Code: [AUSKLAPPEN]
.lib "libcurl.dll"

curl_easy_init%():"curl_easy_init"
curl_easy_cleanup(handle%):"curl_easy_cleanup"
curl_easy_download_file%(handle%, url$, filename$):"curl_easy_download_file"
curl_easy_download_bank%(handle%, url$, tmpbank*):"curl_easy_download_bank"
curl_easy_bank_size%(dlhandle%):"curl_easy_bank_size"
curl_easy_move_bank%(dlhandle%, bank*):"curl_easy_move_bank"


Und noch eine freundliche API als BlitzBasic-Funktionen:
BlitzBasic: [AUSKLAPPEN]

Type CurlHandle
Field hd
End Type

Function CurlSetup%()
hd = curl_easy_init()
If hd <> 0 Then
a.CurlHandle = New CurlHandle
a\hd = hd
End If
Return hd
End Function

Function CurlDownload%(hd%, url$, filename$)
Return curl_easy_download_file(hd, url, filename)
End Function

Function CurlDownloadBank%(hd%, url$)
tmp% = CreateBank(4)
status% = curl_easy_download_bank(hd, url, tmp)
If status = 0 Then FreeBank tmp:Return 0

dl% = PeekInt(tmp, 0)
FreeBank tmp

size% = curl_easy_bank_size(dl)
newbank% = CreateBank(size)
curl_easy_move_bank(dl, newbank)

Return newbank
End Function

Function CurlCleanup%(hd% = 0)
cleaned% = 0

If hd = 0 Then
For a.CurlHandle = Each CurlHandle
curl_easy_cleanup a\hd
Next
Delete Each CurlHandle
cleaned = 1
Else
For a.CurlHandle = Each CurlHandle
If a\hd = hd Then
curl_easy_cleanup a\hd
Delete a
cleaned = 1
Exit
EndIf
Next
End If

Return cleaned
End Function



Beispiel:
BlitzBasic: [AUSKLAPPEN]
LINK$ = "http://curl.haxx.se/libcurl/c/curl_easy_perform.html"

; Curl handle initialisieren
; muss nur einmal fürs ganze Programm gemacht werden
; danach muss dieser Handle immer an die Download Funktionen übergeben werden
Global curl = CurlSetup()

; Den LINK als Datei downloaden
CurlDownload curl, LINK, "C:/BlitzPlus/curl_easy_perform.html"

; Den LINK in eine Bank downloaden
Local bank% = CurlDownloadBank(curl, LINK)
For i% = 0 To BankSize(bank)-1
Write Chr(PeekByte(bank,i))
Next
FreeBank bank

; Am Ende des Programms oder wenn man aufhört, curl zu benutzen
; CurlCleanup aufrufen
CurlCleanup curl
curl = 0


Habe euch die DLL hier hochgeladen: https://www.blitzforum.de/upload/file.php?id=13083 (alte Version)
Ihr könnt sie mit den Änderungen von mir auch selber bauen, wenn euch das lieber ist.
Eine Standard-libcurl DLL kann man aber leider nicht verwenden.

30.09.2017 UPDATE version 7.54.1: https://drive.google.com/open?...XV2cmVCYWc
Habe ne neue Version von der libcurl.dll mit meinen Erweiterungen gebaut. Allerdings nicht mit BB getestet, daher bleibt die alte Version, bis ich weiß, dass die neue auch funktioniert.
Wenn möglich solltet ihr aktuelle Versionen verwenden, weil immer wieder Bugs gefunden und gefixt werden.

Viel Spaß beim Probieren

Edit: Meine Änderungen sind public domain (damit das klar ist).

Edit2: Ich habe leider einen furchtbaren Fehler gemacht und in den Funktionsdeklarationen nicht __stdcall benutzt, daher wird der Stack nach dem Funktionsaufruf auf die DLL nicht wieder reduziert. Das kann zu sehr mysteriösen Abstürzen führen! Ich werde das demnächst fixen.

Edit3: Problem gelöst. Die aktuellste Version auf google drive verwendet __stdcall Funktionen. ich lasse die alte Version aber noch drinnen, weil ich die neue nicht mit BB getestet habe.
Meine Sachen: https://bitbucket.org/chtisgit https://github.com/chtisgit

Neue Antwort erstellen


Übersicht BlitzBasic DLLs und Userlibs

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group