@@ -67,7 +67,7 @@ inline std::string tag_get(SEXP object, const char *tag)
6767 case STRSXP:
6868 if (Rf_length (val) > 0 )
6969 {
70- return std::string (CHAR (STRING_ELT (val, 0 )));
70+ return std::string (Rf_translateCharUTF8 (STRING_ELT (val, 0 )));
7171 }
7272 break ;
7373 case LGLSXP:
@@ -135,8 +135,8 @@ std::string type(SEXP object)
135135}
136136
137137// -------------------- Forward declaration --------------------
138- // This function will be defined later and called recursively
139- std::string json_build_any (SEXP values);
138+ // Internal function that builds JSON and returns std::string (used internally)
139+ std::string json_build_internal (SEXP values);
140140
141141// -------------------- Helper function to safely convert to string --------------------
142142// This function converts an SEXP to a string representation, handling various R types.
@@ -151,17 +151,17 @@ std::string safe_as_string(SEXP x)
151151 switch (type)
152152 {
153153 case STRSXP:
154- // Directly return string for character SEXPs
155- return std::string (CHAR (STRING_ELT (x, 0 )));
154+ // Directly return string for character SEXPs, ensuring UTF-8 encoding
155+ return std::string (Rf_translateCharUTF8 (STRING_ELT (x, 0 )));
156156 case INTSXP:
157157 case REALSXP:
158158 case LGLSXP:
159159 case RAWSXP:
160160 // Coerce to character and then return string for numeric, logical, raw
161- return std::string (CHAR (STRING_ELT (Rf_coerceVector (x, STRSXP), 0 )));
161+ return std::string (Rf_translateCharUTF8 (STRING_ELT (Rf_coerceVector (x, STRSXP), 0 )));
162162 default :
163163 // Coerce any other type to character as a fallback
164- return std::string (CHAR (STRING_ELT (Rf_coerceVector (x, STRSXP), 0 )));
164+ return std::string (Rf_translateCharUTF8 (STRING_ELT (Rf_coerceVector (x, STRSXP), 0 )));
165165 }
166166}
167167
@@ -255,7 +255,7 @@ std::string json_build_list(SEXP values)
255255 for (R_xlen_t i = 0 ; i < n; i++)
256256 {
257257 // Recursively build JSON for each element
258- std::string elem_json = json_build_any (VECTOR_ELT (values, i));
258+ std::string elem_json = json_build_internal (VECTOR_ELT (values, i));
259259 // Only add non-empty elements, excluding "empty" JSON array/object strings
260260 if (!elem_json.empty () && elem_json != " []" && elem_json != " {}" )
261261 {
@@ -325,7 +325,7 @@ std::string json_build_structure(SEXP values)
325325 }
326326
327327 // Recursively build JSON for the payload's value
328- return json_build_any (payload_val);
328+ return json_build_internal (payload_val);
329329 }
330330
331331 SEXP names = Rf_getAttrib (values, symbol_cache.names_sym );
@@ -360,11 +360,11 @@ std::string json_build_structure(SEXP values)
360360 val = uuid_val; // Use the newly created UUID SEXP
361361 }
362362
363- std::string key = CHAR (STRING_ELT (names, i)); // Get the field name
363+ std::string key = Rf_translateCharUTF8 (STRING_ELT (names, i)); // Get the field name
364364 std::string loc_name = tag_get (val, " locationName" ); // Check for locationName tag
365365 std::string name = loc_name.empty () ? key : loc_name; // Use locationName if present
366366
367- std::string json_val = json_build_any (val); // Recursively build JSON for field value
367+ std::string json_val = json_build_internal (val); // Recursively build JSON for field value
368368 // Only add non-empty fields, excluding "empty" JSON array/object strings
369369 if (!json_val.empty () && json_val != " []" && json_val != " {}" )
370370 {
@@ -420,14 +420,14 @@ inline std::string json_build_map(SEXP values)
420420 // Populate the vector with key-value pairs from the R object
421421 for (R_xlen_t i = 0 ; i < n; ++i)
422422 {
423- std::string key = CHAR (STRING_ELT (names_sexp, i));
423+ std::string key = Rf_translateCharUTF8 (STRING_ELT (names_sexp, i));
424424 SEXP val = VECTOR_ELT (values, i);
425425 named_elements.push_back ({key, val});
426426 }
427427
428428 // Sort the vector based on the string key in each pair
429429 std::sort (named_elements.begin (), named_elements.end (),
430- [](const auto &a, const auto &b)
430+ [](const std::pair<std::string, SEXP> &a, const std::pair<std::string, SEXP> &b)
431431 {
432432 return a.first < b.first ;
433433 });
@@ -442,7 +442,7 @@ inline std::string json_build_map(SEXP values)
442442 SEXP val = element.second ;
443443
444444 // Recursively build JSON for the value
445- std::string json_val = json_build_any (val);
445+ std::string json_val = json_build_internal (val);
446446
447447 // Only add non-empty pairs to the final JSON string
448448 if (!json_val.empty () && json_val != " []" && json_val != " {}" )
@@ -469,17 +469,8 @@ inline std::string json_build_map(SEXP values)
469469 return result;
470470}
471471
472- /* *
473- * @brief Build Json Strings Using AWS Attributes for JSON Template
474- *
475- * @param object A list to be parsed into JSON string
476- *
477- * @return a JSON String
478- */
479- // ' @useDynLib paws.common _paws_common_json_build_any
480- // ' @importFrom Rcpp evalCpp
481- // [[Rcpp::export]]
482- std::string json_build_any (SEXP values)
472+ // Internal implementation that returns std::string (used by recursive calls)
473+ std::string json_build_internal (SEXP values)
483474{
484475 // Determine the effective type of the R object for JSON building
485476 std::string t = type (values);
@@ -494,3 +485,20 @@ std::string json_build_any(SEXP values)
494485 // Default to scalar if none of the above, or if `type` returns "scalar"
495486 return json_build_scalar (values);
496487}
488+
489+ /* *
490+ * @brief Build Json Strings Using AWS Attributes for JSON Template
491+ *
492+ * @param object A list to be parsed into JSON string
493+ *
494+ * @return a JSON String
495+ */
496+ // ' @useDynLib paws.common _paws_common_json_build_any
497+ // ' @importFrom Rcpp evalCpp
498+ // [[Rcpp::export]]
499+ CharacterVector json_build_any (SEXP values)
500+ {
501+ // Call internal implementation and UTF-8 encode result
502+ std::string result = json_build_internal (values);
503+ return CharacterVector::create (String (result, CE_UTF8));
504+ }
0 commit comments