getpart.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 #include "server_setup.h"
00023 
00024 #include "getpart.h"
00025 
00026 #define ENABLE_CURLX_PRINTF
00027 /* make the curlx header define all printf() functions to use the curlx_*
00028    versions instead */
00029 #include "curlx.h" /* from the private lib dir */
00030 
00031 /* just to please curl_base64.h we create a fake struct */
00032 struct Curl_easy {
00033   int fake;
00034 };
00035 
00036 #include "curl_base64.h"
00037 #include "curl_memory.h"
00038 
00039 /* include memdebug.h last */
00040 #include "memdebug.h"
00041 
00042 #define EAT_SPACE(p) while(*(p) && ISSPACE(*(p))) (p)++
00043 
00044 #define EAT_WORD(p)  while(*(p) && !ISSPACE(*(p)) && ('>' != *(p))) (p)++
00045 
00046 #ifdef DEBUG_GETPART
00047 #define show(x) printf x
00048 #else
00049 #define show(x) Curl_nop_stmt
00050 #endif
00051 
00052 #if defined(_MSC_VER) && defined(_DLL)
00053 #  pragma warning(disable:4232) /* MSVC extension, dllimport identity */
00054 #endif
00055 
00056 curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
00057 curl_free_callback Curl_cfree = (curl_free_callback)free;
00058 curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
00059 curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)strdup;
00060 curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
00061 #if defined(WIN32) && defined(UNICODE)
00062 curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
00063 #endif
00064 
00065 #if defined(_MSC_VER) && defined(_DLL)
00066 #  pragma warning(default:4232) /* MSVC extension, dllimport identity */
00067 #endif
00068 
00069 /*
00070  * readline()
00071  *
00072  * Reads a complete line from a file into a dynamically allocated buffer.
00073  *
00074  * Calling function may call this multiple times with same 'buffer'
00075  * and 'bufsize' pointers to avoid multiple buffer allocations. Buffer
00076  * will be reallocated and 'bufsize' increased until whole line fits in
00077  * buffer before returning it.
00078  *
00079  * Calling function is responsible to free allocated buffer.
00080  *
00081  * This function may return:
00082  *   GPE_OUT_OF_MEMORY
00083  *   GPE_END_OF_FILE
00084  *   GPE_OK
00085  */
00086 
00087 static int readline(char **buffer, size_t *bufsize, FILE *stream)
00088 {
00089   size_t offset = 0;
00090   size_t length;
00091   char *newptr;
00092 
00093   if(!*buffer) {
00094     *buffer = malloc(128);
00095     if(!*buffer)
00096       return GPE_OUT_OF_MEMORY;
00097     *bufsize = 128;
00098   }
00099 
00100   for(;;) {
00101     int bytestoread = curlx_uztosi(*bufsize - offset);
00102 
00103     if(!fgets(*buffer + offset, bytestoread, stream))
00104       return (offset != 0) ? GPE_OK : GPE_END_OF_FILE;
00105 
00106     length = offset + strlen(*buffer + offset);
00107     if(*(*buffer + length - 1) == '\n')
00108       break;
00109     offset = length;
00110     if(length < *bufsize - 1)
00111       continue;
00112 
00113     newptr = realloc(*buffer, *bufsize * 2);
00114     if(!newptr)
00115       return GPE_OUT_OF_MEMORY;
00116     *buffer = newptr;
00117     *bufsize *= 2;
00118   }
00119 
00120   return GPE_OK;
00121 }
00122 
00123 /*
00124  * appenddata()
00125  *
00126  * This appends data from a given source buffer to the end of the used part of
00127  * a destination buffer. Arguments relative to the destination buffer are, the
00128  * address of a pointer to the destination buffer 'dst_buf', the length of data
00129  * in destination buffer excluding potential null string termination 'dst_len',
00130  * the allocated size of destination buffer 'dst_alloc'. All three destination
00131  * buffer arguments may be modified by this function. Arguments relative to the
00132  * source buffer are, a pointer to the source buffer 'src_buf' and indication
00133  * whether the source buffer is base64 encoded or not 'src_b64'.
00134  *
00135  * If the source buffer is indicated to be base64 encoded, this appends the
00136  * decoded data, binary or whatever, to the destination. The source buffer
00137  * may not hold binary data, only a null terminated string is valid content.
00138  *
00139  * Destination buffer will be enlarged and relocated as needed.
00140  *
00141  * Calling function is responsible to provide preallocated destination
00142  * buffer and also to deallocate it when no longer needed.
00143  *
00144  * This function may return:
00145  *   GPE_OUT_OF_MEMORY
00146  *   GPE_OK
00147  */
00148 
00149 static int appenddata(char  **dst_buf,   /* dest buffer */
00150                       size_t *dst_len,   /* dest buffer data length */
00151                       size_t *dst_alloc, /* dest buffer allocated size */
00152                       char   *src_buf,   /* source buffer */
00153                       int     src_b64)   /* != 0 if source is base64 encoded */
00154 {
00155   size_t need_alloc = 0;
00156   size_t src_len = strlen(src_buf);
00157 
00158   if(!src_len)
00159     return GPE_OK;
00160 
00161   need_alloc = src_len + *dst_len + 1;
00162 
00163   if(src_b64) {
00164     if(src_buf[src_len - 1] == '\r')
00165       src_len--;
00166 
00167     if(src_buf[src_len - 1] == '\n')
00168       src_len--;
00169   }
00170 
00171   /* enlarge destination buffer if required */
00172   if(need_alloc > *dst_alloc) {
00173     size_t newsize = need_alloc * 2;
00174     char *newptr = realloc(*dst_buf, newsize);
00175     if(!newptr) {
00176       return GPE_OUT_OF_MEMORY;
00177     }
00178     *dst_alloc = newsize;
00179     *dst_buf = newptr;
00180   }
00181 
00182   /* memcpy to support binary blobs */
00183   memcpy(*dst_buf + *dst_len, src_buf, src_len);
00184   *dst_len += src_len;
00185   *(*dst_buf + *dst_len) = '\0';
00186 
00187   return GPE_OK;
00188 }
00189 
00190 static int decodedata(char  **buf,   /* dest buffer */
00191                       size_t *len)   /* dest buffer data length */
00192 {
00193   int error = 0;
00194   unsigned char *buf64 = NULL;
00195   size_t src_len = 0;
00196 
00197   if(!*len)
00198     return GPE_OK;
00199 
00200   /* base64 decode the given buffer */
00201   error = (int) Curl_base64_decode(*buf, &buf64, &src_len);
00202   if(error)
00203     return GPE_OUT_OF_MEMORY;
00204 
00205   if(!src_len) {
00206     /*
00207     ** currently there is no way to tell apart an OOM condition in
00208     ** Curl_base64_decode() from zero length decoded data. For now,
00209     ** let's just assume it is an OOM condition, currently we have
00210     ** no input for this function that decodes to zero length data.
00211     */
00212     free(buf64);
00213 
00214     return GPE_OUT_OF_MEMORY;
00215   }
00216 
00217   /* memcpy to support binary blobs */
00218   memcpy(*buf, buf64, src_len);
00219   *len = src_len;
00220   *(*buf + src_len) = '\0';
00221 
00222   free(buf64);
00223 
00224   return GPE_OK;
00225 }
00226 
00227 /*
00228  * getpart()
00229  *
00230  * This returns whole contents of specified XML-like section and subsection
00231  * from the given file. This is mostly used to retrieve a specific part from
00232  * a test definition file for consumption by test suite servers.
00233  *
00234  * Data is returned in a dynamically allocated buffer, a pointer to this data
00235  * and the size of the data is stored at the addresses that caller specifies.
00236  *
00237  * If the returned data is a string the returned size will be the length of
00238  * the string excluding null termination. Otherwise it will just be the size
00239  * of the returned binary data.
00240  *
00241  * Calling function is responsible to free returned buffer.
00242  *
00243  * This function may return:
00244  *   GPE_NO_BUFFER_SPACE
00245  *   GPE_OUT_OF_MEMORY
00246  *   GPE_OK
00247  */
00248 
00249 int getpart(char **outbuf, size_t *outlen,
00250             const char *main, const char *sub, FILE *stream)
00251 {
00252 # define MAX_TAG_LEN 79
00253   char couter[MAX_TAG_LEN+1]; /* current outermost section */
00254   char cmain[MAX_TAG_LEN+1];  /* current main section */
00255   char csub[MAX_TAG_LEN+1];   /* current sub section */
00256   char ptag[MAX_TAG_LEN+1];   /* potential tag */
00257   char patt[MAX_TAG_LEN+1];   /* potential attributes */
00258   char *buffer = NULL;
00259   char *ptr;
00260   char *end;
00261   union {
00262     ssize_t sig;
00263      size_t uns;
00264   } len;
00265   size_t bufsize = 0;
00266   size_t outalloc = 256;
00267   int in_wanted_part = 0;
00268   int base64 = 0;
00269   int error;
00270 
00271   enum {
00272     STATE_OUTSIDE = 0,
00273     STATE_OUTER   = 1,
00274     STATE_INMAIN  = 2,
00275     STATE_INSUB   = 3,
00276     STATE_ILLEGAL = 4
00277   } state = STATE_OUTSIDE;
00278 
00279   *outlen = 0;
00280   *outbuf = malloc(outalloc);
00281   if(!*outbuf)
00282     return GPE_OUT_OF_MEMORY;
00283   *(*outbuf) = '\0';
00284 
00285   couter[0] = cmain[0] = csub[0] = ptag[0] = patt[0] = '\0';
00286 
00287   while((error = readline(&buffer, &bufsize, stream)) == GPE_OK) {
00288 
00289     ptr = buffer;
00290     EAT_SPACE(ptr);
00291 
00292     if('<' != *ptr) {
00293       if(in_wanted_part) {
00294         show(("=> %s", buffer));
00295         error = appenddata(outbuf, outlen, &outalloc, buffer, base64);
00296         if(error)
00297           break;
00298       }
00299       continue;
00300     }
00301 
00302     ptr++;
00303 
00304     if('/' == *ptr) {
00305       /*
00306       ** closing section tag
00307       */
00308 
00309       ptr++;
00310       end = ptr;
00311       EAT_WORD(end);
00312       len.sig = end - ptr;
00313       if(len.sig > MAX_TAG_LEN) {
00314         error = GPE_NO_BUFFER_SPACE;
00315         break;
00316       }
00317       memcpy(ptag, ptr, len.uns);
00318       ptag[len.uns] = '\0';
00319 
00320       if((STATE_INSUB == state) && !strcmp(csub, ptag)) {
00321         /* end of current sub section */
00322         state = STATE_INMAIN;
00323         csub[0] = '\0';
00324         if(in_wanted_part) {
00325           /* end of wanted part */
00326           in_wanted_part = 0;
00327 
00328           /* Do we need to base64 decode the data? */
00329           if(base64) {
00330             error = decodedata(outbuf, outlen);
00331             if(error)
00332               return error;
00333           }
00334           break;
00335         }
00336       }
00337       else if((STATE_INMAIN == state) && !strcmp(cmain, ptag)) {
00338         /* end of current main section */
00339         state = STATE_OUTER;
00340         cmain[0] = '\0';
00341         if(in_wanted_part) {
00342           /* end of wanted part */
00343           in_wanted_part = 0;
00344 
00345           /* Do we need to base64 decode the data? */
00346           if(base64) {
00347             error = decodedata(outbuf, outlen);
00348             if(error)
00349               return error;
00350           }
00351           break;
00352         }
00353       }
00354       else if((STATE_OUTER == state) && !strcmp(couter, ptag)) {
00355         /* end of outermost file section */
00356         state = STATE_OUTSIDE;
00357         couter[0] = '\0';
00358         if(in_wanted_part) {
00359           /* end of wanted part */
00360           in_wanted_part = 0;
00361           break;
00362         }
00363       }
00364 
00365     }
00366     else if(!in_wanted_part) {
00367       /*
00368       ** opening section tag
00369       */
00370 
00371       /* get potential tag */
00372       end = ptr;
00373       EAT_WORD(end);
00374       len.sig = end - ptr;
00375       if(len.sig > MAX_TAG_LEN) {
00376         error = GPE_NO_BUFFER_SPACE;
00377         break;
00378       }
00379       memcpy(ptag, ptr, len.uns);
00380       ptag[len.uns] = '\0';
00381 
00382       /* ignore comments, doctypes and xml declarations */
00383       if(('!' == ptag[0]) || ('?' == ptag[0])) {
00384         show(("* ignoring (%s)", buffer));
00385         continue;
00386       }
00387 
00388       /* get all potential attributes */
00389       ptr = end;
00390       EAT_SPACE(ptr);
00391       end = ptr;
00392       while(*end && ('>' != *end))
00393         end++;
00394       len.sig = end - ptr;
00395       if(len.sig > MAX_TAG_LEN) {
00396         error = GPE_NO_BUFFER_SPACE;
00397         break;
00398       }
00399       memcpy(patt, ptr, len.uns);
00400       patt[len.uns] = '\0';
00401 
00402       if(STATE_OUTSIDE == state) {
00403         /* outermost element (<testcase>) */
00404         strcpy(couter, ptag);
00405         state = STATE_OUTER;
00406         continue;
00407       }
00408       else if(STATE_OUTER == state) {
00409         /* start of a main section */
00410         strcpy(cmain, ptag);
00411         state = STATE_INMAIN;
00412         continue;
00413       }
00414       else if(STATE_INMAIN == state) {
00415         /* start of a sub section */
00416         strcpy(csub, ptag);
00417         state = STATE_INSUB;
00418         if(!strcmp(cmain, main) && !strcmp(csub, sub)) {
00419           /* start of wanted part */
00420           in_wanted_part = 1;
00421           if(strstr(patt, "base64="))
00422               /* bit rough test, but "mostly" functional, */
00423               /* treat wanted part data as base64 encoded */
00424               base64 = 1;
00425         }
00426         continue;
00427       }
00428 
00429     }
00430 
00431     if(in_wanted_part) {
00432       show(("=> %s", buffer));
00433       error = appenddata(outbuf, outlen, &outalloc, buffer, base64);
00434       if(error)
00435         break;
00436     }
00437 
00438   } /* while */
00439 
00440   free(buffer);
00441 
00442   if(error != GPE_OK) {
00443     if(error == GPE_END_OF_FILE)
00444       error = GPE_OK;
00445     else {
00446       free(*outbuf);
00447       *outbuf = NULL;
00448       *outlen = 0;
00449     }
00450   }
00451 
00452   return error;
00453 }
00454 


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:02