From 00bcc2a374151cf121b6f994a1b4b94611cc5c82 Mon Sep 17 00:00:00 2001
From: Tarmo Pikaro <tapika@yahoo.com>
Date: Thu, 4 Aug 2016 15:33:25 +0300
Subject: [PATCH] Windows: Unicode support (UTF-8 based). Changes made to
 static library only, not to front end command line tool.

---
 lib/curl_memory.h     |   18 +-
 lib/curl_setup_once.h |   14 +-
 lib/formdata.c        | 1586 ------------------------------------------------
 lib/formdata.cpp      | 1617 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/formdata.h        |   15 +
 lib/sendf.h           |    3 +
 lib/strdup.h          |    4 +
 lib/vtls/schannel.c   |    4 +
 lib/vtls/vtls.h       |    3 +
 9 files changed, 1668 insertions(+), 1596 deletions(-)
 delete mode 100644 lib/formdata.c
 create mode 100644 lib/formdata.cpp

diff --git a/lib/curl_memory.h b/lib/curl_memory.h
index 6f792ff..d2f491e 100644
--- a/lib/curl_memory.h
+++ b/lib/curl_memory.h
@@ -98,13 +98,19 @@ typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
 #define CURL_DID_MEMORY_FUNC_TYPEDEFS
 #endif
 
-extern curl_malloc_callback Curl_cmalloc;
-extern curl_free_callback Curl_cfree;
-extern curl_realloc_callback Curl_crealloc;
-extern curl_strdup_callback Curl_cstrdup;
-extern curl_calloc_callback Curl_ccalloc;
+#ifdef __cplusplus
+    #define CURL_EXTERN_C extern "C"
+#else
+    #define CURL_EXTERN_C extern
+#endif
+
+CURL_EXTERN_C curl_malloc_callback Curl_cmalloc;
+CURL_EXTERN_C curl_free_callback Curl_cfree;
+CURL_EXTERN_C curl_realloc_callback Curl_crealloc;
+CURL_EXTERN_C curl_strdup_callback Curl_cstrdup;
+CURL_EXTERN_C curl_calloc_callback Curl_ccalloc;
 #if defined(WIN32) && defined(UNICODE)
-extern curl_wcsdup_callback Curl_cwcsdup;
+CURL_EXTERN_C curl_wcsdup_callback Curl_cwcsdup;
 #endif
 
 #ifndef CURLDEBUG
diff --git a/lib/curl_setup_once.h b/lib/curl_setup_once.h
index 4da8349..3c68986 100644
--- a/lib/curl_setup_once.h
+++ b/lib/curl_setup_once.h
@@ -316,10 +316,16 @@ struct timeval {
  */
 
 #ifndef HAVE_BOOL_T
-  typedef enum {
-      bool_false = 0,
-      bool_true  = 1
-  } bool;
+    #if !defined(__cplusplus) || !defined(_MSC_VER)   
+        typedef enum {
+            bool_false = 0,
+            bool_true  = 1
+        } bool;
+    #else
+        // Visual studio compiler, C++. bool is built-in type, no need for enum.
+        #define bool_false 0
+        #define bool_true 1
+    #endif
 
 /*
  * Use a define to let 'true' and 'false' use those enums.  There
diff --git a/lib/formdata.c b/lib/formdata.c
deleted file mode 100644
index 673759d..0000000
--- a/lib/formdata.c
+++ /dev/null
@@ -1,1586 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#include <curl/curl.h>
-
-#ifndef CURL_DISABLE_HTTP
-
-#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
-#include <libgen.h>
-#endif
-
-#include "urldata.h" /* for struct Curl_easy */
-#include "formdata.h"
-#include "vtls/vtls.h"
-#include "strequal.h"
-#include "sendf.h"
-#include "strdup.h"
-/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
-
-#ifndef HAVE_BASENAME
-static char *Curl_basename(char *path);
-#define basename(x)  Curl_basename((x))
-#endif
-
-static size_t readfromfile(struct Form *form, char *buffer, size_t size);
-static char *formboundary(struct Curl_easy *data);
-
-/* What kind of Content-Type to use on un-specified files with unrecognized
-   extensions. */
-#define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
-
-#define FORM_FILE_SEPARATOR ','
-#define FORM_TYPE_SEPARATOR ';'
-
-#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
-#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
-#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
-#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
-#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
-#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
-#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
-
-/***************************************************************************
- *
- * AddHttpPost()
- *
- * Adds a HttpPost structure to the list, if parent_post is given becomes
- * a subpost of parent_post instead of a direct list element.
- *
- * Returns newly allocated HttpPost on success and NULL if malloc failed.
- *
- ***************************************************************************/
-static struct curl_httppost *
-AddHttpPost(char *name, size_t namelength,
-            char *value, curl_off_t contentslength,
-            char *buffer, size_t bufferlength,
-            char *contenttype,
-            long flags,
-            struct curl_slist* contentHeader,
-            char *showfilename, char *userp,
-            struct curl_httppost *parent_post,
-            struct curl_httppost **httppost,
-            struct curl_httppost **last_post)
-{
-  struct curl_httppost *post;
-  post = calloc(1, sizeof(struct curl_httppost));
-  if(post) {
-    post->name = name;
-    post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
-    post->contents = value;
-    post->contentlen = contentslength;
-    post->buffer = buffer;
-    post->bufferlength = (long)bufferlength;
-    post->contenttype = contenttype;
-    post->contentheader = contentHeader;
-    post->showfilename = showfilename;
-    post->userp = userp,
-    post->flags = flags | CURL_HTTPPOST_LARGE;
-  }
-  else
-    return NULL;
-
-  if(parent_post) {
-    /* now, point our 'more' to the original 'more' */
-    post->more = parent_post->more;
-
-    /* then move the original 'more' to point to ourselves */
-    parent_post->more = post;
-  }
-  else {
-    /* make the previous point to this */
-    if(*last_post)
-      (*last_post)->next = post;
-    else
-      (*httppost) = post;
-
-    (*last_post) = post;
-  }
-  return post;
-}
-
-/***************************************************************************
- *
- * AddFormInfo()
- *
- * Adds a FormInfo structure to the list presented by parent_form_info.
- *
- * Returns newly allocated FormInfo on success and NULL if malloc failed/
- * parent_form_info is NULL.
- *
- ***************************************************************************/
-static FormInfo * AddFormInfo(char *value,
-                              char *contenttype,
-                              FormInfo *parent_form_info)
-{
-  FormInfo *form_info;
-  form_info = calloc(1, sizeof(struct FormInfo));
-  if(form_info) {
-    if(value)
-      form_info->value = value;
-    if(contenttype)
-      form_info->contenttype = contenttype;
-    form_info->flags = HTTPPOST_FILENAME;
-  }
-  else
-    return NULL;
-
-  if(parent_form_info) {
-    /* now, point our 'more' to the original 'more' */
-    form_info->more = parent_form_info->more;
-
-    /* then move the original 'more' to point to ourselves */
-    parent_form_info->more = form_info;
-  }
-
-  return form_info;
-}
-
-/***************************************************************************
- *
- * ContentTypeForFilename()
- *
- * Provides content type for filename if one of the known types (else
- * (either the prevtype or the default is returned).
- *
- * Returns some valid contenttype for filename.
- *
- ***************************************************************************/
-static const char *ContentTypeForFilename(const char *filename,
-                                          const char *prevtype)
-{
-  const char *contenttype = NULL;
-  unsigned int i;
-  /*
-   * No type was specified, we scan through a few well-known
-   * extensions and pick the first we match!
-   */
-  struct ContentType {
-    const char *extension;
-    const char *type;
-  };
-  static const struct ContentType ctts[]={
-    {".gif",  "image/gif"},
-    {".jpg",  "image/jpeg"},
-    {".jpeg", "image/jpeg"},
-    {".txt",  "text/plain"},
-    {".html", "text/html"},
-    {".xml", "application/xml"}
-  };
-
-  if(prevtype)
-    /* default to the previously set/used! */
-    contenttype = prevtype;
-  else
-    contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
-
-  if(filename) { /* in case a NULL was passed in */
-    for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
-      if(strlen(filename) >= strlen(ctts[i].extension)) {
-        if(strequal(filename +
-                    strlen(filename) - strlen(ctts[i].extension),
-                    ctts[i].extension)) {
-          contenttype = ctts[i].type;
-          break;
-        }
-      }
-    }
-  }
-  /* we have a contenttype by now */
-  return contenttype;
-}
-
-/***************************************************************************
- *
- * FormAdd()
- *
- * Stores a formpost parameter and builds the appropriate linked list.
- *
- * Has two principal functionalities: using files and byte arrays as
- * post parts. Byte arrays are either copied or just the pointer is stored
- * (as the user requests) while for files only the filename and not the
- * content is stored.
- *
- * While you may have only one byte array for each name, multiple filenames
- * are allowed (and because of this feature CURLFORM_END is needed after
- * using CURLFORM_FILE).
- *
- * Examples:
- *
- * Simple name/value pair with copied contents:
- * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
- * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
- *
- * name/value pair where only the content pointer is remembered:
- * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
- * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
- * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
- *
- * storing a filename (CONTENTTYPE is optional!):
- * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
- * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
- * CURLFORM_END);
- *
- * storing multiple filenames:
- * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
- * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
- *
- * Returns:
- * CURL_FORMADD_OK             on success
- * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
- * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
- * CURL_FORMADD_NULL           if a null pointer was given for a char
- * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
- * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
- * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
- * CURL_FORMADD_MEMORY         if a HttpPost struct cannot be allocated
- * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
- * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
- *
- ***************************************************************************/
-
-static
-CURLFORMcode FormAdd(struct curl_httppost **httppost,
-                     struct curl_httppost **last_post,
-                     va_list params)
-{
-  FormInfo *first_form, *current_form, *form = NULL;
-  CURLFORMcode return_value = CURL_FORMADD_OK;
-  const char *prevtype = NULL;
-  struct curl_httppost *post = NULL;
-  CURLformoption option;
-  struct curl_forms *forms = NULL;
-  char *array_value=NULL; /* value read from an array */
-
-  /* This is a state variable, that if TRUE means that we're parsing an
-     array that we got passed to us. If FALSE we're parsing the input
-     va_list arguments. */
-  bool array_state = FALSE;
-
-  /*
-   * We need to allocate the first struct to fill in.
-   */
-  first_form = calloc(1, sizeof(struct FormInfo));
-  if(!first_form)
-    return CURL_FORMADD_MEMORY;
-
-  current_form = first_form;
-
-  /*
-   * Loop through all the options set. Break if we have an error to report.
-   */
-  while(return_value == CURL_FORMADD_OK) {
-
-    /* first see if we have more parts of the array param */
-    if(array_state && forms) {
-      /* get the upcoming option from the given array */
-      option = forms->option;
-      array_value = (char *)forms->value;
-
-      forms++; /* advance this to next entry */
-      if(CURLFORM_END == option) {
-        /* end of array state */
-        array_state = FALSE;
-        continue;
-      }
-    }
-    else {
-      /* This is not array-state, get next option */
-      option = va_arg(params, CURLformoption);
-      if(CURLFORM_END == option)
-        break;
-    }
-
-    switch (option) {
-    case CURLFORM_ARRAY:
-      if(array_state)
-        /* we don't support an array from within an array */
-        return_value = CURL_FORMADD_ILLEGAL_ARRAY;
-      else {
-        forms = va_arg(params, struct curl_forms *);
-        if(forms)
-          array_state = TRUE;
-        else
-          return_value = CURL_FORMADD_NULL;
-      }
-      break;
-
-      /*
-       * Set the Name property.
-       */
-    case CURLFORM_PTRNAME:
-#ifdef CURL_DOES_CONVERSIONS
-      /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
-       * the data in all cases so that we'll have safe memory for the eventual
-       * conversion.
-       */
-#else
-      current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
-#endif
-    case CURLFORM_COPYNAME:
-      if(current_form->name)
-        return_value = CURL_FORMADD_OPTION_TWICE;
-      else {
-        char *name = array_state?
-          array_value:va_arg(params, char *);
-        if(name)
-          current_form->name = name; /* store for the moment */
-        else
-          return_value = CURL_FORMADD_NULL;
-      }
-      break;
-    case CURLFORM_NAMELENGTH:
-      if(current_form->namelength)
-        return_value = CURL_FORMADD_OPTION_TWICE;
-      else
-        current_form->namelength =
-          array_state?(size_t)array_value:(size_t)va_arg(params, long);
-      break;
-
-      /*
-       * Set the contents property.
-       */
-    case CURLFORM_PTRCONTENTS:
-      current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
-    case CURLFORM_COPYCONTENTS:
-      if(current_form->value)
-        return_value = CURL_FORMADD_OPTION_TWICE;
-      else {
-        char *value =
-          array_state?array_value:va_arg(params, char *);
-        if(value)
-          current_form->value = value; /* store for the moment */
-        else
-          return_value = CURL_FORMADD_NULL;
-      }
-      break;
-    case CURLFORM_CONTENTSLENGTH:
-      current_form->contentslength =
-        array_state?(size_t)array_value:(size_t)va_arg(params, long);
-      break;
-
-    case CURLFORM_CONTENTLEN:
-      current_form->flags |= CURL_HTTPPOST_LARGE;
-      current_form->contentslength =
-        array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
-      break;
-
-      /* Get contents from a given file name */
-    case CURLFORM_FILECONTENT:
-      if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
-        return_value = CURL_FORMADD_OPTION_TWICE;
-      else {
-        const char *filename = array_state?
-          array_value:va_arg(params, char *);
-        if(filename) {
-          current_form->value = strdup(filename);
-          if(!current_form->value)
-            return_value = CURL_FORMADD_MEMORY;
-          else {
-            current_form->flags |= HTTPPOST_READFILE;
-            current_form->value_alloc = TRUE;
-          }
-        }
-        else
-          return_value = CURL_FORMADD_NULL;
-      }
-      break;
-
-      /* We upload a file */
-    case CURLFORM_FILE:
-      {
-        const char *filename = array_state?array_value:
-          va_arg(params, char *);
-
-        if(current_form->value) {
-          if(current_form->flags & HTTPPOST_FILENAME) {
-            if(filename) {
-              char *fname = strdup(filename);
-              if(!fname)
-                return_value = CURL_FORMADD_MEMORY;
-              else {
-                form = AddFormInfo(fname, NULL, current_form);
-                if(!form) {
-                  free(fname);
-                  return_value = CURL_FORMADD_MEMORY;
-                }
-                else {
-                  form->value_alloc = TRUE;
-                  current_form = form;
-                  form = NULL;
-                }
-              }
-            }
-            else
-              return_value = CURL_FORMADD_NULL;
-          }
-          else
-            return_value = CURL_FORMADD_OPTION_TWICE;
-        }
-        else {
-          if(filename) {
-            current_form->value = strdup(filename);
-            if(!current_form->value)
-              return_value = CURL_FORMADD_MEMORY;
-            else {
-              current_form->flags |= HTTPPOST_FILENAME;
-              current_form->value_alloc = TRUE;
-            }
-          }
-          else
-            return_value = CURL_FORMADD_NULL;
-        }
-        break;
-      }
-
-    case CURLFORM_BUFFERPTR:
-      current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
-      if(current_form->buffer)
-        return_value = CURL_FORMADD_OPTION_TWICE;
-      else {
-        char *buffer =
-          array_state?array_value:va_arg(params, char *);
-        if(buffer) {
-          current_form->buffer = buffer; /* store for the moment */
-          current_form->value = buffer; /* make it non-NULL to be accepted
-                                           as fine */
-        }
-        else
-          return_value = CURL_FORMADD_NULL;
-      }
-      break;
-
-    case CURLFORM_BUFFERLENGTH:
-      if(current_form->bufferlength)
-        return_value = CURL_FORMADD_OPTION_TWICE;
-      else
-        current_form->bufferlength =
-          array_state?(size_t)array_value:(size_t)va_arg(params, long);
-      break;
-
-    case CURLFORM_STREAM:
-      current_form->flags |= HTTPPOST_CALLBACK;
-      if(current_form->userp)
-        return_value = CURL_FORMADD_OPTION_TWICE;
-      else {
-        char *userp =
-          array_state?array_value:va_arg(params, char *);
-        if(userp) {
-          current_form->userp = userp;
-          current_form->value = userp; /* this isn't strictly true but we
-                                          derive a value from this later on
-                                          and we need this non-NULL to be
-                                          accepted as a fine form part */
-        }
-        else
-          return_value = CURL_FORMADD_NULL;
-      }
-      break;
-
-    case CURLFORM_CONTENTTYPE:
-      {
-        const char *contenttype =
-          array_state?array_value:va_arg(params, char *);
-        if(current_form->contenttype) {
-          if(current_form->flags & HTTPPOST_FILENAME) {
-            if(contenttype) {
-              char *type = strdup(contenttype);
-              if(!type)
-                return_value = CURL_FORMADD_MEMORY;
-              else {
-                form = AddFormInfo(NULL, type, current_form);
-                if(!form) {
-                  free(type);
-                  return_value = CURL_FORMADD_MEMORY;
-                }
-                else {
-                  form->contenttype_alloc = TRUE;
-                  current_form = form;
-                  form = NULL;
-                }
-              }
-            }
-            else
-              return_value = CURL_FORMADD_NULL;
-          }
-          else
-            return_value = CURL_FORMADD_OPTION_TWICE;
-        }
-        else {
-          if(contenttype) {
-            current_form->contenttype = strdup(contenttype);
-            if(!current_form->contenttype)
-              return_value = CURL_FORMADD_MEMORY;
-            else
-              current_form->contenttype_alloc = TRUE;
-          }
-          else
-            return_value = CURL_FORMADD_NULL;
-        }
-        break;
-      }
-    case CURLFORM_CONTENTHEADER:
-      {
-        /* this "cast increases required alignment of target type" but
-           we consider it OK anyway */
-        struct curl_slist* list = array_state?
-          (struct curl_slist*)(void*)array_value:
-          va_arg(params, struct curl_slist*);
-
-        if(current_form->contentheader)
-          return_value = CURL_FORMADD_OPTION_TWICE;
-        else
-          current_form->contentheader = list;
-
-        break;
-      }
-    case CURLFORM_FILENAME:
-    case CURLFORM_BUFFER:
-      {
-        const char *filename = array_state?array_value:
-          va_arg(params, char *);
-        if(current_form->showfilename)
-          return_value = CURL_FORMADD_OPTION_TWICE;
-        else {
-          current_form->showfilename = strdup(filename);
-          if(!current_form->showfilename)
-            return_value = CURL_FORMADD_MEMORY;
-          else
-            current_form->showfilename_alloc = TRUE;
-        }
-        break;
-      }
-    default:
-      return_value = CURL_FORMADD_UNKNOWN_OPTION;
-      break;
-    }
-  }
-
-  if(CURL_FORMADD_OK != return_value) {
-    /* On error, free allocated fields for all nodes of the FormInfo linked
-       list without deallocating nodes. List nodes are deallocated later on */
-    FormInfo *ptr;
-    for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
-      if(ptr->name_alloc) {
-        Curl_safefree(ptr->name);
-        ptr->name_alloc = FALSE;
-      }
-      if(ptr->value_alloc) {
-        Curl_safefree(ptr->value);
-        ptr->value_alloc = FALSE;
-      }
-      if(ptr->contenttype_alloc) {
-        Curl_safefree(ptr->contenttype);
-        ptr->contenttype_alloc = FALSE;
-      }
-      if(ptr->showfilename_alloc) {
-        Curl_safefree(ptr->showfilename);
-        ptr->showfilename_alloc = FALSE;
-      }
-    }
-  }
-
-  if(CURL_FORMADD_OK == return_value) {
-    /* go through the list, check for completeness and if everything is
-     * alright add the HttpPost item otherwise set return_value accordingly */
-
-    post = NULL;
-    for(form = first_form;
-        form != NULL;
-        form = form->more) {
-      if(((!form->name || !form->value) && !post) ||
-         ( (form->contentslength) &&
-           (form->flags & HTTPPOST_FILENAME) ) ||
-         ( (form->flags & HTTPPOST_FILENAME) &&
-           (form->flags & HTTPPOST_PTRCONTENTS) ) ||
-
-         ( (!form->buffer) &&
-           (form->flags & HTTPPOST_BUFFER) &&
-           (form->flags & HTTPPOST_PTRBUFFER) ) ||
-
-         ( (form->flags & HTTPPOST_READFILE) &&
-           (form->flags & HTTPPOST_PTRCONTENTS) )
-        ) {
-        return_value = CURL_FORMADD_INCOMPLETE;
-        break;
-      }
-      else {
-        if(((form->flags & HTTPPOST_FILENAME) ||
-            (form->flags & HTTPPOST_BUFFER)) &&
-           !form->contenttype) {
-          char *f = form->flags & HTTPPOST_BUFFER?
-            form->showfilename : form->value;
-
-          /* our contenttype is missing */
-          form->contenttype = strdup(ContentTypeForFilename(f, prevtype));
-          if(!form->contenttype) {
-            return_value = CURL_FORMADD_MEMORY;
-            break;
-          }
-          form->contenttype_alloc = TRUE;
-        }
-        if(!(form->flags & HTTPPOST_PTRNAME) &&
-           (form == first_form) ) {
-          /* Note that there's small risk that form->name is NULL here if the
-             app passed in a bad combo, so we better check for that first. */
-          if(form->name) {
-            /* copy name (without strdup; possibly contains null characters) */
-            form->name = Curl_memdup(form->name, form->namelength?
-                                     form->namelength:
-                                     strlen(form->name)+1);
-          }
-          if(!form->name) {
-            return_value = CURL_FORMADD_MEMORY;
-            break;
-          }
-          form->name_alloc = TRUE;
-        }
-        if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
-                            HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
-                            HTTPPOST_CALLBACK)) && form->value) {
-          /* copy value (without strdup; possibly contains null characters) */
-          size_t clen  = (size_t) form->contentslength;
-          if(!clen)
-            clen = strlen(form->value)+1;
-
-          form->value = Curl_memdup(form->value, clen);
-
-          if(!form->value) {
-            return_value = CURL_FORMADD_MEMORY;
-            break;
-          }
-          form->value_alloc = TRUE;
-        }
-        post = AddHttpPost(form->name, form->namelength,
-                           form->value, form->contentslength,
-                           form->buffer, form->bufferlength,
-                           form->contenttype, form->flags,
-                           form->contentheader, form->showfilename,
-                           form->userp,
-                           post, httppost,
-                           last_post);
-
-        if(!post) {
-          return_value = CURL_FORMADD_MEMORY;
-          break;
-        }
-
-        if(form->contenttype)
-          prevtype = form->contenttype;
-      }
-    }
-    if(CURL_FORMADD_OK != return_value) {
-      /* On error, free allocated fields for nodes of the FormInfo linked
-         list which are not already owned by the httppost linked list
-         without deallocating nodes. List nodes are deallocated later on */
-      FormInfo *ptr;
-      for(ptr = form; ptr != NULL; ptr = ptr->more) {
-        if(ptr->name_alloc) {
-          Curl_safefree(ptr->name);
-          ptr->name_alloc = FALSE;
-        }
-        if(ptr->value_alloc) {
-          Curl_safefree(ptr->value);
-          ptr->value_alloc = FALSE;
-        }
-        if(ptr->contenttype_alloc) {
-          Curl_safefree(ptr->contenttype);
-          ptr->contenttype_alloc = FALSE;
-        }
-        if(ptr->showfilename_alloc) {
-          Curl_safefree(ptr->showfilename);
-          ptr->showfilename_alloc = FALSE;
-        }
-      }
-    }
-  }
-
-  /* Always deallocate FormInfo linked list nodes without touching node
-     fields given that these have either been deallocated or are owned
-     now by the httppost linked list */
-  while(first_form) {
-    FormInfo *ptr = first_form->more;
-    free(first_form);
-    first_form = ptr;
-  }
-
-  return return_value;
-}
-
-/*
- * curl_formadd() is a public API to add a section to the multipart formpost.
- *
- * @unittest: 1308
- */
-
-CURLFORMcode curl_formadd(struct curl_httppost **httppost,
-                          struct curl_httppost **last_post,
-                          ...)
-{
-  va_list arg;
-  CURLFORMcode result;
-  va_start(arg, last_post);
-  result = FormAdd(httppost, last_post, arg);
-  va_end(arg);
-  return result;
-}
-
-#ifdef __VMS
-#include <fabdef.h>
-/*
- * get_vms_file_size does what it takes to get the real size of the file
- *
- * For fixed files, find out the size of the EOF block and adjust.
- *
- * For all others, have to read the entire file in, discarding the contents.
- * Most posted text files will be small, and binary files like zlib archives
- * and CD/DVD images should be either a STREAM_LF format or a fixed format.
- *
- */
-curl_off_t VmsRealFileSize(const char * name,
-                           const struct_stat * stat_buf)
-{
-  char buffer[8192];
-  curl_off_t count;
-  int ret_stat;
-  FILE * file;
-
-  file = fopen(name, FOPEN_READTEXT); /* VMS */
-  if(file == NULL)
-    return 0;
-
-  count = 0;
-  ret_stat = 1;
-  while(ret_stat > 0) {
-    ret_stat = fread(buffer, 1, sizeof(buffer), file);
-    if(ret_stat != 0)
-      count += ret_stat;
-  }
-  fclose(file);
-
-  return count;
-}
-
-/*
- *
- *  VmsSpecialSize checks to see if the stat st_size can be trusted and
- *  if not to call a routine to get the correct size.
- *
- */
-static curl_off_t VmsSpecialSize(const char * name,
-                                 const struct_stat * stat_buf)
-{
-  switch(stat_buf->st_fab_rfm) {
-  case FAB$C_VAR:
-  case FAB$C_VFC:
-    return VmsRealFileSize(name, stat_buf);
-    break;
-  default:
-    return stat_buf->st_size;
-  }
-}
-
-#endif
-
-#ifndef __VMS
-#define filesize(name, stat_data) (stat_data.st_size)
-#else
-    /* Getting the expected file size needs help on VMS */
-#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
-#endif
-
-/*
- * AddFormData() adds a chunk of data to the FormData linked list.
- *
- * size is incremented by the chunk length, unless it is NULL
- */
-static CURLcode AddFormData(struct FormData **formp,
-                            enum formtype type,
-                            const void *line,
-                            curl_off_t length,
-                            curl_off_t *size)
-{
-  struct FormData *newform;
-  char *alloc2 = NULL;
-  CURLcode result = CURLE_OK;
-  if(length < 0 || (size && *size < 0))
-    return CURLE_BAD_FUNCTION_ARGUMENT;
-
-  newform = malloc(sizeof(struct FormData));
-  if(!newform)
-    return CURLE_OUT_OF_MEMORY;
-  newform->next = NULL;
-
-  if(type <= FORM_CONTENT) {
-    /* we make it easier for plain strings: */
-    if(!length)
-      length = strlen((char *)line);
-#if (SIZEOF_SIZE_T < CURL_SIZEOF_CURL_OFF_T)
-    else if(length >= (curl_off_t)(size_t)-1) {
-      result = CURLE_BAD_FUNCTION_ARGUMENT;
-      goto error;
-    }
-#endif
-
-    newform->line = malloc((size_t)length+1);
-    if(!newform->line) {
-      result = CURLE_OUT_OF_MEMORY;
-      goto error;
-    }
-    alloc2 = newform->line;
-    memcpy(newform->line, line, (size_t)length);
-    newform->length = (size_t)length;
-    newform->line[(size_t)length]=0; /* zero terminate for easier debugging */
-  }
-  else
-    /* For callbacks and files we don't have any actual data so we just keep a
-       pointer to whatever this points to */
-    newform->line = (char *)line;
-
-  newform->type = type;
-
-  if(*formp) {
-    (*formp)->next = newform;
-    *formp = newform;
-  }
-  else
-    *formp = newform;
-
-  if(size) {
-    if(type != FORM_FILE)
-      /* for static content as well as callback data we add the size given
-         as input argument */
-      *size += length;
-    else {
-      /* Since this is a file to be uploaded here, add the size of the actual
-         file */
-      if(!strequal("-", newform->line)) {
-        struct_stat file;
-        if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode))
-          *size += filesize(newform->line, file);
-        else {
-          result = CURLE_BAD_FUNCTION_ARGUMENT;
-          goto error;
-        }
-      }
-    }
-  }
-  return CURLE_OK;
-  error:
-  if(newform)
-    free(newform);
-  if(alloc2)
-    free(alloc2);
-  return result;
-}
-
-/*
- * AddFormDataf() adds printf()-style formatted data to the formdata chain.
- */
-
-static CURLcode AddFormDataf(struct FormData **formp,
-                             curl_off_t *size,
-                             const char *fmt, ...)
-{
-  char s[4096];
-  va_list ap;
-  va_start(ap, fmt);
-  vsnprintf(s, sizeof(s), fmt, ap);
-  va_end(ap);
-
-  return AddFormData(formp, FORM_DATA, s, 0, size);
-}
-
-/*
- * Curl_formclean() is used from http.c, this cleans a built FormData linked
- * list
- */
-void Curl_formclean(struct FormData **form_ptr)
-{
-  struct FormData *next, *form;
-
-  form = *form_ptr;
-  if(!form)
-    return;
-
-  do {
-    next=form->next;  /* the following form line */
-    if(form->type <= FORM_CONTENT)
-      free(form->line); /* free the line */
-    free(form);       /* free the struct */
-
-  } while((form = next) != NULL); /* continue */
-
-  *form_ptr = NULL;
-}
-
-/*
- * curl_formget()
- * Serialize a curl_httppost struct.
- * Returns 0 on success.
- *
- * @unittest: 1308
- */
-int curl_formget(struct curl_httppost *form, void *arg,
-                 curl_formget_callback append)
-{
-  CURLcode result;
-  curl_off_t size;
-  struct FormData *data, *ptr;
-
-  result = Curl_getformdata(NULL, &data, form, NULL, &size);
-  if(result)
-    return (int)result;
-
-  for(ptr = data; ptr; ptr = ptr->next) {
-    if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) {
-      char buffer[8192];
-      size_t nread;
-      struct Form temp;
-
-      Curl_FormInit(&temp, ptr);
-
-      do {
-        nread = readfromfile(&temp, buffer, sizeof(buffer));
-        if((nread == (size_t) -1) ||
-           (nread > sizeof(buffer)) ||
-           (nread != append(arg, buffer, nread))) {
-          if(temp.fp)
-            fclose(temp.fp);
-          Curl_formclean(&data);
-          return -1;
-        }
-      } while(nread);
-    }
-    else {
-      if(ptr->length != append(arg, ptr->line, ptr->length)) {
-        Curl_formclean(&data);
-        return -1;
-      }
-    }
-  }
-  Curl_formclean(&data);
-  return 0;
-}
-
-/*
- * curl_formfree() is an external function to free up a whole form post
- * chain
- */
-void curl_formfree(struct curl_httppost *form)
-{
-  struct curl_httppost *next;
-
-  if(!form)
-    /* no form to free, just get out of this */
-    return;
-
-  do {
-    next=form->next;  /* the following form line */
-
-    /* recurse to sub-contents */
-    curl_formfree(form->more);
-
-    if(!(form->flags & HTTPPOST_PTRNAME))
-      free(form->name); /* free the name */
-    if(!(form->flags &
-         (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
-      )
-      free(form->contents); /* free the contents */
-    free(form->contenttype); /* free the content type */
-    free(form->showfilename); /* free the faked file name */
-    free(form);       /* free the struct */
-
-  } while((form = next) != NULL); /* continue */
-}
-
-#ifndef HAVE_BASENAME
-/*
-  (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
-  Edition)
-
-  The basename() function shall take the pathname pointed to by path and
-  return a pointer to the final component of the pathname, deleting any
-  trailing '/' characters.
-
-  If the string pointed to by path consists entirely of the '/' character,
-  basename() shall return a pointer to the string "/". If the string pointed
-  to by path is exactly "//", it is implementation-defined whether '/' or "//"
-  is returned.
-
-  If path is a null pointer or points to an empty string, basename() shall
-  return a pointer to the string ".".
-
-  The basename() function may modify the string pointed to by path, and may
-  return a pointer to static storage that may then be overwritten by a
-  subsequent call to basename().
-
-  The basename() function need not be reentrant. A function that is not
-  required to be reentrant is not required to be thread-safe.
-
-*/
-static char *Curl_basename(char *path)
-{
-  /* Ignore all the details above for now and make a quick and simple
-     implementaion here */
-  char *s1;
-  char *s2;
-
-  s1=strrchr(path, '/');
-  s2=strrchr(path, '\\');
-
-  if(s1 && s2) {
-    path = (s1 > s2? s1 : s2)+1;
-  }
-  else if(s1)
-    path = s1 + 1;
-  else if(s2)
-    path = s2 + 1;
-
-  return path;
-}
-#endif
-
-static char *strippath(const char *fullfile)
-{
-  char *filename;
-  char *base;
-  filename = strdup(fullfile); /* duplicate since basename() may ruin the
-                                  buffer it works on */
-  if(!filename)
-    return NULL;
-  base = strdup(basename(filename));
-
-  free(filename); /* free temporary buffer */
-
-  return base; /* returns an allocated string or NULL ! */
-}
-
-static CURLcode formdata_add_filename(const struct curl_httppost *file,
-                                      struct FormData **form,
-                                      curl_off_t *size)
-{
-  CURLcode result = CURLE_OK;
-  char *filename = file->showfilename;
-  char *filebasename = NULL;
-  char *filename_escaped = NULL;
-
-  if(!filename) {
-    filebasename = strippath(file->contents);
-    if(!filebasename)
-      return CURLE_OUT_OF_MEMORY;
-    filename = filebasename;
-  }
-
-  if(strchr(filename, '\\') || strchr(filename, '"')) {
-    char *p0, *p1;
-
-    /* filename need be escaped */
-    filename_escaped = malloc(strlen(filename)*2+1);
-    if(!filename_escaped) {
-      free(filebasename);
-      return CURLE_OUT_OF_MEMORY;
-    }
-    p0 = filename_escaped;
-    p1 = filename;
-    while(*p1) {
-      if(*p1 == '\\' || *p1 == '"')
-        *p0++ = '\\';
-      *p0++ = *p1++;
-    }
-    *p0 = '\0';
-    filename = filename_escaped;
-  }
-  result = AddFormDataf(form, size,
-                        "; filename=\"%s\"",
-                        filename);
-  free(filename_escaped);
-  free(filebasename);
-  return result;
-}
-
-/*
- * Curl_getformdata() converts a linked list of "meta data" into a complete
- * (possibly huge) multipart formdata. The input list is in 'post', while the
- * output resulting linked lists gets stored in '*finalform'. *sizep will get
- * the total size of the whole POST.
- * A multipart/form_data content-type is built, unless a custom content-type
- * is passed in 'custom_content_type'.
- *
- * This function will not do a failf() for the potential memory failures but
- * should for all other errors it spots. Just note that this function MAY get
- * a NULL pointer in the 'data' argument.
- */
-
-CURLcode Curl_getformdata(struct Curl_easy *data,
-                          struct FormData **finalform,
-                          struct curl_httppost *post,
-                          const char *custom_content_type,
-                          curl_off_t *sizep)
-{
-  struct FormData *form = NULL;
-  struct FormData *firstform;
-  struct curl_httppost *file;
-  CURLcode result = CURLE_OK;
-
-  curl_off_t size = 0; /* support potentially ENORMOUS formposts */
-  char *boundary;
-  char *fileboundary = NULL;
-  struct curl_slist* curList;
-
-  *finalform = NULL; /* default form is empty */
-
-  if(!post)
-    return result; /* no input => no output! */
-
-  boundary = formboundary(data);
-  if(!boundary)
-    return CURLE_OUT_OF_MEMORY;
-
-  /* Make the first line of the output */
-  result = AddFormDataf(&form, NULL,
-                        "%s; boundary=%s\r\n",
-                        custom_content_type?custom_content_type:
-                        "Content-Type: multipart/form-data",
-                        boundary);
-
-  if(result) {
-    free(boundary);
-    return result;
-  }
-  /* we DO NOT include that line in the total size of the POST, since it'll be
-     part of the header! */
-
-  firstform = form;
-
-  do {
-
-    if(size) {
-      result = AddFormDataf(&form, &size, "\r\n");
-      if(result)
-        break;
-    }
-
-    /* boundary */
-    result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
-    if(result)
-      break;
-
-    /* Maybe later this should be disabled when a custom_content_type is
-       passed, since Content-Disposition is not meaningful for all multipart
-       types.
-    */
-    result = AddFormDataf(&form, &size,
-                          "Content-Disposition: form-data; name=\"");
-    if(result)
-      break;
-
-    result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
-                         &size);
-    if(result)
-      break;
-
-    result = AddFormDataf(&form, &size, "\"");
-    if(result)
-      break;
-
-    if(post->more) {
-      /* If used, this is a link to more file names, we must then do
-         the magic to include several files with the same field name */
-
-      free(fileboundary);
-      fileboundary = formboundary(data);
-      if(!fileboundary) {
-        result = CURLE_OUT_OF_MEMORY;
-        break;
-      }
-
-      result = AddFormDataf(&form, &size,
-                            "\r\nContent-Type: multipart/mixed;"
-                            " boundary=%s\r\n",
-                            fileboundary);
-      if(result)
-        break;
-    }
-
-    file = post;
-
-    do {
-
-      /* If 'showfilename' is set, that is a faked name passed on to us
-         to use to in the formpost. If that is not set, the actually used
-         local file name should be added. */
-
-      if(post->more) {
-        /* if multiple-file */
-        result = AddFormDataf(&form, &size,
-                              "\r\n--%s\r\nContent-Disposition: "
-                              "attachment",
-                              fileboundary);
-        if(result)
-          break;
-        result = formdata_add_filename(file, &form, &size);
-        if(result)
-          break;
-      }
-      else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
-                             HTTPPOST_CALLBACK)) {
-        /* it should be noted that for the HTTPPOST_FILENAME and
-           HTTPPOST_CALLBACK cases the ->showfilename struct member is always
-           assigned at this point */
-        if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) {
-          result = formdata_add_filename(post, &form, &size);
-        }
-
-        if(result)
-          break;
-      }
-
-      if(file->contenttype) {
-        /* we have a specified type */
-        result = AddFormDataf(&form, &size,
-                              "\r\nContent-Type: %s",
-                              file->contenttype);
-        if(result)
-          break;
-      }
-
-      curList = file->contentheader;
-      while(curList) {
-        /* Process the additional headers specified for this form */
-        result = AddFormDataf(&form, &size, "\r\n%s", curList->data);
-        if(result)
-          break;
-        curList = curList->next;
-      }
-      if(result)
-        break;
-
-      result = AddFormDataf(&form, &size, "\r\n\r\n");
-      if(result)
-        break;
-
-      if((post->flags & HTTPPOST_FILENAME) ||
-         (post->flags & HTTPPOST_READFILE)) {
-        /* we should include the contents from the specified file */
-        FILE *fileread;
-
-        fileread = strequal("-", file->contents)?
-          stdin:fopen(file->contents, "rb"); /* binary read for win32  */
-
-        /*
-         * VMS: This only allows for stream files on VMS.  Stream files are
-         * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
-         * every record needs to have a \n appended & 1 added to SIZE
-         */
-
-        if(fileread) {
-          if(fileread != stdin) {
-            /* close the file */
-            fclose(fileread);
-            /* add the file name only - for later reading from this */
-            result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
-          }
-          else {
-            /* When uploading from stdin, we can't know the size of the file,
-             * thus must read the full file as before. We *could* use chunked
-             * transfer-encoding, but that only works for HTTP 1.1 and we
-             * can't be sure we work with such a server.
-             */
-            size_t nread;
-            char buffer[512];
-            while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
-              result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
-              if(result)
-                break;
-            }
-          }
-        }
-        else {
-          if(data)
-            failf(data, "couldn't open file \"%s\"", file->contents);
-          *finalform = NULL;
-          result = CURLE_READ_ERROR;
-        }
-      }
-      else if(post->flags & HTTPPOST_BUFFER)
-        /* include contents of buffer */
-        result = AddFormData(&form, FORM_CONTENT, post->buffer,
-                             post->bufferlength, &size);
-      else if(post->flags & HTTPPOST_CALLBACK)
-        /* the contents should be read with the callback and the size is set
-           with the contentslength */
-        result = AddFormData(&form, FORM_CALLBACK, post->userp,
-                             post->flags&CURL_HTTPPOST_LARGE?
-                             post->contentlen:post->contentslength, &size);
-      else
-        /* include the contents we got */
-        result = AddFormData(&form, FORM_CONTENT, post->contents,
-                             post->flags&CURL_HTTPPOST_LARGE?
-                             post->contentlen:post->contentslength, &size);
-      file = file->more;
-    } while(file && !result); /* for each specified file for this field */
-
-    if(result)
-      break;
-
-    if(post->more) {
-      /* this was a multiple-file inclusion, make a termination file
-         boundary: */
-      result = AddFormDataf(&form, &size,
-                           "\r\n--%s--",
-                           fileboundary);
-      if(result)
-        break;
-    }
-
-  } while((post = post->next) != NULL); /* for each field */
-
-  /* end-boundary for everything */
-  if(!result)
-    result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary);
-
-  if(result) {
-    Curl_formclean(&firstform);
-    free(fileboundary);
-    free(boundary);
-    return result;
-  }
-
-  *sizep = size;
-
-  free(fileboundary);
-  free(boundary);
-
-  *finalform = firstform;
-
-  return result;
-}
-
-/*
- * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
- * and resets the 'sent' counter.
- */
-int Curl_FormInit(struct Form *form, struct FormData *formdata)
-{
-  if(!formdata)
-    return 1; /* error */
-
-  form->data = formdata;
-  form->sent = 0;
-  form->fp = NULL;
-  form->fread_func = ZERO_NULL;
-
-  return 0;
-}
-
-#ifndef __VMS
-# define fopen_read fopen
-#else
-  /*
-   * vmsfopenread
-   *
-   * For upload to work as expected on VMS, different optional
-   * parameters must be added to the fopen command based on
-   * record format of the file.
-   *
-   */
-# define fopen_read vmsfopenread
-static FILE * vmsfopenread(const char *file, const char *mode) {
-  struct_stat statbuf;
-  int result;
-
-  result = stat(file, &statbuf);
-
-  switch (statbuf.st_fab_rfm) {
-  case FAB$C_VAR:
-  case FAB$C_VFC:
-  case FAB$C_STMCR:
-    return fopen(file, FOPEN_READTEXT); /* VMS */
-    break;
-  default:
-    return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
-  }
-}
-#endif
-
-/*
- * readfromfile()
- *
- * The read callback that this function may use can return a value larger than
- * 'size' (which then this function returns) that indicates a problem and it
- * must be properly dealt with
- */
-static size_t readfromfile(struct Form *form, char *buffer,
-                           size_t size)
-{
-  size_t nread;
-  bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE;
-
-  if(callback) {
-    if(form->fread_func == ZERO_NULL)
-      return 0;
-    else
-      nread = form->fread_func(buffer, 1, size, form->data->line);
-  }
-  else {
-    if(!form->fp) {
-      /* this file hasn't yet been opened */
-      form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
-      if(!form->fp)
-        return (size_t)-1; /* failure */
-    }
-    nread = fread(buffer, 1, size, form->fp);
-  }
-  if(!nread) {
-    /* this is the last chunk from the file, move on */
-    if(form->fp) {
-      fclose(form->fp);
-      form->fp = NULL;
-    }
-    form->data = form->data->next;
-  }
-
-  return nread;
-}
-
-/*
- * Curl_FormReader() is the fread() emulation function that will be used to
- * deliver the formdata to the transfer loop and then sent away to the peer.
- */
-size_t Curl_FormReader(char *buffer,
-                       size_t size,
-                       size_t nitems,
-                       FILE *mydata)
-{
-  struct Form *form;
-  size_t wantedsize;
-  size_t gotsize = 0;
-
-  form=(struct Form *)mydata;
-
-  wantedsize = size * nitems;
-
-  if(!form->data)
-    return 0; /* nothing, error, empty */
-
-  if((form->data->type == FORM_FILE) ||
-     (form->data->type == FORM_CALLBACK)) {
-    gotsize = readfromfile(form, buffer, wantedsize);
-
-    if(gotsize)
-      /* If positive or -1, return. If zero, continue! */
-      return gotsize;
-  }
-  do {
-
-    if((form->data->length - form->sent) > wantedsize - gotsize) {
-
-      memcpy(buffer + gotsize, form->data->line + form->sent,
-             wantedsize - gotsize);
-
-      form->sent += wantedsize-gotsize;
-
-      return wantedsize;
-    }
-
-    memcpy(buffer+gotsize,
-           form->data->line + form->sent,
-           (form->data->length - form->sent) );
-    gotsize += form->data->length - form->sent;
-
-    form->sent = 0;
-
-    form->data = form->data->next; /* advance */
-
-  } while(form->data && (form->data->type < FORM_CALLBACK));
-  /* If we got an empty line and we have more data, we proceed to the next
-     line immediately to avoid returning zero before we've reached the end. */
-
-  return gotsize;
-}
-
-/*
- * Curl_formpostheader() returns the first line of the formpost, the
- * request-header part (which is not part of the request-body like the rest of
- * the post).
- */
-char *Curl_formpostheader(void *formp, size_t *len)
-{
-  char *header;
-  struct Form *form=(struct Form *)formp;
-
-  if(!form->data)
-    return 0; /* nothing, ERROR! */
-
-  header = form->data->line;
-  *len = form->data->length;
-
-  form->data = form->data->next; /* advance */
-
-  return header;
-}
-
-/*
- * formboundary() creates a suitable boundary string and returns an allocated
- * one.
- */
-static char *formboundary(struct Curl_easy *data)
-{
-  /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
-     combinations */
-  return aprintf("------------------------%08x%08x",
-                 Curl_rand(data), Curl_rand(data));
-}
-
-#else  /* CURL_DISABLE_HTTP */
-CURLFORMcode curl_formadd(struct curl_httppost **httppost,
-                          struct curl_httppost **last_post,
-                          ...)
-{
-  (void)httppost;
-  (void)last_post;
-  return CURL_FORMADD_DISABLED;
-}
-
-int curl_formget(struct curl_httppost *form, void *arg,
-                 curl_formget_callback append)
-{
-  (void) form;
-  (void) arg;
-  (void) append;
-  return CURL_FORMADD_DISABLED;
-}
-
-void curl_formfree(struct curl_httppost *form)
-{
-  (void)form;
-  /* does nothing HTTP is disabled */
-}
-
-
-#endif  /* !defined(CURL_DISABLE_HTTP) */
diff --git a/lib/formdata.cpp b/lib/formdata.cpp
new file mode 100644
index 0000000..14dc73a
--- /dev/null
+++ b/lib/formdata.cpp
@@ -0,0 +1,1617 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#ifndef CURL_DISABLE_HTTP
+
+#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
+#include <libgen.h>
+#endif
+
+#include "urldata.h" /* for struct Curl_easy */
+#include "formdata.h"
+#include "vtls/vtls.h"
+#include "strequal.h"
+#include "sendf.h"
+#include "strdup.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+#ifdef WIN32
+    #include <atlbase.h>                //CA2W
+#endif
+
+#ifndef HAVE_BASENAME
+static char *Curl_basename(char *path);
+#define basename(x)  Curl_basename((x))
+#endif
+
+static size_t readfromfile(struct Form *form, char *buffer, size_t size);
+static char *formboundary(struct Curl_easy *data);
+
+/* What kind of Content-Type to use on un-specified files with unrecognized
+   extensions. */
+#define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
+
+#define FORM_FILE_SEPARATOR ','
+#define FORM_TYPE_SEPARATOR ';'
+
+#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
+#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
+#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
+#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
+#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
+#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
+#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
+
+/***************************************************************************
+ *
+ * AddHttpPost()
+ *
+ * Adds a HttpPost structure to the list, if parent_post is given becomes
+ * a subpost of parent_post instead of a direct list element.
+ *
+ * Returns newly allocated HttpPost on success and NULL if malloc failed.
+ *
+ ***************************************************************************/
+static struct curl_httppost *
+AddHttpPost(char *name, size_t namelength,
+            char *value, curl_off_t contentslength,
+            char *buffer, size_t bufferlength,
+            char *contenttype,
+            long flags,
+            struct curl_slist* contentHeader,
+            char *showfilename, char *userp,
+            struct curl_httppost *parent_post,
+            struct curl_httppost **httppost,
+            struct curl_httppost **last_post)
+{
+  struct curl_httppost *post;
+  post = (struct curl_httppost *)calloc(1, sizeof(struct curl_httppost));
+  if(post) {
+    post->name = name;
+    post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
+    post->contents = value;
+    post->contentlen = contentslength;
+    post->buffer = buffer;
+    post->bufferlength = (long)bufferlength;
+    post->contenttype = contenttype;
+    post->contentheader = contentHeader;
+    post->showfilename = showfilename;
+    post->userp = userp,
+    post->flags = flags | CURL_HTTPPOST_LARGE;
+  }
+  else
+    return NULL;
+
+  if(parent_post) {
+    /* now, point our 'more' to the original 'more' */
+    post->more = parent_post->more;
+
+    /* then move the original 'more' to point to ourselves */
+    parent_post->more = post;
+  }
+  else {
+    /* make the previous point to this */
+    if(*last_post)
+      (*last_post)->next = post;
+    else
+      (*httppost) = post;
+
+    (*last_post) = post;
+  }
+  return post;
+}
+
+/***************************************************************************
+ *
+ * AddFormInfo()
+ *
+ * Adds a FormInfo structure to the list presented by parent_form_info.
+ *
+ * Returns newly allocated FormInfo on success and NULL if malloc failed/
+ * parent_form_info is NULL.
+ *
+ ***************************************************************************/
+static FormInfo * AddFormInfo(char *value,
+                              char *contenttype,
+                              FormInfo *parent_form_info)
+{
+  FormInfo *form_info;
+  form_info = (FormInfo*) calloc(1, sizeof(struct FormInfo));
+  if(form_info) {
+    if(value)
+      form_info->value = value;
+    if(contenttype)
+      form_info->contenttype = contenttype;
+    form_info->flags = HTTPPOST_FILENAME;
+  }
+  else
+    return NULL;
+
+  if(parent_form_info) {
+    /* now, point our 'more' to the original 'more' */
+    form_info->more = parent_form_info->more;
+
+    /* then move the original 'more' to point to ourselves */
+    parent_form_info->more = form_info;
+  }
+
+  return form_info;
+}
+
+/***************************************************************************
+ *
+ * ContentTypeForFilename()
+ *
+ * Provides content type for filename if one of the known types (else
+ * (either the prevtype or the default is returned).
+ *
+ * Returns some valid contenttype for filename.
+ *
+ ***************************************************************************/
+static const char *ContentTypeForFilename(const char *filename,
+                                          const char *prevtype)
+{
+  const char *contenttype = NULL;
+  unsigned int i;
+  /*
+   * No type was specified, we scan through a few well-known
+   * extensions and pick the first we match!
+   */
+  struct ContentType {
+    const char *extension;
+    const char *type;
+  };
+  static const struct ContentType ctts[]={
+    {".gif",  "image/gif"},
+    {".jpg",  "image/jpeg"},
+    {".jpeg", "image/jpeg"},
+    {".txt",  "text/plain"},
+    {".html", "text/html"},
+    {".xml", "application/xml"}
+  };
+
+  if(prevtype)
+    /* default to the previously set/used! */
+    contenttype = prevtype;
+  else
+    contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
+
+  if(filename) { /* in case a NULL was passed in */
+    for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
+      if(strlen(filename) >= strlen(ctts[i].extension)) {
+        if(strequal(filename +
+                    strlen(filename) - strlen(ctts[i].extension),
+                    ctts[i].extension)) {
+          contenttype = ctts[i].type;
+          break;
+        }
+      }
+    }
+  }
+  /* we have a contenttype by now */
+  return contenttype;
+}
+
+/***************************************************************************
+ *
+ * FormAdd()
+ *
+ * Stores a formpost parameter and builds the appropriate linked list.
+ *
+ * Has two principal functionalities: using files and byte arrays as
+ * post parts. Byte arrays are either copied or just the pointer is stored
+ * (as the user requests) while for files only the filename and not the
+ * content is stored.
+ *
+ * While you may have only one byte array for each name, multiple filenames
+ * are allowed (and because of this feature CURLFORM_END is needed after
+ * using CURLFORM_FILE).
+ *
+ * Examples:
+ *
+ * Simple name/value pair with copied contents:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
+ *
+ * name/value pair where only the content pointer is remembered:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
+ * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
+ *
+ * storing a filename (CONTENTTYPE is optional!):
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
+ * CURLFORM_END);
+ *
+ * storing multiple filenames:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
+ *
+ * Returns:
+ * CURL_FORMADD_OK             on success
+ * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
+ * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
+ * CURL_FORMADD_NULL           if a null pointer was given for a char
+ * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
+ * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
+ * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
+ * CURL_FORMADD_MEMORY         if a HttpPost struct cannot be allocated
+ * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
+ * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
+ *
+ ***************************************************************************/
+
+static
+CURLFORMcode FormAdd(struct curl_httppost **httppost,
+                     struct curl_httppost **last_post,
+                     va_list params)
+{
+  FormInfo *first_form, *current_form, *form = NULL;
+  CURLFORMcode return_value = CURL_FORMADD_OK;
+  const char *prevtype = NULL;
+  struct curl_httppost *post = NULL;
+  CURLformoption option;
+  struct curl_forms *forms = NULL;
+  char *array_value=NULL; /* value read from an array */
+
+  /* This is a state variable, that if TRUE means that we're parsing an
+     array that we got passed to us. If FALSE we're parsing the input
+     va_list arguments. */
+  bool array_state = FALSE;
+
+  /*
+   * We need to allocate the first struct to fill in.
+   */
+  first_form = (FormInfo*) calloc(1, sizeof(struct FormInfo));
+  if(!first_form)
+    return CURL_FORMADD_MEMORY;
+
+  current_form = first_form;
+
+  /*
+   * Loop through all the options set. Break if we have an error to report.
+   */
+  while(return_value == CURL_FORMADD_OK) {
+
+    /* first see if we have more parts of the array param */
+    if(array_state && forms) {
+      /* get the upcoming option from the given array */
+      option = forms->option;
+      array_value = (char *)forms->value;
+
+      forms++; /* advance this to next entry */
+      if(CURLFORM_END == option) {
+        /* end of array state */
+        array_state = FALSE;
+        continue;
+      }
+    }
+    else {
+      /* This is not array-state, get next option */
+      option = va_arg(params, CURLformoption);
+      if(CURLFORM_END == option)
+        break;
+    }
+
+    switch (option) {
+    case CURLFORM_ARRAY:
+      if(array_state)
+        /* we don't support an array from within an array */
+        return_value = CURL_FORMADD_ILLEGAL_ARRAY;
+      else {
+        forms = va_arg(params, struct curl_forms *);
+        if(forms)
+          array_state = TRUE;
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+
+      /*
+       * Set the Name property.
+       */
+    case CURLFORM_PTRNAME:
+#ifdef CURL_DOES_CONVERSIONS
+      /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
+       * the data in all cases so that we'll have safe memory for the eventual
+       * conversion.
+       */
+#else
+      current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
+#endif
+    case CURLFORM_COPYNAME:
+      if(current_form->name)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        char *name = array_state?
+          array_value:va_arg(params, char *);
+        if(name)
+          current_form->name = name; /* store for the moment */
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+    case CURLFORM_NAMELENGTH:
+      if(current_form->namelength)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else
+        current_form->namelength =
+          array_state?(size_t)array_value:(size_t)va_arg(params, long);
+      break;
+
+      /*
+       * Set the contents property.
+       */
+    case CURLFORM_PTRCONTENTS:
+      current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
+    case CURLFORM_COPYCONTENTS:
+      if(current_form->value)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        char *value =
+          array_state?array_value:va_arg(params, char *);
+        if(value)
+          current_form->value = value; /* store for the moment */
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+    case CURLFORM_CONTENTSLENGTH:
+      current_form->contentslength =
+        array_state?(size_t)array_value:(size_t)va_arg(params, long);
+      break;
+
+    case CURLFORM_CONTENTLEN:
+      current_form->flags |= CURL_HTTPPOST_LARGE;
+      current_form->contentslength =
+        array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
+      break;
+
+      /* Get contents from a given file name */
+    case CURLFORM_FILECONTENT:
+      if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        const char *filename = array_state?
+          array_value:va_arg(params, char *);
+        if(filename) {
+          current_form->value = strdup(filename);
+          if(!current_form->value)
+            return_value = CURL_FORMADD_MEMORY;
+          else {
+            current_form->flags |= HTTPPOST_READFILE;
+            current_form->value_alloc = TRUE;
+          }
+        }
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+
+      /* We upload a file */
+    case CURLFORM_FILE:
+      {
+        const char *filename = array_state?array_value:
+          va_arg(params, char *);
+
+        if(current_form->value) {
+          if(current_form->flags & HTTPPOST_FILENAME) {
+            if(filename) {
+              char *fname = strdup(filename);
+              if(!fname)
+                return_value = CURL_FORMADD_MEMORY;
+              else {
+                form = AddFormInfo(fname, NULL, current_form);
+                if(!form) {
+                  free(fname);
+                  return_value = CURL_FORMADD_MEMORY;
+                }
+                else {
+                  form->value_alloc = TRUE;
+                  current_form = form;
+                  form = NULL;
+                }
+              }
+            }
+            else
+              return_value = CURL_FORMADD_NULL;
+          }
+          else
+            return_value = CURL_FORMADD_OPTION_TWICE;
+        }
+        else {
+          if(filename) {
+            current_form->value = strdup(filename);
+            if(!current_form->value)
+              return_value = CURL_FORMADD_MEMORY;
+            else {
+              current_form->flags |= HTTPPOST_FILENAME;
+              current_form->value_alloc = TRUE;
+            }
+          }
+          else
+            return_value = CURL_FORMADD_NULL;
+        }
+        break;
+      }
+
+    case CURLFORM_BUFFERPTR:
+      current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
+      if(current_form->buffer)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        char *buffer =
+          array_state?array_value:va_arg(params, char *);
+        if(buffer) {
+          current_form->buffer = buffer; /* store for the moment */
+          current_form->value = buffer; /* make it non-NULL to be accepted
+                                           as fine */
+        }
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+
+    case CURLFORM_BUFFERLENGTH:
+      if(current_form->bufferlength)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else
+        current_form->bufferlength =
+          array_state?(size_t)array_value:(size_t)va_arg(params, long);
+      break;
+
+    case CURLFORM_STREAM:
+      current_form->flags |= HTTPPOST_CALLBACK;
+      if(current_form->userp)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        char *userp =
+          array_state?array_value:va_arg(params, char *);
+        if(userp) {
+          current_form->userp = userp;
+          current_form->value = userp; /* this isn't strictly true but we
+                                          derive a value from this later on
+                                          and we need this non-NULL to be
+                                          accepted as a fine form part */
+        }
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+
+    case CURLFORM_CONTENTTYPE:
+      {
+        const char *contenttype =
+          array_state?array_value:va_arg(params, char *);
+        if(current_form->contenttype) {
+          if(current_form->flags & HTTPPOST_FILENAME) {
+            if(contenttype) {
+              char *type = strdup(contenttype);
+              if(!type)
+                return_value = CURL_FORMADD_MEMORY;
+              else {
+                form = AddFormInfo(NULL, type, current_form);
+                if(!form) {
+                  free(type);
+                  return_value = CURL_FORMADD_MEMORY;
+                }
+                else {
+                  form->contenttype_alloc = TRUE;
+                  current_form = form;
+                  form = NULL;
+                }
+              }
+            }
+            else
+              return_value = CURL_FORMADD_NULL;
+          }
+          else
+            return_value = CURL_FORMADD_OPTION_TWICE;
+        }
+        else {
+          if(contenttype) {
+            current_form->contenttype = strdup(contenttype);
+            if(!current_form->contenttype)
+              return_value = CURL_FORMADD_MEMORY;
+            else
+              current_form->contenttype_alloc = TRUE;
+          }
+          else
+            return_value = CURL_FORMADD_NULL;
+        }
+        break;
+      }
+    case CURLFORM_CONTENTHEADER:
+      {
+        /* this "cast increases required alignment of target type" but
+           we consider it OK anyway */
+        struct curl_slist* list = array_state?
+          (struct curl_slist*)(void*)array_value:
+          va_arg(params, struct curl_slist*);
+
+        if(current_form->contentheader)
+          return_value = CURL_FORMADD_OPTION_TWICE;
+        else
+          current_form->contentheader = list;
+
+        break;
+      }
+    case CURLFORM_FILENAME:
+    case CURLFORM_BUFFER:
+      {
+        const char *filename = array_state?array_value:
+          va_arg(params, char *);
+        if(current_form->showfilename)
+          return_value = CURL_FORMADD_OPTION_TWICE;
+        else {
+          current_form->showfilename = strdup(filename);
+          if(!current_form->showfilename)
+            return_value = CURL_FORMADD_MEMORY;
+          else
+            current_form->showfilename_alloc = TRUE;
+        }
+        break;
+      }
+    default:
+      return_value = CURL_FORMADD_UNKNOWN_OPTION;
+      break;
+    }
+  }
+
+  if(CURL_FORMADD_OK != return_value) {
+    /* On error, free allocated fields for all nodes of the FormInfo linked
+       list without deallocating nodes. List nodes are deallocated later on */
+    FormInfo *ptr;
+    for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
+      if(ptr->name_alloc) {
+        Curl_safefree(ptr->name);
+        ptr->name_alloc = FALSE;
+      }
+      if(ptr->value_alloc) {
+        Curl_safefree(ptr->value);
+        ptr->value_alloc = FALSE;
+      }
+      if(ptr->contenttype_alloc) {
+        Curl_safefree(ptr->contenttype);
+        ptr->contenttype_alloc = FALSE;
+      }
+      if(ptr->showfilename_alloc) {
+        Curl_safefree(ptr->showfilename);
+        ptr->showfilename_alloc = FALSE;
+      }
+    }
+  }
+
+  if(CURL_FORMADD_OK == return_value) {
+    /* go through the list, check for completeness and if everything is
+     * alright add the HttpPost item otherwise set return_value accordingly */
+
+    post = NULL;
+    for(form = first_form;
+        form != NULL;
+        form = form->more) {
+      if(((!form->name || !form->value) && !post) ||
+         ( (form->contentslength) &&
+           (form->flags & HTTPPOST_FILENAME) ) ||
+         ( (form->flags & HTTPPOST_FILENAME) &&
+           (form->flags & HTTPPOST_PTRCONTENTS) ) ||
+
+         ( (!form->buffer) &&
+           (form->flags & HTTPPOST_BUFFER) &&
+           (form->flags & HTTPPOST_PTRBUFFER) ) ||
+
+         ( (form->flags & HTTPPOST_READFILE) &&
+           (form->flags & HTTPPOST_PTRCONTENTS) )
+        ) {
+        return_value = CURL_FORMADD_INCOMPLETE;
+        break;
+      }
+      else {
+        if(((form->flags & HTTPPOST_FILENAME) ||
+            (form->flags & HTTPPOST_BUFFER)) &&
+           !form->contenttype) {
+          char *f = form->flags & HTTPPOST_BUFFER?
+            form->showfilename : form->value;
+
+          /* our contenttype is missing */
+          form->contenttype = strdup(ContentTypeForFilename(f, prevtype));
+          if(!form->contenttype) {
+            return_value = CURL_FORMADD_MEMORY;
+            break;
+          }
+          form->contenttype_alloc = TRUE;
+        }
+        if(!(form->flags & HTTPPOST_PTRNAME) &&
+           (form == first_form) ) {
+          /* Note that there's small risk that form->name is NULL here if the
+             app passed in a bad combo, so we better check for that first. */
+          if(form->name) {
+            /* copy name (without strdup; possibly contains null characters) */
+            form->name = Curl_memdup(form->name, form->namelength?
+                                     form->namelength:
+                                     strlen(form->name)+1);
+          }
+          if(!form->name) {
+            return_value = CURL_FORMADD_MEMORY;
+            break;
+          }
+          form->name_alloc = TRUE;
+        }
+        if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
+                            HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
+                            HTTPPOST_CALLBACK)) && form->value) {
+          /* copy value (without strdup; possibly contains null characters) */
+          size_t clen  = (size_t) form->contentslength;
+          if(!clen)
+            clen = strlen(form->value)+1;
+
+          form->value = Curl_memdup(form->value, clen);
+
+          if(!form->value) {
+            return_value = CURL_FORMADD_MEMORY;
+            break;
+          }
+          form->value_alloc = TRUE;
+        }
+        post = AddHttpPost(form->name, form->namelength,
+                           form->value, form->contentslength,
+                           form->buffer, form->bufferlength,
+                           form->contenttype, form->flags,
+                           form->contentheader, form->showfilename,
+                           form->userp,
+                           post, httppost,
+                           last_post);
+
+        if(!post) {
+          return_value = CURL_FORMADD_MEMORY;
+          break;
+        }
+
+        if(form->contenttype)
+          prevtype = form->contenttype;
+      }
+    }
+    if(CURL_FORMADD_OK != return_value) {
+      /* On error, free allocated fields for nodes of the FormInfo linked
+         list which are not already owned by the httppost linked list
+         without deallocating nodes. List nodes are deallocated later on */
+      FormInfo *ptr;
+      for(ptr = form; ptr != NULL; ptr = ptr->more) {
+        if(ptr->name_alloc) {
+          Curl_safefree(ptr->name);
+          ptr->name_alloc = FALSE;
+        }
+        if(ptr->value_alloc) {
+          Curl_safefree(ptr->value);
+          ptr->value_alloc = FALSE;
+        }
+        if(ptr->contenttype_alloc) {
+          Curl_safefree(ptr->contenttype);
+          ptr->contenttype_alloc = FALSE;
+        }
+        if(ptr->showfilename_alloc) {
+          Curl_safefree(ptr->showfilename);
+          ptr->showfilename_alloc = FALSE;
+        }
+      }
+    }
+  }
+
+  /* Always deallocate FormInfo linked list nodes without touching node
+     fields given that these have either been deallocated or are owned
+     now by the httppost linked list */
+  while(first_form) {
+    FormInfo *ptr = first_form->more;
+    free(first_form);
+    first_form = ptr;
+  }
+
+  return return_value;
+}
+
+/*
+ * curl_formadd() is a public API to add a section to the multipart formpost.
+ *
+ * @unittest: 1308
+ */
+
+CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+                          struct curl_httppost **last_post,
+                          ...)
+{
+  va_list arg;
+  CURLFORMcode result;
+  va_start(arg, last_post);
+  result = FormAdd(httppost, last_post, arg);
+  va_end(arg);
+  return result;
+}
+
+#ifdef __VMS
+#include <fabdef.h>
+/*
+ * get_vms_file_size does what it takes to get the real size of the file
+ *
+ * For fixed files, find out the size of the EOF block and adjust.
+ *
+ * For all others, have to read the entire file in, discarding the contents.
+ * Most posted text files will be small, and binary files like zlib archives
+ * and CD/DVD images should be either a STREAM_LF format or a fixed format.
+ *
+ */
+curl_off_t VmsRealFileSize(const char * name,
+                           const struct_stat * stat_buf)
+{
+  char buffer[8192];
+  curl_off_t count;
+  int ret_stat;
+  FILE * file;
+
+  file = fopen(name, FOPEN_READTEXT); /* VMS */
+  if(file == NULL)
+    return 0;
+
+  count = 0;
+  ret_stat = 1;
+  while(ret_stat > 0) {
+    ret_stat = fread(buffer, 1, sizeof(buffer), file);
+    if(ret_stat != 0)
+      count += ret_stat;
+  }
+  fclose(file);
+
+  return count;
+}
+
+/*
+ *
+ *  VmsSpecialSize checks to see if the stat st_size can be trusted and
+ *  if not to call a routine to get the correct size.
+ *
+ */
+static curl_off_t VmsSpecialSize(const char * name,
+                                 const struct_stat * stat_buf)
+{
+  switch(stat_buf->st_fab_rfm) {
+  case FAB$C_VAR:
+  case FAB$C_VFC:
+    return VmsRealFileSize(name, stat_buf);
+    break;
+  default:
+    return stat_buf->st_size;
+  }
+}
+
+#endif
+
+#ifndef __VMS
+#define filesize(name, stat_data) (stat_data.st_size)
+#else
+    /* Getting the expected file size needs help on VMS */
+#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
+#endif
+
+/*
+ * AddFormData() adds a chunk of data to the FormData linked list.
+ *
+ * size is incremented by the chunk length, unless it is NULL
+ */
+static CURLcode AddFormData(struct FormData **formp,
+                            enum formtype type,
+                            const void *line,
+                            curl_off_t length,
+                            curl_off_t *size)
+{
+  struct FormData *newform;
+  char *alloc2 = NULL;
+  CURLcode result = CURLE_OK;
+  if(length < 0 || (size && *size < 0))
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  newform = (FormData*) malloc(sizeof(struct FormData));
+  if(!newform)
+    return CURLE_OUT_OF_MEMORY;
+  newform->next = NULL;
+
+  if(type <= FORM_CONTENT) {
+    /* we make it easier for plain strings: */
+    if(!length)
+      length = strlen((char *)line);
+#if (SIZEOF_SIZE_T < CURL_SIZEOF_CURL_OFF_T)
+    else if(length >= (curl_off_t)(size_t)-1) {
+      result = CURLE_BAD_FUNCTION_ARGUMENT;
+      goto error;
+    }
+#endif
+
+    newform->line = (char*)malloc((size_t)length+1);
+    if(!newform->line) {
+      result = CURLE_OUT_OF_MEMORY;
+      goto error;
+    }
+    alloc2 = newform->line;
+    memcpy(newform->line, line, (size_t)length);
+    newform->length = (size_t)length;
+    newform->line[(size_t)length]=0; /* zero terminate for easier debugging */
+  }
+  else
+    /* For callbacks and files we don't have any actual data so we just keep a
+       pointer to whatever this points to */
+    newform->line = (char *)line;
+
+  newform->type = type;
+
+  if(*formp) {
+    (*formp)->next = newform;
+    *formp = newform;
+  }
+  else
+    *formp = newform;
+
+  if(size) {
+    if(type != FORM_FILE)
+      /* for static content as well as callback data we add the size given
+         as input argument */
+      *size += length;
+    else {
+      /* Since this is a file to be uploaded here, add the size of the actual
+         file */
+      if(!strequal("-", newform->line))
+      {
+        int b;
+        
+        #ifdef WIN32
+            struct _stat64 file;
+            CA2W uFile(newform->line, CP_UTF8 );
+            b = _wstati64(uFile, &file);
+        #else
+            struct_stat file;
+            b = stat(newform->line, &file);
+        #endif
+        
+        if(!b && !S_ISDIR(file.st_mode))
+          *size += filesize(newform->line, file);
+        else {
+          result = CURLE_BAD_FUNCTION_ARGUMENT;
+          goto error;
+        }
+      }
+    }
+  }
+  return CURLE_OK;
+  error:
+  if(newform)
+    free(newform);
+  if(alloc2)
+    free(alloc2);
+  return result;
+}
+
+/*
+ * AddFormDataf() adds printf()-style formatted data to the formdata chain.
+ */
+
+static CURLcode AddFormDataf(struct FormData **formp,
+                             curl_off_t *size,
+                             const char *fmt, ...)
+{
+  char s[4096];
+  va_list ap;
+  va_start(ap, fmt);
+  vsnprintf(s, sizeof(s), fmt, ap);
+  va_end(ap);
+
+  return AddFormData(formp, FORM_DATA, s, 0, size);
+}
+
+/*
+ * Curl_formclean() is used from http.c, this cleans a built FormData linked
+ * list
+ */
+void Curl_formclean(struct FormData **form_ptr)
+{
+  struct FormData *next, *form;
+
+  form = *form_ptr;
+  if(!form)
+    return;
+
+  do {
+    next=form->next;  /* the following form line */
+    if(form->type <= FORM_CONTENT)
+      free(form->line); /* free the line */
+    free(form);       /* free the struct */
+
+  } while((form = next) != NULL); /* continue */
+
+  *form_ptr = NULL;
+}
+
+/*
+ * curl_formget()
+ * Serialize a curl_httppost struct.
+ * Returns 0 on success.
+ *
+ * @unittest: 1308
+ */
+int curl_formget(struct curl_httppost *form, void *arg,
+                 curl_formget_callback append)
+{
+  CURLcode result;
+  curl_off_t size;
+  struct FormData *data, *ptr;
+
+  result = Curl_getformdata(NULL, &data, form, NULL, &size);
+  if(result)
+    return (int)result;
+
+  for(ptr = data; ptr; ptr = ptr->next) {
+    if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) {
+      char buffer[8192];
+      size_t nread;
+      struct Form temp;
+
+      Curl_FormInit(&temp, ptr);
+
+      do {
+        nread = readfromfile(&temp, buffer, sizeof(buffer));
+        if((nread == (size_t) -1) ||
+           (nread > sizeof(buffer)) ||
+           (nread != append(arg, buffer, nread))) {
+          if(temp.fp)
+            fclose(temp.fp);
+          Curl_formclean(&data);
+          return -1;
+        }
+      } while(nread);
+    }
+    else {
+      if(ptr->length != append(arg, ptr->line, ptr->length)) {
+        Curl_formclean(&data);
+        return -1;
+      }
+    }
+  }
+  Curl_formclean(&data);
+  return 0;
+}
+
+/*
+ * curl_formfree() is an external function to free up a whole form post
+ * chain
+ */
+void curl_formfree(struct curl_httppost *form)
+{
+  struct curl_httppost *next;
+
+  if(!form)
+    /* no form to free, just get out of this */
+    return;
+
+  do {
+    next=form->next;  /* the following form line */
+
+    /* recurse to sub-contents */
+    curl_formfree(form->more);
+
+    if(!(form->flags & HTTPPOST_PTRNAME))
+      free(form->name); /* free the name */
+    if(!(form->flags &
+         (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
+      )
+      free(form->contents); /* free the contents */
+    free(form->contenttype); /* free the content type */
+    free(form->showfilename); /* free the faked file name */
+    free(form);       /* free the struct */
+
+  } while((form = next) != NULL); /* continue */
+}
+
+#ifndef HAVE_BASENAME
+/*
+  (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
+  Edition)
+
+  The basename() function shall take the pathname pointed to by path and
+  return a pointer to the final component of the pathname, deleting any
+  trailing '/' characters.
+
+  If the string pointed to by path consists entirely of the '/' character,
+  basename() shall return a pointer to the string "/". If the string pointed
+  to by path is exactly "//", it is implementation-defined whether '/' or "//"
+  is returned.
+
+  If path is a null pointer or points to an empty string, basename() shall
+  return a pointer to the string ".".
+
+  The basename() function may modify the string pointed to by path, and may
+  return a pointer to static storage that may then be overwritten by a
+  subsequent call to basename().
+
+  The basename() function need not be reentrant. A function that is not
+  required to be reentrant is not required to be thread-safe.
+
+*/
+static char *Curl_basename(char *path)
+{
+  /* Ignore all the details above for now and make a quick and simple
+     implementaion here */
+  char *s1;
+  char *s2;
+
+  s1=strrchr(path, '/');
+  s2=strrchr(path, '\\');
+
+  if(s1 && s2) {
+    path = (s1 > s2? s1 : s2)+1;
+  }
+  else if(s1)
+    path = s1 + 1;
+  else if(s2)
+    path = s2 + 1;
+
+  return path;
+}
+#endif
+
+static char *strippath(const char *fullfile)
+{
+  char *filename;
+  char *base;
+  filename = strdup(fullfile); /* duplicate since basename() may ruin the
+                                  buffer it works on */
+  if(!filename)
+    return NULL;
+  base = strdup(basename(filename));
+
+  free(filename); /* free temporary buffer */
+
+  return base; /* returns an allocated string or NULL ! */
+}
+
+static CURLcode formdata_add_filename(const struct curl_httppost *file,
+                                      struct FormData **form,
+                                      curl_off_t *size)
+{
+  CURLcode result = CURLE_OK;
+  char *filename = file->showfilename;
+  char *filebasename = NULL;
+  char *filename_escaped = NULL;
+
+  if(!filename) {
+    filebasename = strippath(file->contents);
+    if(!filebasename)
+      return CURLE_OUT_OF_MEMORY;
+    filename = filebasename;
+  }
+
+  if(strchr(filename, '\\') || strchr(filename, '"')) {
+    char *p0, *p1;
+
+    /* filename need be escaped */
+    filename_escaped = (char*)malloc(strlen(filename)*2+1);
+    if(!filename_escaped) {
+      free(filebasename);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    p0 = filename_escaped;
+    p1 = filename;
+    while(*p1) {
+      if(*p1 == '\\' || *p1 == '"')
+        *p0++ = '\\';
+      *p0++ = *p1++;
+    }
+    *p0 = '\0';
+    filename = filename_escaped;
+  }
+  result = AddFormDataf(form, size,
+                        "; filename=\"%s\"",
+                        filename);
+  free(filename_escaped);
+  free(filebasename);
+  return result;
+}
+
+/*
+ * Curl_getformdata() converts a linked list of "meta data" into a complete
+ * (possibly huge) multipart formdata. The input list is in 'post', while the
+ * output resulting linked lists gets stored in '*finalform'. *sizep will get
+ * the total size of the whole POST.
+ * A multipart/form_data content-type is built, unless a custom content-type
+ * is passed in 'custom_content_type'.
+ *
+ * This function will not do a failf() for the potential memory failures but
+ * should for all other errors it spots. Just note that this function MAY get
+ * a NULL pointer in the 'data' argument.
+ */
+
+CURLcode Curl_getformdata(struct Curl_easy *data,
+                          struct FormData **finalform,
+                          struct curl_httppost *post,
+                          const char *custom_content_type,
+                          curl_off_t *sizep)
+{
+  struct FormData *form = NULL;
+  struct FormData *firstform;
+  struct curl_httppost *file;
+  CURLcode result = CURLE_OK;
+
+  curl_off_t size = 0; /* support potentially ENORMOUS formposts */
+  char *boundary;
+  char *fileboundary = NULL;
+  struct curl_slist* curList;
+
+  *finalform = NULL; /* default form is empty */
+
+  if(!post)
+    return result; /* no input => no output! */
+
+  boundary = formboundary(data);
+  if(!boundary)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Make the first line of the output */
+  result = AddFormDataf(&form, NULL,
+                        "%s; boundary=%s\r\n",
+                        custom_content_type?custom_content_type:
+                        "Content-Type: multipart/form-data",
+                        boundary);
+
+  if(result) {
+    free(boundary);
+    return result;
+  }
+  /* we DO NOT include that line in the total size of the POST, since it'll be
+     part of the header! */
+
+  firstform = form;
+
+  do {
+
+    if(size) {
+      result = AddFormDataf(&form, &size, "\r\n");
+      if(result)
+        break;
+    }
+
+    /* boundary */
+    result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
+    if(result)
+      break;
+
+    /* Maybe later this should be disabled when a custom_content_type is
+       passed, since Content-Disposition is not meaningful for all multipart
+       types.
+    */
+    result = AddFormDataf(&form, &size,
+                          "Content-Disposition: form-data; name=\"");
+    if(result)
+      break;
+
+    result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
+                         &size);
+    if(result)
+      break;
+
+    result = AddFormDataf(&form, &size, "\"");
+    if(result)
+      break;
+
+    if(post->more) {
+      /* If used, this is a link to more file names, we must then do
+         the magic to include several files with the same field name */
+
+      free(fileboundary);
+      fileboundary = formboundary(data);
+      if(!fileboundary) {
+        result = CURLE_OUT_OF_MEMORY;
+        break;
+      }
+
+      result = AddFormDataf(&form, &size,
+                            "\r\nContent-Type: multipart/mixed;"
+                            " boundary=%s\r\n",
+                            fileboundary);
+      if(result)
+        break;
+    }
+
+    file = post;
+
+    do {
+
+      /* If 'showfilename' is set, that is a faked name passed on to us
+         to use to in the formpost. If that is not set, the actually used
+         local file name should be added. */
+
+      if(post->more) {
+        /* if multiple-file */
+        result = AddFormDataf(&form, &size,
+                              "\r\n--%s\r\nContent-Disposition: "
+                              "attachment",
+                              fileboundary);
+        if(result)
+          break;
+        result = formdata_add_filename(file, &form, &size);
+        if(result)
+          break;
+      }
+      else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
+                             HTTPPOST_CALLBACK)) {
+        /* it should be noted that for the HTTPPOST_FILENAME and
+           HTTPPOST_CALLBACK cases the ->showfilename struct member is always
+           assigned at this point */
+        if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) {
+          result = formdata_add_filename(post, &form, &size);
+        }
+
+        if(result)
+          break;
+      }
+
+      if(file->contenttype) {
+        /* we have a specified type */
+        result = AddFormDataf(&form, &size,
+                              "\r\nContent-Type: %s",
+                              file->contenttype);
+        if(result)
+          break;
+      }
+
+      curList = file->contentheader;
+      while(curList) {
+        /* Process the additional headers specified for this form */
+        result = AddFormDataf(&form, &size, "\r\n%s", curList->data);
+        if(result)
+          break;
+        curList = curList->next;
+      }
+      if(result)
+        break;
+
+      result = AddFormDataf(&form, &size, "\r\n\r\n");
+      if(result)
+        break;
+
+      if((post->flags & HTTPPOST_FILENAME) ||
+         (post->flags & HTTPPOST_READFILE)) {
+        /* we should include the contents from the specified file */
+        FILE *fileread;
+
+        if( strequal("-", file->contents) )
+        {
+            fileread = stdin;
+        }
+        else
+        {
+            #ifdef WIN32
+                CA2W uFile(file->contents, CP_UTF8);
+                fileread = _wfopen( uFile , L"rb");
+            #else
+                fileread = fopen(file->contents, "rb");
+            #endif
+        }
+
+        /*
+         * VMS: This only allows for stream files on VMS.  Stream files are
+         * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
+         * every record needs to have a \n appended & 1 added to SIZE
+         */
+
+        if(fileread) {
+          if(fileread != stdin) {
+            /* close the file */
+            fclose(fileread);
+            /* add the file name only - for later reading from this */
+            result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
+          }
+          else {
+            /* When uploading from stdin, we can't know the size of the file,
+             * thus must read the full file as before. We *could* use chunked
+             * transfer-encoding, but that only works for HTTP 1.1 and we
+             * can't be sure we work with such a server.
+             */
+            size_t nread;
+            char buffer[512];
+            while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
+              result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
+              if(result)
+                break;
+            }
+          }
+        }
+        else {
+          if(data)
+            failf(data, "couldn't open file \"%s\"", file->contents);
+          *finalform = NULL;
+          result = CURLE_READ_ERROR;
+        }
+      }
+      else if(post->flags & HTTPPOST_BUFFER)
+        /* include contents of buffer */
+        result = AddFormData(&form, FORM_CONTENT, post->buffer,
+                             post->bufferlength, &size);
+      else if(post->flags & HTTPPOST_CALLBACK)
+        /* the contents should be read with the callback and the size is set
+           with the contentslength */
+        result = AddFormData(&form, FORM_CALLBACK, post->userp,
+                             post->flags&CURL_HTTPPOST_LARGE?
+                             post->contentlen:post->contentslength, &size);
+      else
+        /* include the contents we got */
+        result = AddFormData(&form, FORM_CONTENT, post->contents,
+                             post->flags&CURL_HTTPPOST_LARGE?
+                             post->contentlen:post->contentslength, &size);
+      file = file->more;
+    } while(file && !result); /* for each specified file for this field */
+
+    if(result)
+      break;
+
+    if(post->more) {
+      /* this was a multiple-file inclusion, make a termination file
+         boundary: */
+      result = AddFormDataf(&form, &size,
+                           "\r\n--%s--",
+                           fileboundary);
+      if(result)
+        break;
+    }
+
+  } while((post = post->next) != NULL); /* for each field */
+
+  /* end-boundary for everything */
+  if(!result)
+    result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary);
+
+  if(result) {
+    Curl_formclean(&firstform);
+    free(fileboundary);
+    free(boundary);
+    return result;
+  }
+
+  *sizep = size;
+
+  free(fileboundary);
+  free(boundary);
+
+  *finalform = firstform;
+
+  return result;
+}
+
+/*
+ * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
+ * and resets the 'sent' counter.
+ */
+int Curl_FormInit(struct Form *form, struct FormData *formdata)
+{
+  if(!formdata)
+    return 1; /* error */
+
+  form->data = formdata;
+  form->sent = 0;
+  form->fp = NULL;
+  form->fread_func = ZERO_NULL;
+
+  return 0;
+}
+
+#ifndef __VMS
+# define fopen_read fopen
+#else
+  /*
+   * vmsfopenread
+   *
+   * For upload to work as expected on VMS, different optional
+   * parameters must be added to the fopen command based on
+   * record format of the file.
+   *
+   */
+# define fopen_read vmsfopenread
+static FILE * vmsfopenread(const char *file, const char *mode) {
+  struct_stat statbuf;
+  int result;
+
+  result = stat(file, &statbuf);
+
+  switch (statbuf.st_fab_rfm) {
+  case FAB$C_VAR:
+  case FAB$C_VFC:
+  case FAB$C_STMCR:
+    return fopen(file, FOPEN_READTEXT); /* VMS */
+    break;
+  default:
+    return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
+  }
+}
+#endif
+
+/*
+ * readfromfile()
+ *
+ * The read callback that this function may use can return a value larger than
+ * 'size' (which then this function returns) that indicates a problem and it
+ * must be properly dealt with
+ */
+static size_t readfromfile(struct Form *form, char *buffer,
+                           size_t size)
+{
+  size_t nread;
+  bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE;
+
+  if(callback) {
+    if(form->fread_func == ZERO_NULL)
+      return 0;
+    else
+      nread = form->fread_func(buffer, 1, size, form->data->line);
+  }
+  else {
+    if(!form->fp) {
+      /* this file hasn't yet been opened */
+      #ifdef WIN32
+        CA2W uFile(form->data->line, CP_UTF8 );
+        form->fp = _wfopen(uFile, L"rb"); /* b is for binary */
+      #else
+        form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
+      #endif
+
+      if(!form->fp)
+        return (size_t)-1; /* failure */
+    }
+    nread = fread(buffer, 1, size, form->fp);
+  }
+  if(!nread) {
+    /* this is the last chunk from the file, move on */
+    if(form->fp) {
+      fclose(form->fp);
+      form->fp = NULL;
+    }
+    form->data = form->data->next;
+  }
+
+  return nread;
+}
+
+/*
+ * Curl_FormReader() is the fread() emulation function that will be used to
+ * deliver the formdata to the transfer loop and then sent away to the peer.
+ */
+size_t Curl_FormReader(char *buffer,
+                       size_t size,
+                       size_t nitems,
+                       FILE *mydata)
+{
+  struct Form *form;
+  size_t wantedsize;
+  size_t gotsize = 0;
+
+  form=(struct Form *)mydata;
+
+  wantedsize = size * nitems;
+
+  if(!form->data)
+    return 0; /* nothing, error, empty */
+
+  if((form->data->type == FORM_FILE) ||
+     (form->data->type == FORM_CALLBACK)) {
+    gotsize = readfromfile(form, buffer, wantedsize);
+
+    if(gotsize)
+      /* If positive or -1, return. If zero, continue! */
+      return gotsize;
+  }
+  do {
+
+    if((form->data->length - form->sent) > wantedsize - gotsize) {
+
+      memcpy(buffer + gotsize, form->data->line + form->sent,
+             wantedsize - gotsize);
+
+      form->sent += wantedsize-gotsize;
+
+      return wantedsize;
+    }
+
+    memcpy(buffer+gotsize,
+           form->data->line + form->sent,
+           (form->data->length - form->sent) );
+    gotsize += form->data->length - form->sent;
+
+    form->sent = 0;
+
+    form->data = form->data->next; /* advance */
+
+  } while(form->data && (form->data->type < FORM_CALLBACK));
+  /* If we got an empty line and we have more data, we proceed to the next
+     line immediately to avoid returning zero before we've reached the end. */
+
+  return gotsize;
+}
+
+/*
+ * Curl_formpostheader() returns the first line of the formpost, the
+ * request-header part (which is not part of the request-body like the rest of
+ * the post).
+ */
+char *Curl_formpostheader(void *formp, size_t *len)
+{
+  char *header;
+  struct Form *form=(struct Form *)formp;
+
+  if(!form->data)
+    return 0; /* nothing, ERROR! */
+
+  header = form->data->line;
+  *len = form->data->length;
+
+  form->data = form->data->next; /* advance */
+
+  return header;
+}
+
+/*
+ * formboundary() creates a suitable boundary string and returns an allocated
+ * one.
+ */
+static char *formboundary(struct Curl_easy *data)
+{
+  /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
+     combinations */
+  return aprintf("------------------------%08x%08x",
+                 Curl_rand(data), Curl_rand(data));
+}
+
+#else  /* CURL_DISABLE_HTTP */
+CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+                          struct curl_httppost **last_post,
+                          ...)
+{
+  (void)httppost;
+  (void)last_post;
+  return CURL_FORMADD_DISABLED;
+}
+
+int curl_formget(struct curl_httppost *form, void *arg,
+                 curl_formget_callback append)
+{
+  (void) form;
+  (void) arg;
+  (void) append;
+  return CURL_FORMADD_DISABLED;
+}
+
+void curl_formfree(struct curl_httppost *form)
+{
+  (void)form;
+  /* does nothing HTTP is disabled */
+}
+
+
+#endif  /* !defined(CURL_DISABLE_HTTP) */
diff --git a/lib/formdata.h b/lib/formdata.h
index 6eb7c6c..179f3cf 100644
--- a/lib/formdata.h
+++ b/lib/formdata.h
@@ -68,8 +68,14 @@ typedef struct FormInfo {
   struct FormInfo *more;
 } FormInfo;
 
+#ifdef __cplusplus
+extern "C"
+#endif
 int Curl_FormInit(struct Form *form, struct FormData *formdata);
 
+#ifdef __cplusplus
+extern "C"
+#endif
 CURLcode Curl_getformdata(struct Curl_easy *data,
                           struct FormData **,
                           struct curl_httppost *post,
@@ -77,6 +83,9 @@ CURLcode Curl_getformdata(struct Curl_easy *data,
                           curl_off_t *size);
 
 /* fread() emulation */
+#ifdef __cplusplus
+extern "C"
+#endif
 size_t Curl_FormReader(char *buffer,
                        size_t size,
                        size_t nitems,
@@ -87,10 +96,16 @@ size_t Curl_FormReader(char *buffer,
  * request-header part (which is not part of the request-body like the rest of
  * the post).
  */
+#ifdef __cplusplus
+extern "C"
+#endif
 char *Curl_formpostheader(void *formp, size_t *len);
 
 char *Curl_FormBoundary(void);
 
+#ifdef __cplusplus
+extern "C"
+#endif
 void Curl_formclean(struct FormData **);
 
 CURLcode Curl_formconvert(struct Curl_easy *, struct FormData *);
diff --git a/lib/sendf.h b/lib/sendf.h
index a951a0b..9a1cea4 100644
--- a/lib/sendf.h
+++ b/lib/sendf.h
@@ -27,6 +27,9 @@
 CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *,
                     const char *fmt, ...);
 void Curl_infof(struct Curl_easy *, const char *fmt, ...);
+#ifdef __cplusplus
+extern "C"
+#endif
 void Curl_failf(struct Curl_easy *, const char *fmt, ...);
 
 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
diff --git a/lib/strdup.h b/lib/strdup.h
index 4c48ca4..d1a230d 100644
--- a/lib/strdup.h
+++ b/lib/strdup.h
@@ -26,6 +26,10 @@
 #ifndef HAVE_STRDUP
 extern char *curlx_strdup(const char *str);
 #endif
+
+#ifdef __cplusplus
+extern "C"
+#endif
 char *Curl_memdup(const char *src, size_t buffer_length);
 
 #endif /* HEADER_CURL_STRDUP_H */
diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
index f991ec9..5848e44 100644
--- a/lib/vtls/schannel.c
+++ b/lib/vtls/schannel.c
@@ -64,6 +64,10 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
+#ifdef WIN32    // Windows specific
+    #pragma comment( lib, "crypt32.lib")        //CertFreeCertificateContext
+#endif
+
 /* ALPN requires version 8.1 of the Windows SDK, which was
    shipped with Visual Studio 2013, aka _MSC_VER 1800:
 
diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h
index a41ecc3..8d38583 100644
--- a/lib/vtls/vtls.h
+++ b/lib/vtls/vtls.h
@@ -56,6 +56,9 @@ bool Curl_clone_ssl_config(struct ssl_config_data* source,
                            struct ssl_config_data* dest);
 void Curl_free_ssl_config(struct ssl_config_data* sslc);
 
+#ifdef __cplusplus
+extern "C"
+#endif
 unsigned int Curl_rand(struct Curl_easy *);
 
 int Curl_ssl_backend(void);
-- 
2.5.1.windows.1

