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