1+ #include < scratchcpp/string_pool.h>
2+ #include < scratchcpp/stringptr.h>
13#include < ctgmath>
24#include < cassert>
35#include < clocale>
@@ -17,9 +19,8 @@ extern "C"
1719 {
1820 if (v->type == ValueType::String) {
1921 assert (v->stringValue );
20- free (v->stringValue );
22+ string_pool_free (v->stringValue );
2123 v->stringValue = nullptr ;
22- v->stringSize = 0 ;
2324 }
2425 }
2526
@@ -61,12 +62,23 @@ extern "C"
6162 /* ! Assigns C string to the given value. */
6263 void value_assign_cstring (ValueData *v, const char *stringValue)
6364 {
64- if (v->type == ValueType::String) {
65- value_replaceStr (v, stringValue);
66- } else {
67- value_free (v);
68- value_initStr (v, stringValue);
65+ if (v->type != ValueType::String) {
66+ v->stringValue = string_pool_new ();
67+ v->type = ValueType::String;
6968 }
69+
70+ string_assign_cstring (v->stringValue , stringValue);
71+ }
72+
73+ /* ! Assigns string to the given value. */
74+ void value_assign_stringptr (ValueData *v, const StringPtr *stringValue)
75+ {
76+ if (v->type != ValueType::String) {
77+ v->stringValue = string_pool_new ();
78+ v->type = ValueType::String;
79+ }
80+
81+ string_assign (v->stringValue , stringValue);
7082 }
7183
7284 /* ! Assigns another value to the given value. */
@@ -80,10 +92,11 @@ extern "C"
8092 v->boolValue = another->boolValue ;
8193 } else if (another->type == ValueType::String) {
8294 if (v->type == ValueType::String)
83- value_replaceStr (v , another->stringValue );
95+ string_assign (v-> stringValue , another->stringValue );
8496 else {
85- value_free (v);
86- value_initStr (v, another->stringValue );
97+ v->stringValue = string_pool_new ();
98+ string_assign (v->stringValue , another->stringValue );
99+ v->type = ValueType::String;
87100 }
88101 }
89102
@@ -99,7 +112,8 @@ extern "C"
99112 case ValueType::Number:
100113 return value_isInf (v->numberValue );
101114 case ValueType::String:
102- return strcmp (v->stringValue , " Infinity" ) == 0 ;
115+ // TODO: Use a custom comparison function
116+ return utf8::utf16to8 (std::u16string (v->stringValue ->data )) == " Infinity" ;
103117 default :
104118 return false ;
105119 }
@@ -112,7 +126,8 @@ extern "C"
112126 case ValueType::Number:
113127 return value_isNegativeInf (v->numberValue );
114128 case ValueType::String:
115- return strcmp (v->stringValue , " -Infinity" ) == 0 ;
129+ // TODO: Use a custom comparison function
130+ return utf8::utf16to8 (std::u16string (v->stringValue ->data )) == " -Infinity" ;
116131 default :
117132 return false ;
118133 }
@@ -125,7 +140,8 @@ extern "C"
125140 case ValueType::Number:
126141 return std::isnan (v->numberValue );
127142 case ValueType::String:
128- return strcmp (v->stringValue , " NaN" ) == 0 ;
143+ // TODO: Use a custom comparison function
144+ return utf8::utf16to8 (std::u16string (v->stringValue ->data )) == " NaN" ;
129145 default :
130146 return false ;
131147 }
@@ -151,7 +167,7 @@ extern "C"
151167 case ValueType::Bool:
152168 return true ;
153169 case ValueType::String:
154- return strlen ( v->stringValue ) == 0 || value_checkString (v->stringValue ) > 0 ;
170+ return v->stringValue -> size == 0 || value_checkString (v->stringValue ) > 0 ;
155171 default :
156172 return false ;
157173 }
@@ -245,103 +261,91 @@ extern "C"
245261 /* ! Writes the string representation of the given value to dst. */
246262 void value_toString (const ValueData *v, std::string *dst)
247263 {
248- char *str = value_toCString (v);
249- dst->assign (str);
250- free (str);
264+ StringPtr *str = value_toStringPtr (v);
265+ dst->assign (utf8::utf16to8 ( std::u16string ( str-> data )) );
266+ string_pool_free (str);
251267 }
252268
253269 /* !
254270 * Returns the string representation of the given value.
255271 * \note It is the caller's responsibility to free allocated memory.
256272 */
257- char * value_toCString (const ValueData *v)
273+ StringPtr * value_toStringPtr (const ValueData *v)
258274 {
259275 if (v->type == ValueType::String) {
260- char *ret = ( char *) malloc (( strlen (v-> stringValue ) + 1 ) * sizeof ( char ) );
261- strcpy (ret, v->stringValue );
276+ StringPtr *ret = string_pool_new ( );
277+ string_assign (ret, v->stringValue );
262278 return ret;
263279 } else if (v->type == ValueType::Number)
264- return value_doubleToCString (v->numberValue );
280+ return value_doubleToStringPtr (v->numberValue );
265281 else if (v->type == ValueType::Bool) {
266- char *ret;
267-
268282 if (v->boolValue ) {
269- ret = (char *)malloc ((4 + 1 ) * sizeof (char ));
270- strcpy (ret, " true" );
283+ StringPtr *ret = string_pool_new ();
284+ string_assign_cstring (ret, " true" );
285+ return ret;
271286 } else {
272- ret = (char *)malloc ((5 + 1 ) * sizeof (char ));
273- strcpy (ret, " false" );
287+ StringPtr *ret = string_pool_new ();
288+ string_assign_cstring (ret, " false" );
289+ return ret;
274290 }
275-
276- return ret;
277- } else {
278- char *ret = (char *)malloc (sizeof (char ));
279- ret[0 ] = ' \0 ' ;
280- return ret;
281- }
291+ } else
292+ return string_pool_new ();
282293 }
283294
284295 /* ! Writes the UTF-16 representation of the given value to dst. */
285296 void value_toUtf16 (const libscratchcpp::ValueData *v, std::u16string *dst)
286297 {
287- std::string s ;
288- value_toString (v, &s );
289- dst-> assign ( utf8::utf8to16 (s) );
298+ StringPtr *str = value_toStringPtr (v) ;
299+ dst-> assign (str-> data );
300+ string_pool_free (str );
290301 }
291302
292303 /* ! Returns the RGBA quadruplet from the given color value. */
293304 Rgb value_toRgba (const ValueData *v)
294305 {
295306 // https://github.com/scratchfoundation/scratch-vm/blob/112989da0e7306eeb405a5c52616e41c2164af24/src/util/cast.js#L92-L103
296- char *string = nullptr ;
297- size_t stringLen = 0 ;
307+ StringPtr *string = nullptr ;
298308
299309 if (v->type == ValueType::Number)
300310 return v->numberValue ;
301- else if (v->type == ValueType::String) {
302- string = value_toCString (v);
303- stringLen = strlen (string);
304- } else if (v->type == ValueType::Bool)
311+ else if (v->type == ValueType::String)
312+ string = v->stringValue ;
313+ else if (v->type == ValueType::Bool)
305314 return v->boolValue ;
306315
307- if (stringLen > 0 && string[0 ] == ' #' ) {
316+ if (string-> size > 0 && string-> data [0 ] == u ' #' ) {
308317 // https://github.com/scratchfoundation/scratch-vm/blob/a4f095db5e03e072ba222fe721eeeb543c9b9c15/src/util/color.js#L60-L69
309318 // (this implementation avoids regex)
310319
311320 // Handle shorthand hex (e.g., "abc" -> "aabbcc")
312- char expandedHex[7 ] = { 0 };
313- char *ptr;
314-
315- if (stringLen == 4 ) {
316- expandedHex[0 ] = string[1 ];
317- expandedHex[1 ] = string[1 ];
318- expandedHex[2 ] = string[2 ];
319- expandedHex[3 ] = string[2 ];
320- expandedHex[4 ] = string[3 ];
321- expandedHex[5 ] = string[3 ];
321+ char16_t expandedHex[7 ] = { 0 };
322+ char16_t *ptr;
323+
324+ if (string-> size == 4 ) {
325+ expandedHex[0 ] = string-> data [1 ];
326+ expandedHex[1 ] = string-> data [1 ];
327+ expandedHex[2 ] = string-> data [2 ];
328+ expandedHex[3 ] = string-> data [2 ];
329+ expandedHex[4 ] = string-> data [3 ];
330+ expandedHex[5 ] = string-> data [3 ];
322331 ptr = expandedHex;
323- } else if (stringLen == 7 )
324- ptr = string + 1 ; // skip '#'
325- else {
326- free (string);
332+ } else if (string->size == 7 )
333+ ptr = string->data + 1 ; // skip '#'
334+ else
327335 return rgb (0 , 0 , 0 );
328- }
329336
330337 // Convert hex components to integers
331338 int r, g, b;
332339
333- if (std::sscanf (ptr, " %2x%2x%2x" , &r, &g, &b) == 3 ) {
334- free (string);
335- return rgb (r, g, b);
336- }
340+ // TODO: Do not use sscanf()
341+ std::string str = utf8::utf16to8 (std::u16string (ptr));
337342
338- free (string);
339- } else if (stringLen > 0 ) {
343+ if (std::sscanf (str.c_str (), " %2x%2x%2x" , &r, &g, &b) == 3 )
344+ return rgb (r, g, b);
345+ } else if (string->size > 0 ) {
340346 const double ret = value_stringToDouble (string);
341- free (string);
342347 return ret;
343- } else if (string)
344- free (string);
348+ }
345349
346350 return rgb (0 , 0 , 0 );
347351 }
@@ -359,27 +363,27 @@ extern "C"
359363
360364 /* !
361365 * Converts the given number to string.
362- * \note It is the caller's responsibility to free allocated memory .
366+ * \note It is the caller's responsibility to free the string .
363367 */
364- char * value_doubleToCString (double v)
368+ StringPtr * value_doubleToStringPtr (double v)
365369 {
366370 if (v == 0 ) {
367- char *ret = ( char *) malloc (( 1 + 1 ) * sizeof ( char ) );
368- strcpy (ret, " 0" );
371+ StringPtr *ret = string_pool_new ( );
372+ string_assign_cstring (ret, " 0" );
369373 return ret;
370374 } else if (std::isinf (v)) {
371375 if (v > 0 ) {
372- char *ret = ( char *) malloc (( 8 + 1 ) * sizeof ( char ) );
373- strcpy (ret, " Infinity" );
376+ StringPtr *ret = string_pool_new ( );
377+ string_assign_cstring (ret, " Infinity" );
374378 return ret;
375379 } else {
376- char *ret = ( char *) malloc (( 9 + 1 ) * sizeof ( char ) );
377- strcpy (ret, " -Infinity" );
380+ StringPtr *ret = string_pool_new ( );
381+ string_assign_cstring (ret, " -Infinity" );
378382 return ret;
379383 }
380384 } else if (std::isnan (v)) {
381- char *ret = ( char *) malloc (( 3 + 1 ) * sizeof ( char ) );
382- strcpy (ret, " NaN" );
385+ StringPtr *ret = string_pool_new ( );
386+ string_assign_cstring (ret, " NaN" );
383387 return ret;
384388 }
385389
@@ -437,39 +441,47 @@ extern "C"
437441 // Restore old locale
438442 std::setlocale (LC_NUMERIC, oldLocale.c_str ());
439443
440- return buffer;
444+ StringPtr *ret = string_pool_new ();
445+ string_assign_cstring (ret, buffer);
446+ free (buffer);
447+ return ret;
441448 }
442449
443450 /* !
444451 * Converts the given boolean to string.
445- * \note Do not free allocated memory !
452+ * \note Do not free the string !
446453 */
447- const char * value_boolToCString (bool v)
454+ const StringPtr * value_boolToStringPtr (bool v)
448455 {
449456 if (v) {
450- static const char *ret = " true" ;
451- return ret;
457+ static const std::u16string str = utf8::utf8to16 (std::string (" true" ));
458+ static const StringPtr ret = { const_cast <char16_t *>(str.c_str ()) };
459+ return &ret;
452460 } else {
453- static const char *ret = " false" ;
454- return ret;
461+ static const std::u16string str = utf8::utf8to16 (std::string (" false" ));
462+ static const StringPtr ret = { const_cast <char16_t *>(str.c_str ()) };
463+ return &ret;
455464 }
456465 }
457466
458467 /* ! Converts the given string to double. */
459- double value_stringToDouble (const char *s)
468+ double value_stringToDouble (const StringPtr *s)
460469 {
461- if (strcmp (s, " Infinity" ) == 0 )
470+ // TODO: Use a custom comparison function
471+ if (utf8::utf16to8 (std::u16string (s->data )) == " Infinity" )
462472 return std::numeric_limits<double >::infinity ();
463- else if (strcmp (s, " -Infinity " ) == 0 )
473+ else if (utf8::utf16to8 ( std::u16string (s-> data )) == " -Infinity " )
464474 return -std::numeric_limits<double >::infinity ();
465475
466- return value_stringToDoubleImpl (s);
476+ return value_stringToDoubleImpl (s-> data , s-> size );
467477 }
468478
469479 /* ! Converts the given string to boolean. */
470- bool value_stringToBool (const char *s)
480+ bool value_stringToBool (const StringPtr *s)
471481 {
472- return strlen (s) != 0 && !value_stringsEqual (s, " false" ) && strcmp (s, " 0" ) != 0 ;
482+ // TODO: Use a custom comparison function
483+ return s->size != 0 && !value_u16StringsEqual (std::u16string (s->data ), utf8::utf8to16 (std::string (" false" ))) &&
484+ !value_u16StringsEqual (std::u16string (s->data ), utf8::utf8to16 (std::string (" 0" )));
473485 }
474486
475487 /* operations */
0 commit comments