xref: /aosp_15_r20/external/curl/tests/server/getpart.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker #include "server_setup.h"
25*6236dae4SAndroid Build Coastguard Worker 
26*6236dae4SAndroid Build Coastguard Worker #include "getpart.h"
27*6236dae4SAndroid Build Coastguard Worker 
28*6236dae4SAndroid Build Coastguard Worker #include "curlx.h" /* from the private lib dir */
29*6236dae4SAndroid Build Coastguard Worker 
30*6236dae4SAndroid Build Coastguard Worker #include "curl_base64.h"
31*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
32*6236dae4SAndroid Build Coastguard Worker 
33*6236dae4SAndroid Build Coastguard Worker /* include memdebug.h last */
34*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
35*6236dae4SAndroid Build Coastguard Worker 
36*6236dae4SAndroid Build Coastguard Worker #define EAT_SPACE(p) while(*(p) && ISSPACE(*(p))) (p)++
37*6236dae4SAndroid Build Coastguard Worker 
38*6236dae4SAndroid Build Coastguard Worker #define EAT_WORD(p)  while(*(p) && !ISSPACE(*(p)) && ('>' != *(p))) (p)++
39*6236dae4SAndroid Build Coastguard Worker 
40*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUG_GETPART
41*6236dae4SAndroid Build Coastguard Worker #define show(x) printf x
42*6236dae4SAndroid Build Coastguard Worker #else
43*6236dae4SAndroid Build Coastguard Worker #define show(x) Curl_nop_stmt
44*6236dae4SAndroid Build Coastguard Worker #endif
45*6236dae4SAndroid Build Coastguard Worker 
46*6236dae4SAndroid Build Coastguard Worker #if defined(_MSC_VER) && defined(_DLL)
47*6236dae4SAndroid Build Coastguard Worker #  pragma warning(push)
48*6236dae4SAndroid Build Coastguard Worker #  pragma warning(disable:4232) /* MSVC extension, dllimport identity */
49*6236dae4SAndroid Build Coastguard Worker #endif
50*6236dae4SAndroid Build Coastguard Worker 
51*6236dae4SAndroid Build Coastguard Worker curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
52*6236dae4SAndroid Build Coastguard Worker curl_free_callback Curl_cfree = (curl_free_callback)free;
53*6236dae4SAndroid Build Coastguard Worker curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
54*6236dae4SAndroid Build Coastguard Worker curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)strdup;
55*6236dae4SAndroid Build Coastguard Worker curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
56*6236dae4SAndroid Build Coastguard Worker #if defined(_WIN32) && defined(UNICODE)
57*6236dae4SAndroid Build Coastguard Worker curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
58*6236dae4SAndroid Build Coastguard Worker #endif
59*6236dae4SAndroid Build Coastguard Worker 
60*6236dae4SAndroid Build Coastguard Worker #if defined(_MSC_VER) && defined(_DLL)
61*6236dae4SAndroid Build Coastguard Worker #  pragma warning(pop)
62*6236dae4SAndroid Build Coastguard Worker #endif
63*6236dae4SAndroid Build Coastguard Worker 
64*6236dae4SAndroid Build Coastguard Worker 
65*6236dae4SAndroid Build Coastguard Worker /*
66*6236dae4SAndroid Build Coastguard Worker  * line_length()
67*6236dae4SAndroid Build Coastguard Worker  *
68*6236dae4SAndroid Build Coastguard Worker  * Counts the number of characters in a line including a new line.
69*6236dae4SAndroid Build Coastguard Worker  * Unlike strlen() it does not stop at nul bytes.
70*6236dae4SAndroid Build Coastguard Worker  *
71*6236dae4SAndroid Build Coastguard Worker  */
line_length(const char * buffer,int bytestocheck)72*6236dae4SAndroid Build Coastguard Worker static size_t line_length(const char *buffer, int bytestocheck)
73*6236dae4SAndroid Build Coastguard Worker {
74*6236dae4SAndroid Build Coastguard Worker   size_t length = 1;
75*6236dae4SAndroid Build Coastguard Worker 
76*6236dae4SAndroid Build Coastguard Worker   while(*buffer != '\n' && --bytestocheck) {
77*6236dae4SAndroid Build Coastguard Worker     length++;
78*6236dae4SAndroid Build Coastguard Worker     buffer++;
79*6236dae4SAndroid Build Coastguard Worker   }
80*6236dae4SAndroid Build Coastguard Worker   if(*buffer != '\n') {
81*6236dae4SAndroid Build Coastguard Worker     /*
82*6236dae4SAndroid Build Coastguard Worker      * We didn't find a new line so the last byte must be a
83*6236dae4SAndroid Build Coastguard Worker      * '\0' character inserted by fgets() which we should not
84*6236dae4SAndroid Build Coastguard Worker      * count.
85*6236dae4SAndroid Build Coastguard Worker      */
86*6236dae4SAndroid Build Coastguard Worker     length--;
87*6236dae4SAndroid Build Coastguard Worker   }
88*6236dae4SAndroid Build Coastguard Worker 
89*6236dae4SAndroid Build Coastguard Worker   return length;
90*6236dae4SAndroid Build Coastguard Worker }
91*6236dae4SAndroid Build Coastguard Worker 
92*6236dae4SAndroid Build Coastguard Worker /*
93*6236dae4SAndroid Build Coastguard Worker  * readline()
94*6236dae4SAndroid Build Coastguard Worker  *
95*6236dae4SAndroid Build Coastguard Worker  * Reads a complete line from a file into a dynamically allocated buffer.
96*6236dae4SAndroid Build Coastguard Worker  *
97*6236dae4SAndroid Build Coastguard Worker  * Calling function may call this multiple times with same 'buffer'
98*6236dae4SAndroid Build Coastguard Worker  * and 'bufsize' pointers to avoid multiple buffer allocations. Buffer
99*6236dae4SAndroid Build Coastguard Worker  * will be reallocated and 'bufsize' increased until whole line fits in
100*6236dae4SAndroid Build Coastguard Worker  * buffer before returning it.
101*6236dae4SAndroid Build Coastguard Worker  *
102*6236dae4SAndroid Build Coastguard Worker  * Calling function is responsible to free allocated buffer.
103*6236dae4SAndroid Build Coastguard Worker  *
104*6236dae4SAndroid Build Coastguard Worker  * This function may return:
105*6236dae4SAndroid Build Coastguard Worker  *   GPE_OUT_OF_MEMORY
106*6236dae4SAndroid Build Coastguard Worker  *   GPE_END_OF_FILE
107*6236dae4SAndroid Build Coastguard Worker  *   GPE_OK
108*6236dae4SAndroid Build Coastguard Worker  */
109*6236dae4SAndroid Build Coastguard Worker 
readline(char ** buffer,size_t * bufsize,size_t * length,FILE * stream)110*6236dae4SAndroid Build Coastguard Worker static int readline(char **buffer, size_t *bufsize, size_t *length,
111*6236dae4SAndroid Build Coastguard Worker                     FILE *stream)
112*6236dae4SAndroid Build Coastguard Worker {
113*6236dae4SAndroid Build Coastguard Worker   size_t offset = 0;
114*6236dae4SAndroid Build Coastguard Worker   char *newptr;
115*6236dae4SAndroid Build Coastguard Worker 
116*6236dae4SAndroid Build Coastguard Worker   if(!*buffer) {
117*6236dae4SAndroid Build Coastguard Worker     *buffer = calloc(1, 128);
118*6236dae4SAndroid Build Coastguard Worker     if(!*buffer)
119*6236dae4SAndroid Build Coastguard Worker       return GPE_OUT_OF_MEMORY;
120*6236dae4SAndroid Build Coastguard Worker     *bufsize = 128;
121*6236dae4SAndroid Build Coastguard Worker   }
122*6236dae4SAndroid Build Coastguard Worker 
123*6236dae4SAndroid Build Coastguard Worker   for(;;) {
124*6236dae4SAndroid Build Coastguard Worker     int bytestoread = curlx_uztosi(*bufsize - offset);
125*6236dae4SAndroid Build Coastguard Worker 
126*6236dae4SAndroid Build Coastguard Worker     if(!fgets(*buffer + offset, bytestoread, stream))
127*6236dae4SAndroid Build Coastguard Worker       return (offset != 0) ? GPE_OK : GPE_END_OF_FILE;
128*6236dae4SAndroid Build Coastguard Worker 
129*6236dae4SAndroid Build Coastguard Worker     *length = offset + line_length(*buffer + offset, bytestoread);
130*6236dae4SAndroid Build Coastguard Worker     if(*(*buffer + *length - 1) == '\n')
131*6236dae4SAndroid Build Coastguard Worker       break;
132*6236dae4SAndroid Build Coastguard Worker     offset = *length;
133*6236dae4SAndroid Build Coastguard Worker     if(*length < *bufsize - 1)
134*6236dae4SAndroid Build Coastguard Worker       continue;
135*6236dae4SAndroid Build Coastguard Worker 
136*6236dae4SAndroid Build Coastguard Worker     newptr = realloc(*buffer, *bufsize * 2);
137*6236dae4SAndroid Build Coastguard Worker     if(!newptr)
138*6236dae4SAndroid Build Coastguard Worker       return GPE_OUT_OF_MEMORY;
139*6236dae4SAndroid Build Coastguard Worker     memset(&newptr[*bufsize], 0, *bufsize);
140*6236dae4SAndroid Build Coastguard Worker     *buffer = newptr;
141*6236dae4SAndroid Build Coastguard Worker     *bufsize *= 2;
142*6236dae4SAndroid Build Coastguard Worker   }
143*6236dae4SAndroid Build Coastguard Worker 
144*6236dae4SAndroid Build Coastguard Worker   return GPE_OK;
145*6236dae4SAndroid Build Coastguard Worker }
146*6236dae4SAndroid Build Coastguard Worker 
147*6236dae4SAndroid Build Coastguard Worker /*
148*6236dae4SAndroid Build Coastguard Worker  * appenddata()
149*6236dae4SAndroid Build Coastguard Worker  *
150*6236dae4SAndroid Build Coastguard Worker  * This appends data from a given source buffer to the end of the used part of
151*6236dae4SAndroid Build Coastguard Worker  * a destination buffer. Arguments relative to the destination buffer are, the
152*6236dae4SAndroid Build Coastguard Worker  * address of a pointer to the destination buffer 'dst_buf', the length of data
153*6236dae4SAndroid Build Coastguard Worker  * in destination buffer excluding potential null string termination 'dst_len',
154*6236dae4SAndroid Build Coastguard Worker  * the allocated size of destination buffer 'dst_alloc'. All three destination
155*6236dae4SAndroid Build Coastguard Worker  * buffer arguments may be modified by this function. Arguments relative to the
156*6236dae4SAndroid Build Coastguard Worker  * source buffer are, a pointer to the source buffer 'src_buf' and indication
157*6236dae4SAndroid Build Coastguard Worker  * whether the source buffer is base64 encoded or not 'src_b64'.
158*6236dae4SAndroid Build Coastguard Worker  *
159*6236dae4SAndroid Build Coastguard Worker  * If the source buffer is indicated to be base64 encoded, this appends the
160*6236dae4SAndroid Build Coastguard Worker  * decoded data, binary or whatever, to the destination. The source buffer
161*6236dae4SAndroid Build Coastguard Worker  * may not hold binary data, only a null terminated string is valid content.
162*6236dae4SAndroid Build Coastguard Worker  *
163*6236dae4SAndroid Build Coastguard Worker  * Destination buffer will be enlarged and relocated as needed.
164*6236dae4SAndroid Build Coastguard Worker  *
165*6236dae4SAndroid Build Coastguard Worker  * Calling function is responsible to provide preallocated destination
166*6236dae4SAndroid Build Coastguard Worker  * buffer and also to deallocate it when no longer needed.
167*6236dae4SAndroid Build Coastguard Worker  *
168*6236dae4SAndroid Build Coastguard Worker  * This function may return:
169*6236dae4SAndroid Build Coastguard Worker  *   GPE_OUT_OF_MEMORY
170*6236dae4SAndroid Build Coastguard Worker  *   GPE_OK
171*6236dae4SAndroid Build Coastguard Worker  */
172*6236dae4SAndroid Build Coastguard Worker 
appenddata(char ** dst_buf,size_t * dst_len,size_t * dst_alloc,char * src_buf,size_t src_len,int src_b64)173*6236dae4SAndroid Build Coastguard Worker static int appenddata(char  **dst_buf,   /* dest buffer */
174*6236dae4SAndroid Build Coastguard Worker                       size_t *dst_len,   /* dest buffer data length */
175*6236dae4SAndroid Build Coastguard Worker                       size_t *dst_alloc, /* dest buffer allocated size */
176*6236dae4SAndroid Build Coastguard Worker                       char   *src_buf,   /* source buffer */
177*6236dae4SAndroid Build Coastguard Worker                       size_t  src_len,   /* source buffer length */
178*6236dae4SAndroid Build Coastguard Worker                       int     src_b64)   /* != 0 if source is base64 encoded */
179*6236dae4SAndroid Build Coastguard Worker {
180*6236dae4SAndroid Build Coastguard Worker   size_t need_alloc = 0;
181*6236dae4SAndroid Build Coastguard Worker 
182*6236dae4SAndroid Build Coastguard Worker   if(!src_len)
183*6236dae4SAndroid Build Coastguard Worker     return GPE_OK;
184*6236dae4SAndroid Build Coastguard Worker 
185*6236dae4SAndroid Build Coastguard Worker   need_alloc = src_len + *dst_len + 1;
186*6236dae4SAndroid Build Coastguard Worker 
187*6236dae4SAndroid Build Coastguard Worker   if(src_b64) {
188*6236dae4SAndroid Build Coastguard Worker     if(src_buf[src_len - 1] == '\r')
189*6236dae4SAndroid Build Coastguard Worker       src_len--;
190*6236dae4SAndroid Build Coastguard Worker 
191*6236dae4SAndroid Build Coastguard Worker     if(src_buf[src_len - 1] == '\n')
192*6236dae4SAndroid Build Coastguard Worker       src_len--;
193*6236dae4SAndroid Build Coastguard Worker   }
194*6236dae4SAndroid Build Coastguard Worker 
195*6236dae4SAndroid Build Coastguard Worker   /* enlarge destination buffer if required */
196*6236dae4SAndroid Build Coastguard Worker   if(need_alloc > *dst_alloc) {
197*6236dae4SAndroid Build Coastguard Worker     size_t newsize = need_alloc * 2;
198*6236dae4SAndroid Build Coastguard Worker     char *newptr = realloc(*dst_buf, newsize);
199*6236dae4SAndroid Build Coastguard Worker     if(!newptr) {
200*6236dae4SAndroid Build Coastguard Worker       return GPE_OUT_OF_MEMORY;
201*6236dae4SAndroid Build Coastguard Worker     }
202*6236dae4SAndroid Build Coastguard Worker     *dst_alloc = newsize;
203*6236dae4SAndroid Build Coastguard Worker     *dst_buf = newptr;
204*6236dae4SAndroid Build Coastguard Worker   }
205*6236dae4SAndroid Build Coastguard Worker 
206*6236dae4SAndroid Build Coastguard Worker   /* memcpy to support binary blobs */
207*6236dae4SAndroid Build Coastguard Worker   memcpy(*dst_buf + *dst_len, src_buf, src_len);
208*6236dae4SAndroid Build Coastguard Worker   *dst_len += src_len;
209*6236dae4SAndroid Build Coastguard Worker   *(*dst_buf + *dst_len) = '\0';
210*6236dae4SAndroid Build Coastguard Worker 
211*6236dae4SAndroid Build Coastguard Worker   return GPE_OK;
212*6236dae4SAndroid Build Coastguard Worker }
213*6236dae4SAndroid Build Coastguard Worker 
decodedata(char ** buf,size_t * len)214*6236dae4SAndroid Build Coastguard Worker static int decodedata(char  **buf,   /* dest buffer */
215*6236dae4SAndroid Build Coastguard Worker                       size_t *len)   /* dest buffer data length */
216*6236dae4SAndroid Build Coastguard Worker {
217*6236dae4SAndroid Build Coastguard Worker   CURLcode error = CURLE_OK;
218*6236dae4SAndroid Build Coastguard Worker   unsigned char *buf64 = NULL;
219*6236dae4SAndroid Build Coastguard Worker   size_t src_len = 0;
220*6236dae4SAndroid Build Coastguard Worker 
221*6236dae4SAndroid Build Coastguard Worker   if(!*len)
222*6236dae4SAndroid Build Coastguard Worker     return GPE_OK;
223*6236dae4SAndroid Build Coastguard Worker 
224*6236dae4SAndroid Build Coastguard Worker   /* base64 decode the given buffer */
225*6236dae4SAndroid Build Coastguard Worker   error = Curl_base64_decode(*buf, &buf64, &src_len);
226*6236dae4SAndroid Build Coastguard Worker   if(error)
227*6236dae4SAndroid Build Coastguard Worker     return GPE_OUT_OF_MEMORY;
228*6236dae4SAndroid Build Coastguard Worker 
229*6236dae4SAndroid Build Coastguard Worker   if(!src_len) {
230*6236dae4SAndroid Build Coastguard Worker     /*
231*6236dae4SAndroid Build Coastguard Worker     ** currently there is no way to tell apart an OOM condition in
232*6236dae4SAndroid Build Coastguard Worker     ** Curl_base64_decode() from zero length decoded data. For now,
233*6236dae4SAndroid Build Coastguard Worker     ** let's just assume it is an OOM condition, currently we have
234*6236dae4SAndroid Build Coastguard Worker     ** no input for this function that decodes to zero length data.
235*6236dae4SAndroid Build Coastguard Worker     */
236*6236dae4SAndroid Build Coastguard Worker     free(buf64);
237*6236dae4SAndroid Build Coastguard Worker 
238*6236dae4SAndroid Build Coastguard Worker     return GPE_OUT_OF_MEMORY;
239*6236dae4SAndroid Build Coastguard Worker   }
240*6236dae4SAndroid Build Coastguard Worker 
241*6236dae4SAndroid Build Coastguard Worker   /* memcpy to support binary blobs */
242*6236dae4SAndroid Build Coastguard Worker   memcpy(*buf, buf64, src_len);
243*6236dae4SAndroid Build Coastguard Worker   *len = src_len;
244*6236dae4SAndroid Build Coastguard Worker   *(*buf + src_len) = '\0';
245*6236dae4SAndroid Build Coastguard Worker 
246*6236dae4SAndroid Build Coastguard Worker   free(buf64);
247*6236dae4SAndroid Build Coastguard Worker 
248*6236dae4SAndroid Build Coastguard Worker   return GPE_OK;
249*6236dae4SAndroid Build Coastguard Worker }
250*6236dae4SAndroid Build Coastguard Worker 
251*6236dae4SAndroid Build Coastguard Worker /*
252*6236dae4SAndroid Build Coastguard Worker  * getpart()
253*6236dae4SAndroid Build Coastguard Worker  *
254*6236dae4SAndroid Build Coastguard Worker  * This returns whole contents of specified XML-like section and subsection
255*6236dae4SAndroid Build Coastguard Worker  * from the given file. This is mostly used to retrieve a specific part from
256*6236dae4SAndroid Build Coastguard Worker  * a test definition file for consumption by test suite servers.
257*6236dae4SAndroid Build Coastguard Worker  *
258*6236dae4SAndroid Build Coastguard Worker  * Data is returned in a dynamically allocated buffer, a pointer to this data
259*6236dae4SAndroid Build Coastguard Worker  * and the size of the data is stored at the addresses that caller specifies.
260*6236dae4SAndroid Build Coastguard Worker  *
261*6236dae4SAndroid Build Coastguard Worker  * If the returned data is a string the returned size will be the length of
262*6236dae4SAndroid Build Coastguard Worker  * the string excluding null termination. Otherwise it will just be the size
263*6236dae4SAndroid Build Coastguard Worker  * of the returned binary data.
264*6236dae4SAndroid Build Coastguard Worker  *
265*6236dae4SAndroid Build Coastguard Worker  * Calling function is responsible to free returned buffer.
266*6236dae4SAndroid Build Coastguard Worker  *
267*6236dae4SAndroid Build Coastguard Worker  * This function may return:
268*6236dae4SAndroid Build Coastguard Worker  *   GPE_NO_BUFFER_SPACE
269*6236dae4SAndroid Build Coastguard Worker  *   GPE_OUT_OF_MEMORY
270*6236dae4SAndroid Build Coastguard Worker  *   GPE_OK
271*6236dae4SAndroid Build Coastguard Worker  */
272*6236dae4SAndroid Build Coastguard Worker 
getpart(char ** outbuf,size_t * outlen,const char * main,const char * sub,FILE * stream)273*6236dae4SAndroid Build Coastguard Worker int getpart(char **outbuf, size_t *outlen,
274*6236dae4SAndroid Build Coastguard Worker             const char *main, const char *sub, FILE *stream)
275*6236dae4SAndroid Build Coastguard Worker {
276*6236dae4SAndroid Build Coastguard Worker # define MAX_TAG_LEN 200
277*6236dae4SAndroid Build Coastguard Worker   char couter[MAX_TAG_LEN + 1]; /* current outermost section */
278*6236dae4SAndroid Build Coastguard Worker   char cmain[MAX_TAG_LEN + 1];  /* current main section */
279*6236dae4SAndroid Build Coastguard Worker   char csub[MAX_TAG_LEN + 1];   /* current sub section */
280*6236dae4SAndroid Build Coastguard Worker   char ptag[MAX_TAG_LEN + 1];   /* potential tag */
281*6236dae4SAndroid Build Coastguard Worker   char patt[MAX_TAG_LEN + 1];   /* potential attributes */
282*6236dae4SAndroid Build Coastguard Worker   char *buffer = NULL;
283*6236dae4SAndroid Build Coastguard Worker   char *ptr;
284*6236dae4SAndroid Build Coastguard Worker   char *end;
285*6236dae4SAndroid Build Coastguard Worker   union {
286*6236dae4SAndroid Build Coastguard Worker     ssize_t sig;
287*6236dae4SAndroid Build Coastguard Worker      size_t uns;
288*6236dae4SAndroid Build Coastguard Worker   } len;
289*6236dae4SAndroid Build Coastguard Worker   size_t bufsize = 0;
290*6236dae4SAndroid Build Coastguard Worker   size_t outalloc = 256;
291*6236dae4SAndroid Build Coastguard Worker   size_t datalen;
292*6236dae4SAndroid Build Coastguard Worker   int in_wanted_part = 0;
293*6236dae4SAndroid Build Coastguard Worker   int base64 = 0;
294*6236dae4SAndroid Build Coastguard Worker   int nonewline = 0;
295*6236dae4SAndroid Build Coastguard Worker   int error;
296*6236dae4SAndroid Build Coastguard Worker 
297*6236dae4SAndroid Build Coastguard Worker   enum {
298*6236dae4SAndroid Build Coastguard Worker     STATE_OUTSIDE = 0,
299*6236dae4SAndroid Build Coastguard Worker     STATE_OUTER   = 1,
300*6236dae4SAndroid Build Coastguard Worker     STATE_INMAIN  = 2,
301*6236dae4SAndroid Build Coastguard Worker     STATE_INSUB   = 3,
302*6236dae4SAndroid Build Coastguard Worker     STATE_ILLEGAL = 4
303*6236dae4SAndroid Build Coastguard Worker   } state = STATE_OUTSIDE;
304*6236dae4SAndroid Build Coastguard Worker 
305*6236dae4SAndroid Build Coastguard Worker   *outlen = 0;
306*6236dae4SAndroid Build Coastguard Worker   *outbuf = malloc(outalloc);
307*6236dae4SAndroid Build Coastguard Worker   if(!*outbuf)
308*6236dae4SAndroid Build Coastguard Worker     return GPE_OUT_OF_MEMORY;
309*6236dae4SAndroid Build Coastguard Worker   *(*outbuf) = '\0';
310*6236dae4SAndroid Build Coastguard Worker 
311*6236dae4SAndroid Build Coastguard Worker   couter[0] = cmain[0] = csub[0] = ptag[0] = patt[0] = '\0';
312*6236dae4SAndroid Build Coastguard Worker 
313*6236dae4SAndroid Build Coastguard Worker   while((error = readline(&buffer, &bufsize, &datalen, stream)) == GPE_OK) {
314*6236dae4SAndroid Build Coastguard Worker 
315*6236dae4SAndroid Build Coastguard Worker     ptr = buffer;
316*6236dae4SAndroid Build Coastguard Worker     EAT_SPACE(ptr);
317*6236dae4SAndroid Build Coastguard Worker 
318*6236dae4SAndroid Build Coastguard Worker     if('<' != *ptr) {
319*6236dae4SAndroid Build Coastguard Worker       if(in_wanted_part) {
320*6236dae4SAndroid Build Coastguard Worker         show(("=> %s", buffer));
321*6236dae4SAndroid Build Coastguard Worker         error = appenddata(outbuf, outlen, &outalloc, buffer, datalen,
322*6236dae4SAndroid Build Coastguard Worker                            base64);
323*6236dae4SAndroid Build Coastguard Worker         if(error)
324*6236dae4SAndroid Build Coastguard Worker           break;
325*6236dae4SAndroid Build Coastguard Worker       }
326*6236dae4SAndroid Build Coastguard Worker       continue;
327*6236dae4SAndroid Build Coastguard Worker     }
328*6236dae4SAndroid Build Coastguard Worker 
329*6236dae4SAndroid Build Coastguard Worker     ptr++;
330*6236dae4SAndroid Build Coastguard Worker 
331*6236dae4SAndroid Build Coastguard Worker     if('/' == *ptr) {
332*6236dae4SAndroid Build Coastguard Worker       /*
333*6236dae4SAndroid Build Coastguard Worker       ** closing section tag
334*6236dae4SAndroid Build Coastguard Worker       */
335*6236dae4SAndroid Build Coastguard Worker 
336*6236dae4SAndroid Build Coastguard Worker       ptr++;
337*6236dae4SAndroid Build Coastguard Worker       end = ptr;
338*6236dae4SAndroid Build Coastguard Worker       EAT_WORD(end);
339*6236dae4SAndroid Build Coastguard Worker       len.sig = end - ptr;
340*6236dae4SAndroid Build Coastguard Worker       if(len.sig > MAX_TAG_LEN) {
341*6236dae4SAndroid Build Coastguard Worker         error = GPE_NO_BUFFER_SPACE;
342*6236dae4SAndroid Build Coastguard Worker         break;
343*6236dae4SAndroid Build Coastguard Worker       }
344*6236dae4SAndroid Build Coastguard Worker       memcpy(ptag, ptr, len.uns);
345*6236dae4SAndroid Build Coastguard Worker       ptag[len.uns] = '\0';
346*6236dae4SAndroid Build Coastguard Worker 
347*6236dae4SAndroid Build Coastguard Worker       if((STATE_INSUB == state) && !strcmp(csub, ptag)) {
348*6236dae4SAndroid Build Coastguard Worker         /* end of current sub section */
349*6236dae4SAndroid Build Coastguard Worker         state = STATE_INMAIN;
350*6236dae4SAndroid Build Coastguard Worker         csub[0] = '\0';
351*6236dae4SAndroid Build Coastguard Worker         if(in_wanted_part) {
352*6236dae4SAndroid Build Coastguard Worker           /* end of wanted part */
353*6236dae4SAndroid Build Coastguard Worker           in_wanted_part = 0;
354*6236dae4SAndroid Build Coastguard Worker 
355*6236dae4SAndroid Build Coastguard Worker           /* Do we need to base64 decode the data? */
356*6236dae4SAndroid Build Coastguard Worker           if(base64) {
357*6236dae4SAndroid Build Coastguard Worker             error = decodedata(outbuf, outlen);
358*6236dae4SAndroid Build Coastguard Worker             if(error)
359*6236dae4SAndroid Build Coastguard Worker               return error;
360*6236dae4SAndroid Build Coastguard Worker           }
361*6236dae4SAndroid Build Coastguard Worker           if(nonewline)
362*6236dae4SAndroid Build Coastguard Worker             (*outlen)--;
363*6236dae4SAndroid Build Coastguard Worker           break;
364*6236dae4SAndroid Build Coastguard Worker         }
365*6236dae4SAndroid Build Coastguard Worker       }
366*6236dae4SAndroid Build Coastguard Worker       else if((STATE_INMAIN == state) && !strcmp(cmain, ptag)) {
367*6236dae4SAndroid Build Coastguard Worker         /* end of current main section */
368*6236dae4SAndroid Build Coastguard Worker         state = STATE_OUTER;
369*6236dae4SAndroid Build Coastguard Worker         cmain[0] = '\0';
370*6236dae4SAndroid Build Coastguard Worker         if(in_wanted_part) {
371*6236dae4SAndroid Build Coastguard Worker           /* end of wanted part */
372*6236dae4SAndroid Build Coastguard Worker           in_wanted_part = 0;
373*6236dae4SAndroid Build Coastguard Worker 
374*6236dae4SAndroid Build Coastguard Worker           /* Do we need to base64 decode the data? */
375*6236dae4SAndroid Build Coastguard Worker           if(base64) {
376*6236dae4SAndroid Build Coastguard Worker             error = decodedata(outbuf, outlen);
377*6236dae4SAndroid Build Coastguard Worker             if(error)
378*6236dae4SAndroid Build Coastguard Worker               return error;
379*6236dae4SAndroid Build Coastguard Worker           }
380*6236dae4SAndroid Build Coastguard Worker           if(nonewline)
381*6236dae4SAndroid Build Coastguard Worker             (*outlen)--;
382*6236dae4SAndroid Build Coastguard Worker           break;
383*6236dae4SAndroid Build Coastguard Worker         }
384*6236dae4SAndroid Build Coastguard Worker       }
385*6236dae4SAndroid Build Coastguard Worker       else if((STATE_OUTER == state) && !strcmp(couter, ptag)) {
386*6236dae4SAndroid Build Coastguard Worker         /* end of outermost file section */
387*6236dae4SAndroid Build Coastguard Worker         state = STATE_OUTSIDE;
388*6236dae4SAndroid Build Coastguard Worker         couter[0] = '\0';
389*6236dae4SAndroid Build Coastguard Worker         if(in_wanted_part) {
390*6236dae4SAndroid Build Coastguard Worker           /* end of wanted part */
391*6236dae4SAndroid Build Coastguard Worker           in_wanted_part = 0;
392*6236dae4SAndroid Build Coastguard Worker           break;
393*6236dae4SAndroid Build Coastguard Worker         }
394*6236dae4SAndroid Build Coastguard Worker       }
395*6236dae4SAndroid Build Coastguard Worker 
396*6236dae4SAndroid Build Coastguard Worker     }
397*6236dae4SAndroid Build Coastguard Worker     else if(!in_wanted_part) {
398*6236dae4SAndroid Build Coastguard Worker       /*
399*6236dae4SAndroid Build Coastguard Worker       ** opening section tag
400*6236dae4SAndroid Build Coastguard Worker       */
401*6236dae4SAndroid Build Coastguard Worker 
402*6236dae4SAndroid Build Coastguard Worker       /* get potential tag */
403*6236dae4SAndroid Build Coastguard Worker       end = ptr;
404*6236dae4SAndroid Build Coastguard Worker       EAT_WORD(end);
405*6236dae4SAndroid Build Coastguard Worker       len.sig = end - ptr;
406*6236dae4SAndroid Build Coastguard Worker       if(len.sig > MAX_TAG_LEN) {
407*6236dae4SAndroid Build Coastguard Worker         error = GPE_NO_BUFFER_SPACE;
408*6236dae4SAndroid Build Coastguard Worker         break;
409*6236dae4SAndroid Build Coastguard Worker       }
410*6236dae4SAndroid Build Coastguard Worker       memcpy(ptag, ptr, len.uns);
411*6236dae4SAndroid Build Coastguard Worker       ptag[len.uns] = '\0';
412*6236dae4SAndroid Build Coastguard Worker 
413*6236dae4SAndroid Build Coastguard Worker       /* ignore comments, doctypes and xml declarations */
414*6236dae4SAndroid Build Coastguard Worker       if(('!' == ptag[0]) || ('?' == ptag[0])) {
415*6236dae4SAndroid Build Coastguard Worker         show(("* ignoring (%s)", buffer));
416*6236dae4SAndroid Build Coastguard Worker         continue;
417*6236dae4SAndroid Build Coastguard Worker       }
418*6236dae4SAndroid Build Coastguard Worker 
419*6236dae4SAndroid Build Coastguard Worker       /* get all potential attributes */
420*6236dae4SAndroid Build Coastguard Worker       ptr = end;
421*6236dae4SAndroid Build Coastguard Worker       EAT_SPACE(ptr);
422*6236dae4SAndroid Build Coastguard Worker       end = ptr;
423*6236dae4SAndroid Build Coastguard Worker       while(*end && ('>' != *end))
424*6236dae4SAndroid Build Coastguard Worker         end++;
425*6236dae4SAndroid Build Coastguard Worker       len.sig = end - ptr;
426*6236dae4SAndroid Build Coastguard Worker       if(len.sig > MAX_TAG_LEN) {
427*6236dae4SAndroid Build Coastguard Worker         error = GPE_NO_BUFFER_SPACE;
428*6236dae4SAndroid Build Coastguard Worker         break;
429*6236dae4SAndroid Build Coastguard Worker       }
430*6236dae4SAndroid Build Coastguard Worker       memcpy(patt, ptr, len.uns);
431*6236dae4SAndroid Build Coastguard Worker       patt[len.uns] = '\0';
432*6236dae4SAndroid Build Coastguard Worker 
433*6236dae4SAndroid Build Coastguard Worker       if(STATE_OUTSIDE == state) {
434*6236dae4SAndroid Build Coastguard Worker         /* outermost element (<testcase>) */
435*6236dae4SAndroid Build Coastguard Worker         strcpy(couter, ptag);
436*6236dae4SAndroid Build Coastguard Worker         state = STATE_OUTER;
437*6236dae4SAndroid Build Coastguard Worker         continue;
438*6236dae4SAndroid Build Coastguard Worker       }
439*6236dae4SAndroid Build Coastguard Worker       else if(STATE_OUTER == state) {
440*6236dae4SAndroid Build Coastguard Worker         /* start of a main section */
441*6236dae4SAndroid Build Coastguard Worker         strcpy(cmain, ptag);
442*6236dae4SAndroid Build Coastguard Worker         state = STATE_INMAIN;
443*6236dae4SAndroid Build Coastguard Worker         continue;
444*6236dae4SAndroid Build Coastguard Worker       }
445*6236dae4SAndroid Build Coastguard Worker       else if(STATE_INMAIN == state) {
446*6236dae4SAndroid Build Coastguard Worker         /* start of a sub section */
447*6236dae4SAndroid Build Coastguard Worker         strcpy(csub, ptag);
448*6236dae4SAndroid Build Coastguard Worker         state = STATE_INSUB;
449*6236dae4SAndroid Build Coastguard Worker         if(!strcmp(cmain, main) && !strcmp(csub, sub)) {
450*6236dae4SAndroid Build Coastguard Worker           /* start of wanted part */
451*6236dae4SAndroid Build Coastguard Worker           in_wanted_part = 1;
452*6236dae4SAndroid Build Coastguard Worker           if(strstr(patt, "base64="))
453*6236dae4SAndroid Build Coastguard Worker               /* bit rough test, but "mostly" functional, */
454*6236dae4SAndroid Build Coastguard Worker               /* treat wanted part data as base64 encoded */
455*6236dae4SAndroid Build Coastguard Worker               base64 = 1;
456*6236dae4SAndroid Build Coastguard Worker           if(strstr(patt, "nonewline=")) {
457*6236dae4SAndroid Build Coastguard Worker             show(("* setting nonewline\n"));
458*6236dae4SAndroid Build Coastguard Worker             nonewline = 1;
459*6236dae4SAndroid Build Coastguard Worker           }
460*6236dae4SAndroid Build Coastguard Worker         }
461*6236dae4SAndroid Build Coastguard Worker         continue;
462*6236dae4SAndroid Build Coastguard Worker       }
463*6236dae4SAndroid Build Coastguard Worker 
464*6236dae4SAndroid Build Coastguard Worker     }
465*6236dae4SAndroid Build Coastguard Worker 
466*6236dae4SAndroid Build Coastguard Worker     if(in_wanted_part) {
467*6236dae4SAndroid Build Coastguard Worker       show(("=> %s", buffer));
468*6236dae4SAndroid Build Coastguard Worker       error = appenddata(outbuf, outlen, &outalloc, buffer, datalen, base64);
469*6236dae4SAndroid Build Coastguard Worker       if(error)
470*6236dae4SAndroid Build Coastguard Worker         break;
471*6236dae4SAndroid Build Coastguard Worker     }
472*6236dae4SAndroid Build Coastguard Worker 
473*6236dae4SAndroid Build Coastguard Worker   } /* while */
474*6236dae4SAndroid Build Coastguard Worker 
475*6236dae4SAndroid Build Coastguard Worker   free(buffer);
476*6236dae4SAndroid Build Coastguard Worker 
477*6236dae4SAndroid Build Coastguard Worker   if(error != GPE_OK) {
478*6236dae4SAndroid Build Coastguard Worker     if(error == GPE_END_OF_FILE)
479*6236dae4SAndroid Build Coastguard Worker       error = GPE_OK;
480*6236dae4SAndroid Build Coastguard Worker     else {
481*6236dae4SAndroid Build Coastguard Worker       free(*outbuf);
482*6236dae4SAndroid Build Coastguard Worker       *outbuf = NULL;
483*6236dae4SAndroid Build Coastguard Worker       *outlen = 0;
484*6236dae4SAndroid Build Coastguard Worker     }
485*6236dae4SAndroid Build Coastguard Worker   }
486*6236dae4SAndroid Build Coastguard Worker 
487*6236dae4SAndroid Build Coastguard Worker   return error;
488*6236dae4SAndroid Build Coastguard Worker }
489