mirror of
https://gitlab.com/Theopse/fbi-i18n-zh.git
synced 2025-04-26 19:36:38 +08:00
Add compression support to HTTPC code.
This commit is contained in:
parent
c7708a4f40
commit
0404a33a58
@ -3,21 +3,35 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <3ds.h>
|
#include <3ds.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
|
|
||||||
#define HTTPC_TIMEOUT 15000000000
|
#define HTTPC_TIMEOUT 15000000000
|
||||||
|
|
||||||
Result http_open(httpcContext* context, const char* url, bool userAgent) {
|
struct http_context_s {
|
||||||
|
httpcContext httpc;
|
||||||
|
|
||||||
|
bool compressed;
|
||||||
|
z_stream inflate;
|
||||||
|
u8 buffer[32 * 1024];
|
||||||
|
u32 bufferSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
Result http_open(http_context* context, const char* url, bool userAgent) {
|
||||||
return http_open_ranged(context, url, userAgent, 0, 0);
|
return http_open_ranged(context, url, userAgent, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result http_open_ranged(httpcContext* context, const char* url, bool userAgent, u32 rangeStart, u32 rangeEnd) {
|
Result http_open_ranged(http_context* context, const char* url, bool userAgent, u32 rangeStart, u32 rangeEnd) {
|
||||||
if(context == NULL || url == NULL) {
|
if(url == NULL) {
|
||||||
return R_APP_INVALID_ARGUMENT;
|
return R_APP_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
http_context ctx = (http_context) calloc(1, sizeof(struct http_context_s));
|
||||||
|
if(ctx != NULL) {
|
||||||
char currUrl[1024];
|
char currUrl[1024];
|
||||||
strncpy(currUrl, url, sizeof(currUrl));
|
strncpy(currUrl, url, sizeof(currUrl));
|
||||||
|
|
||||||
@ -28,37 +42,53 @@ Result http_open_ranged(httpcContext* context, const char* url, bool userAgent,
|
|||||||
snprintf(range, sizeof(range), "%lu-", rangeStart);
|
snprintf(range, sizeof(range), "%lu-", rangeStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result res = 0;
|
|
||||||
|
|
||||||
bool resolved = false;
|
bool resolved = false;
|
||||||
u32 redirectCount = 0;
|
u32 redirectCount = 0;
|
||||||
while(R_SUCCEEDED(res) && !resolved && redirectCount < 32) {
|
while(R_SUCCEEDED(res) && !resolved && redirectCount < 32) {
|
||||||
if(R_SUCCEEDED(res = httpcOpenContext(context, HTTPC_METHOD_GET, currUrl, 1))) {
|
if(R_SUCCEEDED(res = httpcOpenContext(&ctx->httpc, HTTPC_METHOD_GET, currUrl, 1))) {
|
||||||
u32 response = 0;
|
u32 response = 0;
|
||||||
if(R_SUCCEEDED(res = httpcSetSSLOpt(context, SSLCOPT_DisableVerify))
|
if(R_SUCCEEDED(res = httpcSetSSLOpt(&ctx->httpc, SSLCOPT_DisableVerify))
|
||||||
&& (!userAgent || R_SUCCEEDED(res = httpcAddRequestHeaderField(context, "User-Agent", HTTP_USER_AGENT)))
|
&& (!userAgent || R_SUCCEEDED(res = httpcAddRequestHeaderField(&ctx->httpc, "User-Agent", HTTP_USER_AGENT)))
|
||||||
&& (rangeStart == 0 || R_SUCCEEDED(res = httpcAddRequestHeaderField(context, "Range", range)))
|
&& (rangeStart == 0 || R_SUCCEEDED(res = httpcAddRequestHeaderField(&ctx->httpc, "Range", range)))
|
||||||
&& R_SUCCEEDED(res = httpcSetKeepAlive(context, HTTPC_KEEPALIVE_ENABLED))
|
&& R_SUCCEEDED(res = httpcAddRequestHeaderField(&ctx->httpc, "Accept-Encoding", "gzip, deflate"))
|
||||||
&& R_SUCCEEDED(res = httpcBeginRequest(context))
|
&& R_SUCCEEDED(res = httpcSetKeepAlive(&ctx->httpc, HTTPC_KEEPALIVE_ENABLED))
|
||||||
&& R_SUCCEEDED(res = httpcGetResponseStatusCodeTimeout(context, &response, HTTPC_TIMEOUT))) {
|
&& R_SUCCEEDED(res = httpcBeginRequest(&ctx->httpc))
|
||||||
|
&& R_SUCCEEDED(res = httpcGetResponseStatusCodeTimeout(&ctx->httpc, &response, HTTPC_TIMEOUT))) {
|
||||||
if(response == 301 || response == 302 || response == 303) {
|
if(response == 301 || response == 302 || response == 303) {
|
||||||
redirectCount++;
|
redirectCount++;
|
||||||
|
|
||||||
memset(currUrl, '\0', sizeof(currUrl));
|
memset(currUrl, '\0', sizeof(currUrl));
|
||||||
if(R_SUCCEEDED(res = httpcGetResponseHeader(context, "Location", currUrl, sizeof(currUrl)))) {
|
if(R_SUCCEEDED(res = httpcGetResponseHeader(&ctx->httpc, "Location", currUrl, sizeof(currUrl)))) {
|
||||||
httpcCloseContext(context);
|
httpcCloseContext(&ctx->httpc);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resolved = true;
|
resolved = true;
|
||||||
|
|
||||||
if(response != 200) {
|
if(response == 200) {
|
||||||
|
char encoding[32];
|
||||||
|
if(R_SUCCEEDED(httpcGetResponseHeader(&ctx->httpc, "Content-Encoding", encoding, sizeof(encoding)))) {
|
||||||
|
bool gzip = strncmp(encoding, "gzip", sizeof(encoding)) == 0;
|
||||||
|
bool deflate = strncmp(encoding, "deflate", sizeof(encoding)) == 0;
|
||||||
|
|
||||||
|
ctx->compressed = gzip || deflate;
|
||||||
|
|
||||||
|
if(ctx->compressed) {
|
||||||
|
memset(&ctx->inflate, 0, sizeof(ctx->inflate));
|
||||||
|
if(deflate) {
|
||||||
|
inflateInit(&ctx->inflate);
|
||||||
|
} else if(gzip) {
|
||||||
|
inflateInit2(&ctx->inflate, MAX_WBITS | 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
res = R_APP_HTTP_ERROR_BASE + response;
|
res = R_APP_HTTP_ERROR_BASE + response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(R_FAILED(res)) {
|
if(R_FAILED(res)) {
|
||||||
httpcCloseContext(context);
|
httpcCloseContext(&ctx->httpc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,18 +97,43 @@ Result http_open_ranged(httpcContext* context, const char* url, bool userAgent,
|
|||||||
res = R_APP_HTTP_TOO_MANY_REDIRECTS;
|
res = R_APP_HTTP_TOO_MANY_REDIRECTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(R_FAILED(res)) {
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res = R_APP_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(R_SUCCEEDED(res)) {
|
||||||
|
*context = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result http_get_size(httpcContext* context, u32* size) {
|
Result http_close(http_context context) {
|
||||||
|
if(context == NULL) {
|
||||||
|
return R_APP_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(context->compressed) {
|
||||||
|
inflateEnd(&context->inflate);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result res = httpcCloseContext(&context->httpc);
|
||||||
|
free(context);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result http_get_size(http_context context, u32* size) {
|
||||||
if(context == NULL || size == NULL) {
|
if(context == NULL || size == NULL) {
|
||||||
return R_APP_INVALID_ARGUMENT;
|
return R_APP_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return httpcGetDownloadSizeState(context, NULL, size);
|
return httpcGetDownloadSizeState(&context->httpc, NULL, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result http_get_file_name(httpcContext* context, char* out, u32 size) {
|
Result http_get_file_name(http_context context, char* out, u32 size) {
|
||||||
if(context == NULL || out == NULL) {
|
if(context == NULL || out == NULL) {
|
||||||
return R_APP_INVALID_ARGUMENT;
|
return R_APP_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
@ -87,7 +142,7 @@ Result http_get_file_name(httpcContext* context, char* out, u32 size) {
|
|||||||
|
|
||||||
char* header = (char*) calloc(1, size + 64);
|
char* header = (char*) calloc(1, size + 64);
|
||||||
if(header != NULL) {
|
if(header != NULL) {
|
||||||
if(R_SUCCEEDED(res = httpcGetResponseHeader(context, "Content-Disposition", header, size + 64))) {
|
if(R_SUCCEEDED(res = httpcGetResponseHeader(&context->httpc, "Content-Disposition", header, size + 64))) {
|
||||||
char* start = strstr(header, "filename=");
|
char* start = strstr(header, "filename=");
|
||||||
if(start != NULL) {
|
if(start != NULL) {
|
||||||
char format[32];
|
char format[32];
|
||||||
@ -108,7 +163,7 @@ Result http_get_file_name(httpcContext* context, char* out, u32 size) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result http_read(httpcContext* context, u32* bytesRead, void* buffer, u32 size) {
|
Result http_read(http_context context, u32* bytesRead, void* buffer, u32 size) {
|
||||||
if(context == NULL || buffer == NULL) {
|
if(context == NULL || buffer == NULL) {
|
||||||
return R_APP_INVALID_ARGUMENT;
|
return R_APP_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
@ -116,21 +171,50 @@ Result http_read(httpcContext* context, u32* bytesRead, void* buffer, u32 size)
|
|||||||
Result res = 0;
|
Result res = 0;
|
||||||
|
|
||||||
u32 startPos = 0;
|
u32 startPos = 0;
|
||||||
if(R_SUCCEEDED(res = httpcGetDownloadSizeState(context, &startPos, NULL))) {
|
if(R_SUCCEEDED(res = httpcGetDownloadSizeState(&context->httpc, &startPos, NULL))) {
|
||||||
res = HTTPC_RESULTCODE_DOWNLOADPENDING;
|
res = HTTPC_RESULTCODE_DOWNLOADPENDING;
|
||||||
|
|
||||||
u32 outPos = 0;
|
u32 outPos = 0;
|
||||||
|
if(context->compressed) {
|
||||||
|
u32 lastPos = context->bufferSize;
|
||||||
while(res == HTTPC_RESULTCODE_DOWNLOADPENDING && outPos < size) {
|
while(res == HTTPC_RESULTCODE_DOWNLOADPENDING && outPos < size) {
|
||||||
if(R_SUCCEEDED(res = httpcReceiveDataTimeout(context, &((u8*) buffer)[outPos], size - outPos, HTTPC_TIMEOUT)) || res == HTTPC_RESULTCODE_DOWNLOADPENDING) {
|
if((context->bufferSize > 0
|
||||||
|
|| R_SUCCEEDED(res = httpcReceiveDataTimeout(&context->httpc, &context->buffer[context->bufferSize], sizeof(context->buffer) - context->bufferSize, HTTPC_TIMEOUT))
|
||||||
|
|| res == HTTPC_RESULTCODE_DOWNLOADPENDING)) {
|
||||||
Result posRes = 0;
|
Result posRes = 0;
|
||||||
u32 currPos = 0;
|
u32 currPos = 0;
|
||||||
if(R_SUCCEEDED(posRes = httpcGetDownloadSizeState(context, &currPos, NULL))) {
|
if(R_SUCCEEDED(posRes = httpcGetDownloadSizeState(&context->httpc, &currPos, NULL))) {
|
||||||
|
context->bufferSize += currPos - lastPos;
|
||||||
|
|
||||||
|
context->inflate.next_in = context->buffer;
|
||||||
|
context->inflate.next_out = buffer + outPos;
|
||||||
|
context->inflate.avail_in = context->bufferSize;
|
||||||
|
context->inflate.avail_out = size - outPos;
|
||||||
|
inflate(&context->inflate, Z_SYNC_FLUSH);
|
||||||
|
|
||||||
|
memcpy(context->buffer, context->buffer + (context->bufferSize - context->inflate.avail_in), context->inflate.avail_in);
|
||||||
|
context->bufferSize = context->inflate.avail_in;
|
||||||
|
|
||||||
|
lastPos = currPos;
|
||||||
|
outPos = size - context->inflate.avail_out;
|
||||||
|
} else {
|
||||||
|
res = posRes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while(res == HTTPC_RESULTCODE_DOWNLOADPENDING && outPos < size) {
|
||||||
|
if(R_SUCCEEDED(res = httpcReceiveDataTimeout(&context->httpc, &((u8*) buffer)[outPos], size - outPos, HTTPC_TIMEOUT)) || res == HTTPC_RESULTCODE_DOWNLOADPENDING) {
|
||||||
|
Result posRes = 0;
|
||||||
|
u32 currPos = 0;
|
||||||
|
if(R_SUCCEEDED(posRes = httpcGetDownloadSizeState(&context->httpc, &currPos, NULL))) {
|
||||||
outPos = currPos - startPos;
|
outPos = currPos - startPos;
|
||||||
} else {
|
} else {
|
||||||
res = posRes;
|
res = posRes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(res == HTTPC_RESULTCODE_DOWNLOADPENDING) {
|
if(res == HTTPC_RESULTCODE_DOWNLOADPENDING) {
|
||||||
res = 0;
|
res = 0;
|
||||||
@ -143,11 +227,3 @@ Result http_read(httpcContext* context, u32* bytesRead, void* buffer, u32 size)
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result http_close(httpcContext* context) {
|
|
||||||
if(context == NULL) {
|
|
||||||
return R_APP_INVALID_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return httpcCloseContext(context);
|
|
||||||
}
|
|
@ -6,9 +6,11 @@
|
|||||||
|
|
||||||
#define HTTP_CONNECT_TIMEOUT 15
|
#define HTTP_CONNECT_TIMEOUT 15
|
||||||
|
|
||||||
Result http_open(httpcContext* context, const char* url, bool userAgent);
|
typedef struct http_context_s* http_context;
|
||||||
Result http_open_ranged(httpcContext* context, const char* url, bool userAgent, u32 rangeStart, u32 rangeEnd);
|
|
||||||
Result http_get_size(httpcContext* context, u32* size);
|
Result http_open(http_context* context, const char* url, bool userAgent);
|
||||||
Result http_get_file_name(httpcContext* context, char* out, u32 size);
|
Result http_open_ranged(http_context* context, const char* url, bool userAgent, u32 rangeStart, u32 rangeEnd);
|
||||||
Result http_read(httpcContext* context, u32* bytesRead, void* buffer, u32 size);
|
Result http_close(http_context context);
|
||||||
Result http_close(httpcContext* context);
|
Result http_get_size(http_context context, u32* size);
|
||||||
|
Result http_get_file_name(http_context context, char* out, u32 size);
|
||||||
|
Result http_read(http_context context, u32* bytesRead, void* buffer, u32 size);
|
@ -227,11 +227,11 @@ Result task_download_sync(const char* url, u32* downloadedSize, void* buf, size_
|
|||||||
#else
|
#else
|
||||||
Result res = 0;
|
Result res = 0;
|
||||||
|
|
||||||
httpcContext context;
|
http_context context = NULL;
|
||||||
if(R_SUCCEEDED(res = http_open(&context, url, true))) {
|
if(R_SUCCEEDED(res = http_open(&context, url, true))) {
|
||||||
res = http_read(&context, downloadedSize, buf, size);
|
res = http_read(context, downloadedSize, buf, size);
|
||||||
|
|
||||||
Result closeRes = http_close(&context);
|
Result closeRes = http_close(context);
|
||||||
if(R_SUCCEEDED(res)) {
|
if(R_SUCCEEDED(res)) {
|
||||||
res = closeRes;
|
res = closeRes;
|
||||||
}
|
}
|
||||||
|
@ -37,10 +37,6 @@ static Result action_install_cdn_make_dst_directory(void* data, u32 index) {
|
|||||||
static Result action_install_cdn_open_src(void* data, u32 index, u32* handle) {
|
static Result action_install_cdn_open_src(void* data, u32 index, u32* handle) {
|
||||||
install_cdn_data* installData = (install_cdn_data*) data;
|
install_cdn_data* installData = (install_cdn_data*) data;
|
||||||
|
|
||||||
Result res = 0;
|
|
||||||
|
|
||||||
httpcContext* context = (httpcContext*) calloc(1, sizeof(httpcContext));
|
|
||||||
if(context != NULL) {
|
|
||||||
char url[256];
|
char url[256];
|
||||||
if(index == 0) {
|
if(index == 0) {
|
||||||
if(strlen(installData->tmdVersion) > 0) {
|
if(strlen(installData->tmdVersion) > 0) {
|
||||||
@ -52,32 +48,23 @@ static Result action_install_cdn_open_src(void* data, u32 index, u32* handle) {
|
|||||||
snprintf(url, 256, "http://ccs.cdn.c.shop.nintendowifi.net/ccs/download/%016llX/%08lX", installData->ticket->titleId, installData->contentIds[index - 1]);
|
snprintf(url, 256, "http://ccs.cdn.c.shop.nintendowifi.net/ccs/download/%016llX/%08lX", installData->ticket->titleId, installData->contentIds[index - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(R_SUCCEEDED(res = http_open(context, url, false))) {
|
return http_open((http_context*) handle, url, true);
|
||||||
*handle = (u32) context;
|
|
||||||
} else {
|
|
||||||
free(context);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res = R_APP_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result action_install_cdn_close_src(void* data, u32 index, bool succeeded, u32 handle) {
|
static Result action_install_cdn_close_src(void* data, u32 index, bool succeeded, u32 handle) {
|
||||||
return http_close((httpcContext*) handle);
|
return http_close((http_context) handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result action_install_cdn_get_src_size(void* data, u32 handle, u64* size) {
|
static Result action_install_cdn_get_src_size(void* data, u32 handle, u64* size) {
|
||||||
u32 downloadSize = 0;
|
u32 downloadSize = 0;
|
||||||
Result res = http_get_size((httpcContext*) handle, &downloadSize);
|
Result res = http_get_size((http_context) handle, &downloadSize);
|
||||||
|
|
||||||
*size = downloadSize;
|
*size = downloadSize;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result action_install_cdn_read_src(void* data, u32 handle, u32* bytesRead, void* buffer, u64 offset, u32 size) {
|
static Result action_install_cdn_read_src(void* data, u32 handle, u32* bytesRead, void* buffer, u64 offset, u32 size) {
|
||||||
return http_read((httpcContext*) handle, bytesRead, buffer, size);
|
return http_read((http_context) handle, bytesRead, buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result action_install_cdn_open_dst(void* data, u32 index, void* initialReadBlock, u64 size, u32* handle) {
|
static Result action_install_cdn_open_dst(void* data, u32 index, void* initialReadBlock, u64 size, u32* handle) {
|
||||||
|
@ -32,7 +32,7 @@ typedef struct {
|
|||||||
u64 currTitleId;
|
u64 currTitleId;
|
||||||
volatile bool n3dsContinue;
|
volatile bool n3dsContinue;
|
||||||
ticket_info ticketInfo;
|
ticket_info ticketInfo;
|
||||||
httpcContext* currContext;
|
http_context currContext;
|
||||||
char curr3dsxPath[FILE_PATH_MAX];
|
char curr3dsxPath[FILE_PATH_MAX];
|
||||||
|
|
||||||
data_op_data installInfo;
|
data_op_data installInfo;
|
||||||
@ -106,17 +106,8 @@ static Result action_install_url_open_src(void* data, u32 index, u32* handle) {
|
|||||||
|
|
||||||
Result res = 0;
|
Result res = 0;
|
||||||
|
|
||||||
httpcContext* context = (httpcContext*) calloc(1, sizeof(httpcContext));
|
if(R_SUCCEEDED(res = http_open(&installData->currContext, installData->urls[index], true))) {
|
||||||
if(context != NULL) {
|
*handle = (u32) installData->currContext;
|
||||||
if(R_SUCCEEDED(res = http_open(context, installData->urls[index], true))) {
|
|
||||||
*handle = (u32) context;
|
|
||||||
|
|
||||||
installData->currContext = context;
|
|
||||||
} else {
|
|
||||||
free(context);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res = R_APP_OUT_OF_MEMORY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -125,19 +116,19 @@ static Result action_install_url_open_src(void* data, u32 index, u32* handle) {
|
|||||||
static Result action_install_url_close_src(void* data, u32 index, bool succeeded, u32 handle) {
|
static Result action_install_url_close_src(void* data, u32 index, bool succeeded, u32 handle) {
|
||||||
((install_url_data*) data)->currContext = NULL;
|
((install_url_data*) data)->currContext = NULL;
|
||||||
|
|
||||||
return http_close((httpcContext*) handle);
|
return http_close((http_context) handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result action_install_url_get_src_size(void* data, u32 handle, u64* size) {
|
static Result action_install_url_get_src_size(void* data, u32 handle, u64* size) {
|
||||||
u32 downloadSize = 0;
|
u32 downloadSize = 0;
|
||||||
Result res = http_get_size((httpcContext*) handle, &downloadSize);
|
Result res = http_get_size((http_context) handle, &downloadSize);
|
||||||
|
|
||||||
*size = downloadSize;
|
*size = downloadSize;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result action_install_url_read_src(void* data, u32 handle, u32* bytesRead, void* buffer, u64 offset, u32 size) {
|
static Result action_install_url_read_src(void* data, u32 handle, u32* bytesRead, void* buffer, u64 offset, u32 size) {
|
||||||
return http_read((httpcContext*) handle, bytesRead, buffer, size);
|
return http_read((http_context) handle, bytesRead, buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user