@@ -72,7 +72,7 @@ typedef struct {
72
72
/* We return a pointer to these zvals in get_gc(), so it's
73
73
* important that a) they are adjacent b) object is the first
74
74
* and c) the number of zvals is kept up to date. */
75
- #define XML_PARSER_NUM_ZVALS 12
75
+ #define XML_PARSER_NUM_ZVALS 14
76
76
zval object ;
77
77
zval startElementHandler ;
78
78
zval endElementHandler ;
@@ -85,6 +85,8 @@ typedef struct {
85
85
zval unknownEncodingHandler ;
86
86
zval startNamespaceDeclHandler ;
87
87
zval endNamespaceDeclHandler ;
88
+ zval data ;
89
+ zval info ;
88
90
89
91
zend_function * startElementPtr ;
90
92
zend_function * endElementPtr ;
@@ -98,12 +100,10 @@ typedef struct {
98
100
zend_function * startNamespaceDeclPtr ;
99
101
zend_function * endNamespaceDeclPtr ;
100
102
101
- zval data ;
102
- zval info ;
103
103
int level ;
104
104
int toffset ;
105
105
int curtag ;
106
- zval * ctag ;
106
+ uint32_t ctag_index ;
107
107
char * * ltags ;
108
108
int lastwasopen ;
109
109
int skipwhite ;
@@ -326,6 +326,8 @@ static void xml_parser_free_obj(zend_object *object)
326
326
{
327
327
xml_parser * parser = xml_parser_from_obj (object );
328
328
329
+ zval_ptr_dtor (& parser -> info );
330
+ zval_ptr_dtor (& parser -> data );
329
331
if (parser -> parser ) {
330
332
XML_ParserFree (parser -> parser );
331
333
}
@@ -551,15 +553,18 @@ static void _xml_add_to_info(xml_parser *parser, const char *name)
551
553
{
552
554
zval * element ;
553
555
554
- if (Z_ISUNDEF (parser -> info )) {
556
+ if (Z_ISUNDEF (parser -> info ) || UNEXPECTED ( Z_TYPE_P ( Z_REFVAL ( parser -> info )) != IS_ARRAY ) ) {
555
557
return ;
556
558
}
557
559
560
+ SEPARATE_ARRAY (Z_REFVAL (parser -> info ));
561
+ zend_array * arr = Z_ARRVAL_P (Z_REFVAL (parser -> info ));
562
+
558
563
size_t name_len = strlen (name );
559
- if ((element = zend_hash_str_find (Z_ARRVAL ( parser -> info ) , name , name_len )) == NULL ) {
564
+ if ((element = zend_hash_str_find (arr , name , name_len )) == NULL ) {
560
565
zval values ;
561
566
array_init (& values );
562
- element = zend_hash_str_update (Z_ARRVAL ( parser -> info ) , name , name_len , & values );
567
+ element = zend_hash_str_update (arr , name , name_len , & values );
563
568
}
564
569
565
570
add_next_index_long (element , parser -> curtag );
@@ -583,6 +588,33 @@ static zend_string *_xml_decode_tag(xml_parser *parser, const XML_Char *tag)
583
588
}
584
589
/* }}} */
585
590
591
+ static zval * xml_get_separated_data (xml_parser * parser )
592
+ {
593
+ if (EXPECTED (Z_TYPE_P (Z_REFVAL (parser -> data )) == IS_ARRAY )) {
594
+ SEPARATE_ARRAY (Z_REFVAL (parser -> data ));
595
+ return Z_REFVAL (parser -> data );
596
+ }
597
+ return NULL ;
598
+ }
599
+
600
+ static zval * xml_get_ctag (xml_parser * parser )
601
+ {
602
+ zval * data = xml_get_separated_data (parser );
603
+ if (EXPECTED (data )) {
604
+ zval * zv = zend_hash_index_find (Z_ARRVAL_P (data ), parser -> ctag_index );
605
+ if (!zv ) {
606
+ return NULL ;
607
+ }
608
+ ZVAL_DEREF (zv );
609
+ if (Z_TYPE_P (zv ) != IS_ARRAY ) {
610
+ return NULL ;
611
+ }
612
+ SEPARATE_ARRAY (zv );
613
+ return zv ;
614
+ }
615
+ return NULL ;
616
+ }
617
+
586
618
/* {{{ _xml_startElementHandler() */
587
619
void _xml_startElementHandler (void * userData , const XML_Char * name , const XML_Char * * attributes )
588
620
{
@@ -662,7 +694,15 @@ void _xml_startElementHandler(void *userData, const XML_Char *name, const XML_Ch
662
694
zval_ptr_dtor (& atr );
663
695
}
664
696
665
- parser -> ctag = zend_hash_next_index_insert (Z_ARRVAL (parser -> data ), & tag );
697
+ zval * data = xml_get_separated_data (parser );
698
+ if (EXPECTED (data )) {
699
+ /* Note: due to array resizes or user interference,
700
+ * we have to store an index instaed of a zval into the array's memory. */
701
+ parser -> ctag_index = Z_ARRVAL_P (data )-> nNextFreeElement ;
702
+ zend_hash_next_index_insert (Z_ARRVAL_P (data ), & tag );
703
+ } else {
704
+ zval_ptr_dtor (& tag );
705
+ }
666
706
} else if (parser -> level == (XML_MAXLEVEL + 1 )) {
667
707
php_error_docref (NULL , E_WARNING , "Maximum depth exceeded - Results truncated" );
668
708
}
@@ -695,19 +735,29 @@ void _xml_endElementHandler(void *userData, const XML_Char *name)
695
735
696
736
if (!Z_ISUNDEF (parser -> data ) && !EG (exception )) {
697
737
zval tag ;
738
+ zval * data = xml_get_separated_data (parser );
698
739
699
740
if (parser -> lastwasopen ) {
700
- add_assoc_string (parser -> ctag , "type" , "complete" );
741
+ if (EXPECTED (data )) {
742
+ zval * zv = zend_hash_index_find (Z_ARRVAL_P (data ), parser -> ctag_index );
743
+ if (EXPECTED (zv )) {
744
+ ZVAL_DEREF (zv );
745
+ if (EXPECTED (Z_TYPE_P (zv ) == IS_ARRAY )) {
746
+ SEPARATE_ARRAY (zv );
747
+ add_assoc_string (zv , "type" , "complete" );
748
+ }
749
+ }
750
+ }
701
751
} else {
702
- array_init (& tag );
703
-
704
752
_xml_add_to_info (parser , ZSTR_VAL (tag_name ) + parser -> toffset );
705
753
706
- add_assoc_string (& tag , "tag" , SKIP_TAGSTART (ZSTR_VAL (tag_name ))); /* cast to avoid gcc-warning */
707
- add_assoc_string (& tag , "type" , "close" );
708
- add_assoc_long (& tag , "level" , parser -> level );
709
-
710
- zend_hash_next_index_insert (Z_ARRVAL (parser -> data ), & tag );
754
+ if (EXPECTED (data )) {
755
+ array_init (& tag );
756
+ add_assoc_string (& tag , "tag" , SKIP_TAGSTART (ZSTR_VAL (tag_name ))); /* cast to avoid gcc-warning */
757
+ add_assoc_string (& tag , "type" , "close" );
758
+ add_assoc_long (& tag , "level" , parser -> level );
759
+ zend_hash_next_index_insert (Z_ARRVAL_P (data ), & tag );
760
+ }
711
761
}
712
762
713
763
parser -> lastwasopen = 0 ;
@@ -765,27 +815,39 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len)
765
815
}
766
816
}
767
817
if (parser -> lastwasopen ) {
818
+ zval * ctag = xml_get_ctag (parser );
819
+ if (UNEXPECTED (!ctag )) {
820
+ return ;
821
+ }
822
+
768
823
zval * myval ;
769
824
/* check if the current tag already has a value - if yes append to that! */
770
- if ((myval = zend_hash_find (Z_ARRVAL_P (parser -> ctag ), ZSTR_KNOWN (ZEND_STR_VALUE )))) {
825
+ if ((myval = zend_hash_find (Z_ARRVAL_P (ctag ), ZSTR_KNOWN (ZEND_STR_VALUE )))) {
771
826
size_t newlen = Z_STRLEN_P (myval ) + ZSTR_LEN (decoded_value );
772
827
Z_STR_P (myval ) = zend_string_extend (Z_STR_P (myval ), newlen , 0 );
773
828
strncpy (Z_STRVAL_P (myval ) + Z_STRLEN_P (myval ) - ZSTR_LEN (decoded_value ),
774
829
ZSTR_VAL (decoded_value ), ZSTR_LEN (decoded_value ) + 1 );
775
830
zend_string_release_ex (decoded_value , 0 );
776
831
} else {
777
832
if (doprint || (! parser -> skipwhite )) {
778
- add_assoc_str (parser -> ctag , "value" , decoded_value );
833
+ add_assoc_str (ctag , "value" , decoded_value );
779
834
} else {
780
835
zend_string_release_ex (decoded_value , 0 );
781
836
}
782
837
}
783
838
} else {
784
839
zval tag ;
785
840
zval * curtag , * mytype , * myval ;
786
- ZEND_HASH_REVERSE_FOREACH_VAL (Z_ARRVAL (parser -> data ), curtag ) {
787
- if ((mytype = zend_hash_str_find (Z_ARRVAL_P (curtag ),"type" , sizeof ("type" ) - 1 ))) {
788
- if (zend_string_equals_literal (Z_STR_P (mytype ), "cdata" )) {
841
+
842
+ zval * data = xml_get_separated_data (parser );
843
+ if (UNEXPECTED (!data )) {
844
+ return ;
845
+ }
846
+
847
+ ZEND_HASH_REVERSE_FOREACH_VAL (Z_ARRVAL_P (data ), curtag ) {
848
+ if (EXPECTED (Z_TYPE_P (curtag ) == IS_ARRAY ) && (mytype = zend_hash_str_find (Z_ARRVAL_P (curtag ),"type" , sizeof ("type" ) - 1 ))) {
849
+ if (EXPECTED (Z_TYPE_P (mytype ) == IS_STRING ) && zend_string_equals_literal (Z_STR_P (mytype ), "cdata" )) {
850
+ SEPARATE_ARRAY (curtag );
789
851
if ((myval = zend_hash_find (Z_ARRVAL_P (curtag ), ZSTR_KNOWN (ZEND_STR_VALUE )))) {
790
852
size_t newlen = Z_STRLEN_P (myval ) + ZSTR_LEN (decoded_value );
791
853
Z_STR_P (myval ) = zend_string_extend (Z_STR_P (myval ), newlen , 0 );
@@ -805,7 +867,7 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len)
805
867
add_assoc_str (& tag , "value" , decoded_value );
806
868
add_assoc_string (& tag , "type" , "cdata" );
807
869
add_assoc_long (& tag , "level" , parser -> level );
808
- zend_hash_next_index_insert (Z_ARRVAL ( parser -> data ), & tag );
870
+ zend_hash_next_index_insert (Z_ARRVAL_P ( data ), & tag );
809
871
} else if (parser -> level == (XML_MAXLEVEL + 1 )) {
810
872
php_error_docref (NULL , E_WARNING , "Maximum depth exceeded - Results truncated" );
811
873
} else {
@@ -1266,21 +1328,21 @@ PHP_FUNCTION(xml_parse_into_struct)
1266
1328
}
1267
1329
1268
1330
if (info ) {
1269
- info = zend_try_array_init (info );
1270
- if (!info ) {
1331
+ if (!zend_try_array_init (info )) {
1271
1332
RETURN_THROWS ();
1272
1333
}
1273
1334
}
1274
1335
1275
- xdata = zend_try_array_init (xdata );
1276
- if (!xdata ) {
1336
+ if (!zend_try_array_init (xdata )) {
1277
1337
RETURN_THROWS ();
1278
1338
}
1279
1339
1280
- ZVAL_COPY_VALUE (& parser -> data , xdata );
1340
+ zval_ptr_dtor (& parser -> data );
1341
+ ZVAL_COPY (& parser -> data , xdata );
1281
1342
1282
1343
if (info ) {
1283
- ZVAL_COPY_VALUE (& parser -> info , info );
1344
+ zval_ptr_dtor (& parser -> info );
1345
+ ZVAL_COPY (& parser -> info , info );
1284
1346
}
1285
1347
1286
1348
parser -> level = 0 ;
0 commit comments