*/ REBSER *Decode_UTF_String(REBYTE *bp, REBCNT len, REBINT utf, REBFLG ccr) /* ** Do all the details to decode a string. ** Input is a byte series. Len is len of input. ** The utf is 0, 8, +/-16, +/-32. ** A special -1 means use the BOM. ** ***********************************************************************/ { REBSER *ser = BUF_UTF8; // buffer is Unicode width REBSER *dst; REBINT size; //REBFLG ccr = FALSE; // in original R3-alpha if was TRUE //@@ https://github.com/rebol/rebol-issues/issues/2336 if (utf == -1) { utf = What_UTF(bp, len); if (utf) { if (utf == 8) bp += 3, len -= 3; else if (utf == -16 || utf == 16) bp += 2, len -= 2; else if (utf == -32 || utf == 32) bp += 4, len -= 4; } } if (utf == 0 || utf == 8) { size = Decode_UTF8((REBUNI*)Reset_Buffer(ser, len), bp, len, ccr); } else if (utf == -16 || utf == 16) { size = Decode_UTF16((REBUNI*)Reset_Buffer(ser, len/2 + 1), bp, len, utf < 0, ccr); } else if (utf == -32 || utf == 32) { size = Decode_UTF32((REBUNI*)Reset_Buffer(ser, len/4 + 1), bp, len, utf < 0, ccr); } else { return NULL; } if (size < 0) { size = -size; dst = Make_Binary(size); Append_Uni_Bytes(dst, UNI_HEAD(ser), size); } else { dst = Make_Unicode(size); Append_Uni_Uni(dst, UNI_HEAD(ser), size); } return dst; }
*/ REBCHR *Val_Str_To_OS_Managed(REBSER **out, REBVAL *val) /* ** This is used to pass a REBOL value string to an OS API. ** ** The REBOL (input) string can be byte or wide sized. ** The OS (output) string is in the native OS format. ** On Windows, its a wide-char, but on Linux, its UTF-8. ** ** If we know that the string can be used directly as-is, ** (because it's in the OS size format), we can used it ** like that. ** ** !!! The series is created but just let up to the garbage ** collector to free. This is a "leaky" approach. You may ** optionally request to have the series returned if it is ** important for you to protect it from GC, but you cannot ** currently get a "freeable" series out of this. ** ***********************************************************************/ { #ifdef OS_WIDE_CHAR if (VAL_BYTE_SIZE(val)) { // On windows, we need to convert byte to wide: REBINT n = VAL_LEN(val); REBSER *up = Make_Unicode(n); // !!!"Leaks" in the sense that the GC has to take care of this MANAGE_SERIES(up); n = Decode_UTF8(UNI_HEAD(up), VAL_BIN_DATA(val), n, FALSE); SERIES_TAIL(up) = abs(n); UNI_TERM(up); if (out) *out = up; return cast(REBCHR*, UNI_HEAD(up)); } else { // Already wide, we can use it as-is: // !Assumes the OS uses same wide format! if (out) *out = VAL_SERIES(val);
// // Clipboard_Actor: C // static REB_R Clipboard_Actor(struct Reb_Call *call_, REBSER *port, REBCNT action) { REBREQ *req; REBINT result; REBVAL *arg; REBCNT refs; // refinement argument flags REBINT len; REBSER *ser; Validate_Port(port, action); arg = DS_ARGC > 1 ? D_ARG(2) : NULL; req = cast(REBREQ*, Use_Port_State(port, RDI_CLIPBOARD, sizeof(REBREQ))); switch (action) { case A_UPDATE: // Update the port object after a READ or WRITE operation. // This is normally called by the WAKE-UP function. arg = OFV(port, STD_PORT_DATA); if (req->command == RDC_READ) { // this could be executed twice: // once for an event READ, once for the CLOSE following the READ if (!req->common.data) return R_NONE; len = req->actual; if (GET_FLAG(req->flags, RRF_WIDE)) { // convert to UTF8, so that it can be converted back to string! Val_Init_Binary(arg, Make_UTF8_Binary( req->common.data, len / sizeof(REBUNI), 0, OPT_ENC_UNISRC )); } else { REBSER *ser = Make_Binary(len); memcpy(BIN_HEAD(ser), req->common.data, len); SERIES_TAIL(ser) = len; Val_Init_Binary(arg, ser); } OS_FREE(req->common.data); // release the copy buffer req->common.data = 0; } else if (req->command == RDC_WRITE) { SET_NONE(arg); // Write is done. } return R_NONE; case A_READ: // This device is opened on the READ: if (!IS_OPEN(req)) { if (OS_DO_DEVICE(req, RDC_OPEN)) fail (Error_On_Port(RE_CANNOT_OPEN, port, req->error)); } // Issue the read request: CLR_FLAG(req->flags, RRF_WIDE); // allow byte or wide chars result = OS_DO_DEVICE(req, RDC_READ); if (result < 0) fail (Error_On_Port(RE_READ_ERROR, port, req->error)); if (result > 0) return R_NONE; /* pending */ // Copy and set the string result: arg = OFV(port, STD_PORT_DATA); len = req->actual; if (GET_FLAG(req->flags, RRF_WIDE)) { // convert to UTF8, so that it can be converted back to string! Val_Init_Binary(arg, Make_UTF8_Binary( req->common.data, len / sizeof(REBUNI), 0, OPT_ENC_UNISRC )); } else { REBSER *ser = Make_Binary(len); memcpy(BIN_HEAD(ser), req->common.data, len); SERIES_TAIL(ser) = len; Val_Init_Binary(arg, ser); } *D_OUT = *arg; return R_OUT; case A_WRITE: if (!IS_STRING(arg) && !IS_BINARY(arg)) fail (Error(RE_INVALID_PORT_ARG, arg)); // This device is opened on the WRITE: if (!IS_OPEN(req)) { if (OS_DO_DEVICE(req, RDC_OPEN)) fail (Error_On_Port(RE_CANNOT_OPEN, port, req->error)); } refs = Find_Refines(call_, ALL_WRITE_REFS); // Handle /part refinement: len = VAL_LEN(arg); if (refs & AM_WRITE_PART && VAL_INT32(D_ARG(ARG_WRITE_LIMIT)) < len) len = VAL_INT32(D_ARG(ARG_WRITE_LIMIT)); // If bytes, see if we can fit it: if (SERIES_WIDE(VAL_SERIES(arg)) == 1) { #ifdef ARG_STRINGS_ALLOWED if (!All_Bytes_ASCII(VAL_BIN_DATA(arg), len)) { Val_Init_String( arg, Copy_Bytes_To_Unicode(VAL_BIN_DATA(arg), len) ); } else req->common.data = VAL_BIN_DATA(arg); #endif // Temp conversion:!!! ser = Make_Unicode(len); len = Decode_UTF8(UNI_HEAD(ser), VAL_BIN_DATA(arg), len, FALSE); SERIES_TAIL(ser) = len = abs(len); UNI_TERM(ser); Val_Init_String(arg, ser); req->common.data = cast(REBYTE*, UNI_HEAD(ser)); SET_FLAG(req->flags, RRF_WIDE); } else // If unicode (may be from above conversion), handle it: if (SERIES_WIDE(VAL_SERIES(arg)) == sizeof(REBUNI)) { req->common.data = cast(REBYTE *, VAL_UNI_DATA(arg)); SET_FLAG(req->flags, RRF_WIDE); }