@@ -602,17 +602,23 @@ zend_result php_json_escape_string(
602602 pos ++ ;
603603 len -- ;
604604 } else {
605- if (pos ) {
606- smart_str_appendl (buf , s , pos );
607- s += pos ;
608- pos = 0 ;
609- }
610605 if (UNEXPECTED (us >= 0x80 )) {
611606 zend_result status ;
612- us = php_next_utf8_char ((unsigned char * )s , len , & pos , & status );
607+ size_t pos_old = pos ;
608+ const char * cur = s + pos ;
609+ pos = 0 ;
610+ us = php_next_utf8_char ((unsigned char * )cur , len , & pos , & status );
611+ pos += pos_old ;
612+ len -= pos - pos_old ;
613613
614614 /* check whether UTF8 character is correct */
615615 if (UNEXPECTED (status != SUCCESS )) {
616+ if (pos_old && (options & (PHP_JSON_INVALID_UTF8_IGNORE |PHP_JSON_INVALID_UTF8_SUBSTITUTE ))) {
617+ smart_str_appendl (buf , s , pos_old );
618+ s += pos ;
619+ pos = 0 ;
620+ }
621+
616622 if (options & PHP_JSON_INVALID_UTF8_IGNORE ) {
617623 /* ignore invalid UTF8 character */
618624 } else if (options & PHP_JSON_INVALID_UTF8_SUBSTITUTE ) {
@@ -637,8 +643,14 @@ zend_result php_json_escape_string(
637643 } else if ((options & PHP_JSON_UNESCAPED_UNICODE )
638644 && ((options & PHP_JSON_UNESCAPED_LINE_TERMINATORS )
639645 || us < 0x2028 || us > 0x2029 )) {
640- smart_str_appendl ( buf , s , pos );
646+ /* No need to emit any bytes, just move the cursor. */
641647 } else {
648+ if (pos_old ) {
649+ smart_str_appendl (buf , s , pos_old );
650+ }
651+ s += pos ;
652+ pos = 0 ;
653+
642654 /* From http://en.wikipedia.org/wiki/UTF16 */
643655 if (us >= 0x10000 ) {
644656 unsigned int next_us ;
@@ -663,10 +675,12 @@ zend_result php_json_escape_string(
663675 dst [4 ] = digits [(us >> 4 ) & 0xf ];
664676 dst [5 ] = digits [us & 0xf ];
665677 }
666- s += pos ;
667- len -= pos ;
668- pos = 0 ;
669678 } else {
679+ if (pos ) {
680+ smart_str_appendl (buf , s , pos );
681+ s += pos ;
682+ pos = 0 ;
683+ }
670684 s ++ ;
671685 switch (us ) {
672686 case '\b' :
0 commit comments