+/* a CURLOPT_READFUNCTION that writes nothing. */
+size_t
+s3_empty_read_func(G_GNUC_UNUSED void *ptr, G_GNUC_UNUSED size_t size, G_GNUC_UNUSED size_t nmemb, G_GNUC_UNUSED void * stream)
+{
+ return 0;
+}
+
+size_t
+s3_empty_size_func(G_GNUC_UNUSED void *stream)
+{
+ return 0;
+}
+
+GByteArray*
+s3_empty_md5_func(G_GNUC_UNUSED void *stream)
+{
+ static const GByteArray empty = {(guint8 *) "", 0};
+
+ return s3_compute_md5_hash(&empty);
+}
+
+/* a CURLOPT_WRITEFUNCTION to write data that just counts data.
+ * s3_write_data should be NULL or a pointer to an gint64.
+ */
+size_t
+s3_counter_write_func(G_GNUC_UNUSED void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ gint64 *count = (gint64*) stream, inc = nmemb*size;
+
+ if (count) *count += inc;
+ return inc;
+}
+
+void
+s3_counter_reset_func(void *stream)
+{
+ gint64 *count = (gint64*) stream;
+
+ if (count) *count = 0;
+}
+
+#ifdef _WIN32
+/* a CURLOPT_READFUNCTION to read data from a file. */
+size_t
+s3_file_read_func(void *ptr, size_t size, size_t nmemb, void * stream)
+{
+ HANDLE *hFile = (HANDLE *) stream;
+ DWORD bytes_read;
+
+ ReadFile(hFile, ptr, (DWORD) size*nmemb, &bytes_read, NULL);
+ return bytes_read;
+}
+
+size_t
+s3_file_size_func(void *stream)
+{
+ HANDLE *hFile = (HANDLE *) stream;
+ DWORD size = GetFileSize(hFile, NULL);
+
+ if (INVALID_FILE_SIZE == size) {
+ return -1;
+ } else {
+ return size;
+ }
+}
+
+GByteArray*
+s3_file_md5_func(void *stream)
+{
+#define S3_MD5_BUF_SIZE (10*1024)
+ HANDLE *hFile = (HANDLE *) stream;
+ guint8 buf[S3_MD5_BUF_SIZE];
+ DWORD bytes_read;
+ MD5_CTX md5_ctx;
+ GByteArray *ret = NULL;
+
+ g_assert(INVALID_SET_FILE_POINTER != SetFilePointer(hFile, 0, NULL, FILE_BEGIN));
+
+ ret = g_byte_array_sized_new(S3_MD5_HASH_BYTE_LEN);
+ g_byte_array_set_size(ret, S3_MD5_HASH_BYTE_LEN);
+ MD5_Init(&md5_ctx);
+
+ while (ReadFile(hFile, buf, S3_MD5_BUF_SIZE, &bytes_read, NULL)) {
+ MD5_Update(&md5_ctx, buf, bytes_read);
+ }
+ MD5_Final(ret->data, &md5_ctx);
+
+ g_assert(INVALID_SET_FILE_POINTER != SetFilePointer(hFile, 0, NULL, FILE_BEGIN));
+ return ret;
+#undef S3_MD5_BUF_SIZE
+}
+
+GByteArray*
+s3_file_reset_func(void *stream)
+{
+ g_assert(INVALID_SET_FILE_POINTER != SetFilePointer(hFile, 0, NULL, FILE_BEGIN));
+}
+
+/* a CURLOPT_WRITEFUNCTION to write data to a file. */
+size_t
+s3_file_write_func(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ HANDLE *hFile = (HANDLE *) stream;
+ DWORD bytes_written;
+
+ WriteFile(hFile, ptr, (DWORD) size*nmemb, &bytes_written, NULL);
+ return bytes_written;
+}
+#endif
+