xref: /aosp_15_r20/external/curl/src/tool_cb_wrt.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 "tool_setup.h"
25*6236dae4SAndroid Build Coastguard Worker 
26*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_FCNTL_H
27*6236dae4SAndroid Build Coastguard Worker /* for open() */
28*6236dae4SAndroid Build Coastguard Worker #include <fcntl.h>
29*6236dae4SAndroid Build Coastguard Worker #endif
30*6236dae4SAndroid Build Coastguard Worker 
31*6236dae4SAndroid Build Coastguard Worker #include <sys/stat.h>
32*6236dae4SAndroid Build Coastguard Worker 
33*6236dae4SAndroid Build Coastguard Worker #include "curlx.h"
34*6236dae4SAndroid Build Coastguard Worker 
35*6236dae4SAndroid Build Coastguard Worker #include "tool_cfgable.h"
36*6236dae4SAndroid Build Coastguard Worker #include "tool_msgs.h"
37*6236dae4SAndroid Build Coastguard Worker #include "tool_cb_wrt.h"
38*6236dae4SAndroid Build Coastguard Worker #include "tool_operate.h"
39*6236dae4SAndroid Build Coastguard Worker 
40*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h" /* keep this as LAST include */
41*6236dae4SAndroid Build Coastguard Worker 
42*6236dae4SAndroid Build Coastguard Worker #ifndef O_BINARY
43*6236dae4SAndroid Build Coastguard Worker #define O_BINARY 0
44*6236dae4SAndroid Build Coastguard Worker #endif
45*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
46*6236dae4SAndroid Build Coastguard Worker #define OPENMODE S_IREAD | S_IWRITE
47*6236dae4SAndroid Build Coastguard Worker #else
48*6236dae4SAndroid Build Coastguard Worker #define OPENMODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH
49*6236dae4SAndroid Build Coastguard Worker #endif
50*6236dae4SAndroid Build Coastguard Worker 
51*6236dae4SAndroid Build Coastguard Worker /* create/open a local file for writing, return TRUE on success */
tool_create_output_file(struct OutStruct * outs,struct OperationConfig * config)52*6236dae4SAndroid Build Coastguard Worker bool tool_create_output_file(struct OutStruct *outs,
53*6236dae4SAndroid Build Coastguard Worker                              struct OperationConfig *config)
54*6236dae4SAndroid Build Coastguard Worker {
55*6236dae4SAndroid Build Coastguard Worker   struct GlobalConfig *global;
56*6236dae4SAndroid Build Coastguard Worker   FILE *file = NULL;
57*6236dae4SAndroid Build Coastguard Worker   const char *fname = outs->filename;
58*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(outs);
59*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(config);
60*6236dae4SAndroid Build Coastguard Worker   global = config->global;
61*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(fname && *fname);
62*6236dae4SAndroid Build Coastguard Worker 
63*6236dae4SAndroid Build Coastguard Worker   if(config->file_clobber_mode == CLOBBER_ALWAYS ||
64*6236dae4SAndroid Build Coastguard Worker      (config->file_clobber_mode == CLOBBER_DEFAULT &&
65*6236dae4SAndroid Build Coastguard Worker       !outs->is_cd_filename)) {
66*6236dae4SAndroid Build Coastguard Worker     /* open file for writing */
67*6236dae4SAndroid Build Coastguard Worker     file = fopen(fname, "wb");
68*6236dae4SAndroid Build Coastguard Worker   }
69*6236dae4SAndroid Build Coastguard Worker   else {
70*6236dae4SAndroid Build Coastguard Worker     int fd;
71*6236dae4SAndroid Build Coastguard Worker     do {
72*6236dae4SAndroid Build Coastguard Worker       fd = open(fname, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, OPENMODE);
73*6236dae4SAndroid Build Coastguard Worker       /* Keep retrying in the hope that it is not interrupted sometime */
74*6236dae4SAndroid Build Coastguard Worker     } while(fd == -1 && errno == EINTR);
75*6236dae4SAndroid Build Coastguard Worker     if(config->file_clobber_mode == CLOBBER_NEVER && fd == -1) {
76*6236dae4SAndroid Build Coastguard Worker       int next_num = 1;
77*6236dae4SAndroid Build Coastguard Worker       size_t len = strlen(fname);
78*6236dae4SAndroid Build Coastguard Worker       size_t newlen = len + 13; /* nul + 1-11 digits + dot */
79*6236dae4SAndroid Build Coastguard Worker       char *newname;
80*6236dae4SAndroid Build Coastguard Worker       /* Guard against wraparound in new filename */
81*6236dae4SAndroid Build Coastguard Worker       if(newlen < len) {
82*6236dae4SAndroid Build Coastguard Worker         errorf(global, "overflow in filename generation");
83*6236dae4SAndroid Build Coastguard Worker         return FALSE;
84*6236dae4SAndroid Build Coastguard Worker       }
85*6236dae4SAndroid Build Coastguard Worker       newname = malloc(newlen);
86*6236dae4SAndroid Build Coastguard Worker       if(!newname) {
87*6236dae4SAndroid Build Coastguard Worker         errorf(global, "out of memory");
88*6236dae4SAndroid Build Coastguard Worker         return FALSE;
89*6236dae4SAndroid Build Coastguard Worker       }
90*6236dae4SAndroid Build Coastguard Worker       memcpy(newname, fname, len);
91*6236dae4SAndroid Build Coastguard Worker       newname[len] = '.';
92*6236dae4SAndroid Build Coastguard Worker       while(fd == -1 && /* have not successfully opened a file */
93*6236dae4SAndroid Build Coastguard Worker             (errno == EEXIST || errno == EISDIR) &&
94*6236dae4SAndroid Build Coastguard Worker             /* because we keep having files that already exist */
95*6236dae4SAndroid Build Coastguard Worker             next_num < 100 /* and we have not reached the retry limit */ ) {
96*6236dae4SAndroid Build Coastguard Worker         msnprintf(newname + len + 1, 12, "%d", next_num);
97*6236dae4SAndroid Build Coastguard Worker         next_num++;
98*6236dae4SAndroid Build Coastguard Worker         do {
99*6236dae4SAndroid Build Coastguard Worker           fd = open(newname, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, OPENMODE);
100*6236dae4SAndroid Build Coastguard Worker           /* Keep retrying in the hope that it is not interrupted sometime */
101*6236dae4SAndroid Build Coastguard Worker         } while(fd == -1 && errno == EINTR);
102*6236dae4SAndroid Build Coastguard Worker       }
103*6236dae4SAndroid Build Coastguard Worker       outs->filename = newname; /* remember the new one */
104*6236dae4SAndroid Build Coastguard Worker       outs->alloc_filename = TRUE;
105*6236dae4SAndroid Build Coastguard Worker     }
106*6236dae4SAndroid Build Coastguard Worker     /* An else statement to not overwrite existing files and not retry with
107*6236dae4SAndroid Build Coastguard Worker        new numbered names (which would cover
108*6236dae4SAndroid Build Coastguard Worker        config->file_clobber_mode == CLOBBER_DEFAULT && outs->is_cd_filename)
109*6236dae4SAndroid Build Coastguard Worker        is not needed because we would have failed earlier, in the while loop
110*6236dae4SAndroid Build Coastguard Worker        and `fd` would now be -1 */
111*6236dae4SAndroid Build Coastguard Worker     if(fd != -1) {
112*6236dae4SAndroid Build Coastguard Worker       file = fdopen(fd, "wb");
113*6236dae4SAndroid Build Coastguard Worker       if(!file)
114*6236dae4SAndroid Build Coastguard Worker         close(fd);
115*6236dae4SAndroid Build Coastguard Worker     }
116*6236dae4SAndroid Build Coastguard Worker   }
117*6236dae4SAndroid Build Coastguard Worker 
118*6236dae4SAndroid Build Coastguard Worker   if(!file) {
119*6236dae4SAndroid Build Coastguard Worker     warnf(global, "Failed to open the file %s: %s", fname,
120*6236dae4SAndroid Build Coastguard Worker           strerror(errno));
121*6236dae4SAndroid Build Coastguard Worker     return FALSE;
122*6236dae4SAndroid Build Coastguard Worker   }
123*6236dae4SAndroid Build Coastguard Worker   outs->s_isreg = TRUE;
124*6236dae4SAndroid Build Coastguard Worker   outs->fopened = TRUE;
125*6236dae4SAndroid Build Coastguard Worker   outs->stream = file;
126*6236dae4SAndroid Build Coastguard Worker   outs->bytes = 0;
127*6236dae4SAndroid Build Coastguard Worker   outs->init = 0;
128*6236dae4SAndroid Build Coastguard Worker   return TRUE;
129*6236dae4SAndroid Build Coastguard Worker }
130*6236dae4SAndroid Build Coastguard Worker 
131*6236dae4SAndroid Build Coastguard Worker /*
132*6236dae4SAndroid Build Coastguard Worker ** callback for CURLOPT_WRITEFUNCTION
133*6236dae4SAndroid Build Coastguard Worker */
134*6236dae4SAndroid Build Coastguard Worker 
tool_write_cb(char * buffer,size_t sz,size_t nmemb,void * userdata)135*6236dae4SAndroid Build Coastguard Worker size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
136*6236dae4SAndroid Build Coastguard Worker {
137*6236dae4SAndroid Build Coastguard Worker   size_t rc;
138*6236dae4SAndroid Build Coastguard Worker   struct per_transfer *per = userdata;
139*6236dae4SAndroid Build Coastguard Worker   struct OutStruct *outs = &per->outs;
140*6236dae4SAndroid Build Coastguard Worker   struct OperationConfig *config = per->config;
141*6236dae4SAndroid Build Coastguard Worker   size_t bytes = sz * nmemb;
142*6236dae4SAndroid Build Coastguard Worker   bool is_tty = config->global->isatty;
143*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
144*6236dae4SAndroid Build Coastguard Worker   CONSOLE_SCREEN_BUFFER_INFO console_info;
145*6236dae4SAndroid Build Coastguard Worker   intptr_t fhnd;
146*6236dae4SAndroid Build Coastguard Worker #endif
147*6236dae4SAndroid Build Coastguard Worker 
148*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUGBUILD
149*6236dae4SAndroid Build Coastguard Worker   {
150*6236dae4SAndroid Build Coastguard Worker     char *tty = curl_getenv("CURL_ISATTY");
151*6236dae4SAndroid Build Coastguard Worker     if(tty) {
152*6236dae4SAndroid Build Coastguard Worker       is_tty = TRUE;
153*6236dae4SAndroid Build Coastguard Worker       curl_free(tty);
154*6236dae4SAndroid Build Coastguard Worker     }
155*6236dae4SAndroid Build Coastguard Worker   }
156*6236dae4SAndroid Build Coastguard Worker 
157*6236dae4SAndroid Build Coastguard Worker   if(config->show_headers) {
158*6236dae4SAndroid Build Coastguard Worker     if(bytes > (size_t)CURL_MAX_HTTP_HEADER) {
159*6236dae4SAndroid Build Coastguard Worker       warnf(config->global, "Header data size exceeds single call write "
160*6236dae4SAndroid Build Coastguard Worker             "limit");
161*6236dae4SAndroid Build Coastguard Worker       return CURL_WRITEFUNC_ERROR;
162*6236dae4SAndroid Build Coastguard Worker     }
163*6236dae4SAndroid Build Coastguard Worker   }
164*6236dae4SAndroid Build Coastguard Worker   else {
165*6236dae4SAndroid Build Coastguard Worker     if(bytes > (size_t)CURL_MAX_WRITE_SIZE) {
166*6236dae4SAndroid Build Coastguard Worker       warnf(config->global, "Data size exceeds single call write limit");
167*6236dae4SAndroid Build Coastguard Worker       return CURL_WRITEFUNC_ERROR;
168*6236dae4SAndroid Build Coastguard Worker     }
169*6236dae4SAndroid Build Coastguard Worker   }
170*6236dae4SAndroid Build Coastguard Worker 
171*6236dae4SAndroid Build Coastguard Worker   {
172*6236dae4SAndroid Build Coastguard Worker     /* Some internal congruency checks on received OutStruct */
173*6236dae4SAndroid Build Coastguard Worker     bool check_fails = FALSE;
174*6236dae4SAndroid Build Coastguard Worker     if(outs->filename) {
175*6236dae4SAndroid Build Coastguard Worker       /* regular file */
176*6236dae4SAndroid Build Coastguard Worker       if(!*outs->filename)
177*6236dae4SAndroid Build Coastguard Worker         check_fails = TRUE;
178*6236dae4SAndroid Build Coastguard Worker       if(!outs->s_isreg)
179*6236dae4SAndroid Build Coastguard Worker         check_fails = TRUE;
180*6236dae4SAndroid Build Coastguard Worker       if(outs->fopened && !outs->stream)
181*6236dae4SAndroid Build Coastguard Worker         check_fails = TRUE;
182*6236dae4SAndroid Build Coastguard Worker       if(!outs->fopened && outs->stream)
183*6236dae4SAndroid Build Coastguard Worker         check_fails = TRUE;
184*6236dae4SAndroid Build Coastguard Worker       if(!outs->fopened && outs->bytes)
185*6236dae4SAndroid Build Coastguard Worker         check_fails = TRUE;
186*6236dae4SAndroid Build Coastguard Worker     }
187*6236dae4SAndroid Build Coastguard Worker     else {
188*6236dae4SAndroid Build Coastguard Worker       /* standard stream */
189*6236dae4SAndroid Build Coastguard Worker       if(!outs->stream || outs->s_isreg || outs->fopened)
190*6236dae4SAndroid Build Coastguard Worker         check_fails = TRUE;
191*6236dae4SAndroid Build Coastguard Worker       if(outs->alloc_filename || outs->is_cd_filename || outs->init)
192*6236dae4SAndroid Build Coastguard Worker         check_fails = TRUE;
193*6236dae4SAndroid Build Coastguard Worker     }
194*6236dae4SAndroid Build Coastguard Worker     if(check_fails) {
195*6236dae4SAndroid Build Coastguard Worker       warnf(config->global, "Invalid output struct data for write callback");
196*6236dae4SAndroid Build Coastguard Worker       return CURL_WRITEFUNC_ERROR;
197*6236dae4SAndroid Build Coastguard Worker     }
198*6236dae4SAndroid Build Coastguard Worker   }
199*6236dae4SAndroid Build Coastguard Worker #endif
200*6236dae4SAndroid Build Coastguard Worker 
201*6236dae4SAndroid Build Coastguard Worker   if(!outs->stream && !tool_create_output_file(outs, per->config))
202*6236dae4SAndroid Build Coastguard Worker     return CURL_WRITEFUNC_ERROR;
203*6236dae4SAndroid Build Coastguard Worker 
204*6236dae4SAndroid Build Coastguard Worker   if(is_tty && (outs->bytes < 2000) && !config->terminal_binary_ok) {
205*6236dae4SAndroid Build Coastguard Worker     /* binary output to terminal? */
206*6236dae4SAndroid Build Coastguard Worker     if(memchr(buffer, 0, bytes)) {
207*6236dae4SAndroid Build Coastguard Worker       warnf(config->global, "Binary output can mess up your terminal. "
208*6236dae4SAndroid Build Coastguard Worker             "Use \"--output -\" to tell curl to output it to your terminal "
209*6236dae4SAndroid Build Coastguard Worker             "anyway, or consider \"--output <FILE>\" to save to a file.");
210*6236dae4SAndroid Build Coastguard Worker       config->synthetic_error = TRUE;
211*6236dae4SAndroid Build Coastguard Worker       return CURL_WRITEFUNC_ERROR;
212*6236dae4SAndroid Build Coastguard Worker     }
213*6236dae4SAndroid Build Coastguard Worker   }
214*6236dae4SAndroid Build Coastguard Worker 
215*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
216*6236dae4SAndroid Build Coastguard Worker   fhnd = _get_osfhandle(fileno(outs->stream));
217*6236dae4SAndroid Build Coastguard Worker   /* if Windows console then UTF-8 must be converted to UTF-16 */
218*6236dae4SAndroid Build Coastguard Worker   if(isatty(fileno(outs->stream)) &&
219*6236dae4SAndroid Build Coastguard Worker      GetConsoleScreenBufferInfo((HANDLE)fhnd, &console_info)) {
220*6236dae4SAndroid Build Coastguard Worker     wchar_t *wc_buf;
221*6236dae4SAndroid Build Coastguard Worker     DWORD wc_len, chars_written;
222*6236dae4SAndroid Build Coastguard Worker     unsigned char *rbuf = (unsigned char *)buffer;
223*6236dae4SAndroid Build Coastguard Worker     DWORD rlen = (DWORD)bytes;
224*6236dae4SAndroid Build Coastguard Worker 
225*6236dae4SAndroid Build Coastguard Worker #define IS_TRAILING_BYTE(x) (0x80 <= (x) && (x) < 0xC0)
226*6236dae4SAndroid Build Coastguard Worker 
227*6236dae4SAndroid Build Coastguard Worker     /* attempt to complete an incomplete UTF-8 sequence from previous call.
228*6236dae4SAndroid Build Coastguard Worker        the sequence does not have to be well-formed. */
229*6236dae4SAndroid Build Coastguard Worker     if(outs->utf8seq[0] && rlen) {
230*6236dae4SAndroid Build Coastguard Worker       bool complete = false;
231*6236dae4SAndroid Build Coastguard Worker       /* two byte sequence (lead byte 110yyyyy) */
232*6236dae4SAndroid Build Coastguard Worker       if(0xC0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xE0) {
233*6236dae4SAndroid Build Coastguard Worker         outs->utf8seq[1] = *rbuf++;
234*6236dae4SAndroid Build Coastguard Worker         --rlen;
235*6236dae4SAndroid Build Coastguard Worker         complete = true;
236*6236dae4SAndroid Build Coastguard Worker       }
237*6236dae4SAndroid Build Coastguard Worker       /* three byte sequence (lead byte 1110zzzz) */
238*6236dae4SAndroid Build Coastguard Worker       else if(0xE0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xF0) {
239*6236dae4SAndroid Build Coastguard Worker         if(!outs->utf8seq[1]) {
240*6236dae4SAndroid Build Coastguard Worker           outs->utf8seq[1] = *rbuf++;
241*6236dae4SAndroid Build Coastguard Worker           --rlen;
242*6236dae4SAndroid Build Coastguard Worker         }
243*6236dae4SAndroid Build Coastguard Worker         if(rlen && !outs->utf8seq[2]) {
244*6236dae4SAndroid Build Coastguard Worker           outs->utf8seq[2] = *rbuf++;
245*6236dae4SAndroid Build Coastguard Worker           --rlen;
246*6236dae4SAndroid Build Coastguard Worker           complete = true;
247*6236dae4SAndroid Build Coastguard Worker         }
248*6236dae4SAndroid Build Coastguard Worker       }
249*6236dae4SAndroid Build Coastguard Worker       /* four byte sequence (lead byte 11110uuu) */
250*6236dae4SAndroid Build Coastguard Worker       else if(0xF0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xF8) {
251*6236dae4SAndroid Build Coastguard Worker         if(!outs->utf8seq[1]) {
252*6236dae4SAndroid Build Coastguard Worker           outs->utf8seq[1] = *rbuf++;
253*6236dae4SAndroid Build Coastguard Worker           --rlen;
254*6236dae4SAndroid Build Coastguard Worker         }
255*6236dae4SAndroid Build Coastguard Worker         if(rlen && !outs->utf8seq[2]) {
256*6236dae4SAndroid Build Coastguard Worker           outs->utf8seq[2] = *rbuf++;
257*6236dae4SAndroid Build Coastguard Worker           --rlen;
258*6236dae4SAndroid Build Coastguard Worker         }
259*6236dae4SAndroid Build Coastguard Worker         if(rlen && !outs->utf8seq[3]) {
260*6236dae4SAndroid Build Coastguard Worker           outs->utf8seq[3] = *rbuf++;
261*6236dae4SAndroid Build Coastguard Worker           --rlen;
262*6236dae4SAndroid Build Coastguard Worker           complete = true;
263*6236dae4SAndroid Build Coastguard Worker         }
264*6236dae4SAndroid Build Coastguard Worker       }
265*6236dae4SAndroid Build Coastguard Worker 
266*6236dae4SAndroid Build Coastguard Worker       if(complete) {
267*6236dae4SAndroid Build Coastguard Worker         WCHAR prefix[3] = {0};  /* UTF-16 (1-2 WCHARs) + NUL */
268*6236dae4SAndroid Build Coastguard Worker 
269*6236dae4SAndroid Build Coastguard Worker         if(MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)outs->utf8seq, -1,
270*6236dae4SAndroid Build Coastguard Worker                                prefix, sizeof(prefix)/sizeof(prefix[0]))) {
271*6236dae4SAndroid Build Coastguard Worker           DEBUGASSERT(prefix[2] == L'\0');
272*6236dae4SAndroid Build Coastguard Worker           if(!WriteConsoleW(
273*6236dae4SAndroid Build Coastguard Worker               (HANDLE) fhnd,
274*6236dae4SAndroid Build Coastguard Worker               prefix,
275*6236dae4SAndroid Build Coastguard Worker               prefix[1] ? 2 : 1,
276*6236dae4SAndroid Build Coastguard Worker               &chars_written,
277*6236dae4SAndroid Build Coastguard Worker               NULL)) {
278*6236dae4SAndroid Build Coastguard Worker             return CURL_WRITEFUNC_ERROR;
279*6236dae4SAndroid Build Coastguard Worker           }
280*6236dae4SAndroid Build Coastguard Worker         }
281*6236dae4SAndroid Build Coastguard Worker         /* else: UTF-8 input was not well formed and OS is pre-Vista which
282*6236dae4SAndroid Build Coastguard Worker            drops invalid characters instead of writing U+FFFD to output.  */
283*6236dae4SAndroid Build Coastguard Worker 
284*6236dae4SAndroid Build Coastguard Worker         memset(outs->utf8seq, 0, sizeof(outs->utf8seq));
285*6236dae4SAndroid Build Coastguard Worker       }
286*6236dae4SAndroid Build Coastguard Worker     }
287*6236dae4SAndroid Build Coastguard Worker 
288*6236dae4SAndroid Build Coastguard Worker     /* suppress an incomplete utf-8 sequence at end of rbuf */
289*6236dae4SAndroid Build Coastguard Worker     if(!outs->utf8seq[0] && rlen && (rbuf[rlen - 1] & 0x80)) {
290*6236dae4SAndroid Build Coastguard Worker       /* check for lead byte from a two, three or four byte sequence */
291*6236dae4SAndroid Build Coastguard Worker       if(0xC0 <= rbuf[rlen - 1] && rbuf[rlen - 1] < 0xF8) {
292*6236dae4SAndroid Build Coastguard Worker         outs->utf8seq[0] = rbuf[rlen - 1];
293*6236dae4SAndroid Build Coastguard Worker         rlen -= 1;
294*6236dae4SAndroid Build Coastguard Worker       }
295*6236dae4SAndroid Build Coastguard Worker       else if(rlen >= 2 && IS_TRAILING_BYTE(rbuf[rlen - 1])) {
296*6236dae4SAndroid Build Coastguard Worker         /* check for lead byte from a three or four byte sequence */
297*6236dae4SAndroid Build Coastguard Worker         if(0xE0 <= rbuf[rlen - 2] && rbuf[rlen - 2] < 0xF8) {
298*6236dae4SAndroid Build Coastguard Worker           outs->utf8seq[0] = rbuf[rlen - 2];
299*6236dae4SAndroid Build Coastguard Worker           outs->utf8seq[1] = rbuf[rlen - 1];
300*6236dae4SAndroid Build Coastguard Worker           rlen -= 2;
301*6236dae4SAndroid Build Coastguard Worker         }
302*6236dae4SAndroid Build Coastguard Worker         else if(rlen >= 3 && IS_TRAILING_BYTE(rbuf[rlen - 2])) {
303*6236dae4SAndroid Build Coastguard Worker           /* check for lead byte from a four byte sequence */
304*6236dae4SAndroid Build Coastguard Worker           if(0xF0 <= rbuf[rlen - 3] && rbuf[rlen - 3] < 0xF8) {
305*6236dae4SAndroid Build Coastguard Worker             outs->utf8seq[0] = rbuf[rlen - 3];
306*6236dae4SAndroid Build Coastguard Worker             outs->utf8seq[1] = rbuf[rlen - 2];
307*6236dae4SAndroid Build Coastguard Worker             outs->utf8seq[2] = rbuf[rlen - 1];
308*6236dae4SAndroid Build Coastguard Worker             rlen -= 3;
309*6236dae4SAndroid Build Coastguard Worker           }
310*6236dae4SAndroid Build Coastguard Worker         }
311*6236dae4SAndroid Build Coastguard Worker       }
312*6236dae4SAndroid Build Coastguard Worker     }
313*6236dae4SAndroid Build Coastguard Worker 
314*6236dae4SAndroid Build Coastguard Worker     if(rlen) {
315*6236dae4SAndroid Build Coastguard Worker       /* calculate buffer size for wide characters */
316*6236dae4SAndroid Build Coastguard Worker       wc_len = (DWORD)MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)rbuf, (int)rlen,
317*6236dae4SAndroid Build Coastguard Worker                                           NULL, 0);
318*6236dae4SAndroid Build Coastguard Worker       if(!wc_len)
319*6236dae4SAndroid Build Coastguard Worker         return CURL_WRITEFUNC_ERROR;
320*6236dae4SAndroid Build Coastguard Worker 
321*6236dae4SAndroid Build Coastguard Worker       wc_buf = (wchar_t*) malloc(wc_len * sizeof(wchar_t));
322*6236dae4SAndroid Build Coastguard Worker       if(!wc_buf)
323*6236dae4SAndroid Build Coastguard Worker         return CURL_WRITEFUNC_ERROR;
324*6236dae4SAndroid Build Coastguard Worker 
325*6236dae4SAndroid Build Coastguard Worker       wc_len = (DWORD)MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)rbuf, (int)rlen,
326*6236dae4SAndroid Build Coastguard Worker                                           wc_buf, (int)wc_len);
327*6236dae4SAndroid Build Coastguard Worker       if(!wc_len) {
328*6236dae4SAndroid Build Coastguard Worker         free(wc_buf);
329*6236dae4SAndroid Build Coastguard Worker         return CURL_WRITEFUNC_ERROR;
330*6236dae4SAndroid Build Coastguard Worker       }
331*6236dae4SAndroid Build Coastguard Worker 
332*6236dae4SAndroid Build Coastguard Worker       if(!WriteConsoleW(
333*6236dae4SAndroid Build Coastguard Worker           (HANDLE) fhnd,
334*6236dae4SAndroid Build Coastguard Worker           wc_buf,
335*6236dae4SAndroid Build Coastguard Worker           wc_len,
336*6236dae4SAndroid Build Coastguard Worker           &chars_written,
337*6236dae4SAndroid Build Coastguard Worker           NULL)) {
338*6236dae4SAndroid Build Coastguard Worker         free(wc_buf);
339*6236dae4SAndroid Build Coastguard Worker         return CURL_WRITEFUNC_ERROR;
340*6236dae4SAndroid Build Coastguard Worker       }
341*6236dae4SAndroid Build Coastguard Worker       free(wc_buf);
342*6236dae4SAndroid Build Coastguard Worker     }
343*6236dae4SAndroid Build Coastguard Worker 
344*6236dae4SAndroid Build Coastguard Worker     rc = bytes;
345*6236dae4SAndroid Build Coastguard Worker   }
346*6236dae4SAndroid Build Coastguard Worker   else
347*6236dae4SAndroid Build Coastguard Worker #endif
348*6236dae4SAndroid Build Coastguard Worker   {
349*6236dae4SAndroid Build Coastguard Worker     if(per->hdrcbdata.headlist) {
350*6236dae4SAndroid Build Coastguard Worker       if(tool_write_headers(&per->hdrcbdata, outs->stream))
351*6236dae4SAndroid Build Coastguard Worker         return CURL_WRITEFUNC_ERROR;
352*6236dae4SAndroid Build Coastguard Worker     }
353*6236dae4SAndroid Build Coastguard Worker     rc = fwrite(buffer, sz, nmemb, outs->stream);
354*6236dae4SAndroid Build Coastguard Worker   }
355*6236dae4SAndroid Build Coastguard Worker 
356*6236dae4SAndroid Build Coastguard Worker   if(bytes == rc)
357*6236dae4SAndroid Build Coastguard Worker     /* we added this amount of data to the output */
358*6236dae4SAndroid Build Coastguard Worker     outs->bytes += bytes;
359*6236dae4SAndroid Build Coastguard Worker 
360*6236dae4SAndroid Build Coastguard Worker   if(config->readbusy) {
361*6236dae4SAndroid Build Coastguard Worker     config->readbusy = FALSE;
362*6236dae4SAndroid Build Coastguard Worker     curl_easy_pause(per->curl, CURLPAUSE_CONT);
363*6236dae4SAndroid Build Coastguard Worker   }
364*6236dae4SAndroid Build Coastguard Worker 
365*6236dae4SAndroid Build Coastguard Worker   if(config->nobuffer) {
366*6236dae4SAndroid Build Coastguard Worker     /* output buffering disabled */
367*6236dae4SAndroid Build Coastguard Worker     int res = fflush(outs->stream);
368*6236dae4SAndroid Build Coastguard Worker     if(res)
369*6236dae4SAndroid Build Coastguard Worker       return CURL_WRITEFUNC_ERROR;
370*6236dae4SAndroid Build Coastguard Worker   }
371*6236dae4SAndroid Build Coastguard Worker 
372*6236dae4SAndroid Build Coastguard Worker   return rc;
373*6236dae4SAndroid Build Coastguard Worker }
374