]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
tool_cb_wrt: split out win_console() from tool_write_cb()
authorDaniel Stenberg <daniel@haxx.se>
Tue, 5 Aug 2025 11:26:44 +0000 (13:26 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 5 Aug 2025 12:05:40 +0000 (14:05 +0200)
Closes #18180

src/tool_cb_wrt.c

index d34c1fa2eeda7db65c488cd07d73fcfc2ef93440..7b570b8e57e40c60ebcbda8974cdc43e403e64d1 100644 (file)
@@ -124,6 +124,130 @@ bool tool_create_output_file(struct OutStruct *outs,
   return TRUE;
 }
 
+#if defined(_WIN32) && !defined(UNDER_CE)
+static size_t win_console(intptr_t fhnd, struct OutStruct *outs,
+                          char *buffer, size_t bytes,
+                          size_t *retp)
+{
+  wchar_t *wc_buf;
+  DWORD wc_len, chars_written;
+  unsigned char *rbuf = (unsigned char *)buffer;
+  DWORD rlen = (DWORD)bytes;
+
+#define IS_TRAILING_BYTE(x) (0x80 <= (x) && (x) < 0xC0)
+
+  /* attempt to complete an incomplete UTF-8 sequence from previous call. the
+     sequence does not have to be well-formed. */
+  if(outs->utf8seq[0] && rlen) {
+    bool complete = false;
+    /* two byte sequence (lead byte 110yyyyy) */
+    if(0xC0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xE0) {
+      outs->utf8seq[1] = *rbuf++;
+      --rlen;
+      complete = true;
+    }
+    /* three byte sequence (lead byte 1110zzzz) */
+    else if(0xE0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xF0) {
+      if(!outs->utf8seq[1]) {
+        outs->utf8seq[1] = *rbuf++;
+        --rlen;
+      }
+      if(rlen && !outs->utf8seq[2]) {
+        outs->utf8seq[2] = *rbuf++;
+        --rlen;
+        complete = true;
+      }
+    }
+    /* four byte sequence (lead byte 11110uuu) */
+    else if(0xF0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xF8) {
+      if(!outs->utf8seq[1]) {
+        outs->utf8seq[1] = *rbuf++;
+        --rlen;
+      }
+      if(rlen && !outs->utf8seq[2]) {
+        outs->utf8seq[2] = *rbuf++;
+        --rlen;
+      }
+      if(rlen && !outs->utf8seq[3]) {
+        outs->utf8seq[3] = *rbuf++;
+        --rlen;
+        complete = true;
+      }
+    }
+
+    if(complete) {
+      WCHAR prefix[3] = {0};  /* UTF-16 (1-2 WCHARs) + NUL */
+
+      if(MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)outs->utf8seq, -1,
+                             prefix, CURL_ARRAYSIZE(prefix))) {
+        DEBUGASSERT(prefix[2] == L'\0');
+        if(!WriteConsoleW((HANDLE) fhnd, prefix, prefix[1] ? 2 : 1,
+                          &chars_written, NULL)) {
+          return CURL_WRITEFUNC_ERROR;
+        }
+      }
+      /* else: UTF-8 input was not well formed and OS is pre-Vista which drops
+         invalid characters instead of writing U+FFFD to output. */
+      memset(outs->utf8seq, 0, sizeof(outs->utf8seq));
+    }
+  }
+
+  /* suppress an incomplete utf-8 sequence at end of rbuf */
+  if(!outs->utf8seq[0] && rlen && (rbuf[rlen - 1] & 0x80)) {
+    /* check for lead byte from a two, three or four byte sequence */
+    if(0xC0 <= rbuf[rlen - 1] && rbuf[rlen - 1] < 0xF8) {
+      outs->utf8seq[0] = rbuf[rlen - 1];
+      rlen -= 1;
+    }
+    else if(rlen >= 2 && IS_TRAILING_BYTE(rbuf[rlen - 1])) {
+      /* check for lead byte from a three or four byte sequence */
+      if(0xE0 <= rbuf[rlen - 2] && rbuf[rlen - 2] < 0xF8) {
+        outs->utf8seq[0] = rbuf[rlen - 2];
+        outs->utf8seq[1] = rbuf[rlen - 1];
+        rlen -= 2;
+      }
+      else if(rlen >= 3 && IS_TRAILING_BYTE(rbuf[rlen - 2])) {
+        /* check for lead byte from a four byte sequence */
+        if(0xF0 <= rbuf[rlen - 3] && rbuf[rlen - 3] < 0xF8) {
+          outs->utf8seq[0] = rbuf[rlen - 3];
+          outs->utf8seq[1] = rbuf[rlen - 2];
+          outs->utf8seq[2] = rbuf[rlen - 1];
+          rlen -= 3;
+        }
+      }
+    }
+  }
+
+  if(rlen) {
+    /* calculate buffer size for wide characters */
+    wc_len = (DWORD)MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)rbuf, (int)rlen,
+                                        NULL, 0);
+    if(!wc_len)
+      return CURL_WRITEFUNC_ERROR;
+
+    wc_buf = (wchar_t*) malloc(wc_len * sizeof(wchar_t));
+    if(!wc_buf)
+      return CURL_WRITEFUNC_ERROR;
+
+    wc_len = (DWORD)MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)rbuf, (int)rlen,
+                                        wc_buf, (int)wc_len);
+    if(!wc_len) {
+      free(wc_buf);
+      return CURL_WRITEFUNC_ERROR;
+    }
+
+    if(!WriteConsoleW((HANDLE) fhnd, wc_buf, wc_len, &chars_written, NULL)) {
+      free(wc_buf);
+      return CURL_WRITEFUNC_ERROR;
+    }
+    free(wc_buf);
+  }
+
+  *retp = bytes;
+  return 0;
+}
+#endif
+
 /*
 ** callback for CURLOPT_WRITEFUNCTION
 */
@@ -215,131 +339,9 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
   /* if Windows console then UTF-8 must be converted to UTF-16 */
   if(isatty(fileno(outs->stream)) &&
      GetConsoleScreenBufferInfo((HANDLE)fhnd, &console_info)) {
-    wchar_t *wc_buf;
-    DWORD wc_len, chars_written;
-    unsigned char *rbuf = (unsigned char *)buffer;
-    DWORD rlen = (DWORD)bytes;
-
-#define IS_TRAILING_BYTE(x) (0x80 <= (x) && (x) < 0xC0)
-
-    /* attempt to complete an incomplete UTF-8 sequence from previous call.
-       the sequence does not have to be well-formed. */
-    if(outs->utf8seq[0] && rlen) {
-      bool complete = false;
-      /* two byte sequence (lead byte 110yyyyy) */
-      if(0xC0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xE0) {
-        outs->utf8seq[1] = *rbuf++;
-        --rlen;
-        complete = true;
-      }
-      /* three byte sequence (lead byte 1110zzzz) */
-      else if(0xE0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xF0) {
-        if(!outs->utf8seq[1]) {
-          outs->utf8seq[1] = *rbuf++;
-          --rlen;
-        }
-        if(rlen && !outs->utf8seq[2]) {
-          outs->utf8seq[2] = *rbuf++;
-          --rlen;
-          complete = true;
-        }
-      }
-      /* four byte sequence (lead byte 11110uuu) */
-      else if(0xF0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xF8) {
-        if(!outs->utf8seq[1]) {
-          outs->utf8seq[1] = *rbuf++;
-          --rlen;
-        }
-        if(rlen && !outs->utf8seq[2]) {
-          outs->utf8seq[2] = *rbuf++;
-          --rlen;
-        }
-        if(rlen && !outs->utf8seq[3]) {
-          outs->utf8seq[3] = *rbuf++;
-          --rlen;
-          complete = true;
-        }
-      }
-
-      if(complete) {
-        WCHAR prefix[3] = {0};  /* UTF-16 (1-2 WCHARs) + NUL */
-
-        if(MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)outs->utf8seq, -1,
-                               prefix, CURL_ARRAYSIZE(prefix))) {
-          DEBUGASSERT(prefix[2] == L'\0');
-          if(!WriteConsoleW(
-              (HANDLE) fhnd,
-              prefix,
-              prefix[1] ? 2 : 1,
-              &chars_written,
-              NULL)) {
-            return CURL_WRITEFUNC_ERROR;
-          }
-        }
-        /* else: UTF-8 input was not well formed and OS is pre-Vista which
-           drops invalid characters instead of writing U+FFFD to output.  */
-
-        memset(outs->utf8seq, 0, sizeof(outs->utf8seq));
-      }
-    }
-
-    /* suppress an incomplete utf-8 sequence at end of rbuf */
-    if(!outs->utf8seq[0] && rlen && (rbuf[rlen - 1] & 0x80)) {
-      /* check for lead byte from a two, three or four byte sequence */
-      if(0xC0 <= rbuf[rlen - 1] && rbuf[rlen - 1] < 0xF8) {
-        outs->utf8seq[0] = rbuf[rlen - 1];
-        rlen -= 1;
-      }
-      else if(rlen >= 2 && IS_TRAILING_BYTE(rbuf[rlen - 1])) {
-        /* check for lead byte from a three or four byte sequence */
-        if(0xE0 <= rbuf[rlen - 2] && rbuf[rlen - 2] < 0xF8) {
-          outs->utf8seq[0] = rbuf[rlen - 2];
-          outs->utf8seq[1] = rbuf[rlen - 1];
-          rlen -= 2;
-        }
-        else if(rlen >= 3 && IS_TRAILING_BYTE(rbuf[rlen - 2])) {
-          /* check for lead byte from a four byte sequence */
-          if(0xF0 <= rbuf[rlen - 3] && rbuf[rlen - 3] < 0xF8) {
-            outs->utf8seq[0] = rbuf[rlen - 3];
-            outs->utf8seq[1] = rbuf[rlen - 2];
-            outs->utf8seq[2] = rbuf[rlen - 1];
-            rlen -= 3;
-          }
-        }
-      }
-    }
-
-    if(rlen) {
-      /* calculate buffer size for wide characters */
-      wc_len = (DWORD)MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)rbuf, (int)rlen,
-                                          NULL, 0);
-      if(!wc_len)
-        return CURL_WRITEFUNC_ERROR;
-
-      wc_buf = (wchar_t*) malloc(wc_len * sizeof(wchar_t));
-      if(!wc_buf)
-        return CURL_WRITEFUNC_ERROR;
-
-      wc_len = (DWORD)MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)rbuf, (int)rlen,
-                                          wc_buf, (int)wc_len);
-      if(!wc_len) {
-        free(wc_buf);
-        return CURL_WRITEFUNC_ERROR;
-      }
-
-      if(!WriteConsoleW(
-          (HANDLE) fhnd,
-          wc_buf,
-          wc_len,
-          &chars_written,
-          NULL)) {
-        free(wc_buf);
-        return CURL_WRITEFUNC_ERROR;
-      }
-      free(wc_buf);
-    }
-
-    rc = bytes;
+    size_t retval = win_console(fhnd, outs, buffer, bytes, &rc);
+    if(retval)
+      return retval;
   }
   else
 #endif