@@ -908,68 +908,80 @@ internal struct XMLPlistScanner {
908908 }
909909 }
910910
911- func determineTag ( ) throws -> XMLPlistTag ? {
911+ mutating func readTag ( ) throws -> XMLPlistTag ? {
912912 let marker = reader. readIndex
913- switch reader. char ( at: marker) {
913+ var tag : XMLPlistTag ?
914+ switch reader. peek ( ) {
914915 case UInt8 ( ascii: " a " ) : // Array
915916 if matches ( tag: . array, at: marker, until: reader. endIndex) {
916- return . array
917+ tag = . array
917918 }
918919 case UInt8 ( ascii: " d " ) : // Dictionary, data, or date
919920 if matches ( tag: . dict, at: marker, until: reader. endIndex) {
920- return . dict
921+ tag = . dict
921922 } else if matches ( tag: . data, at: marker, until: reader. endIndex) {
922- return . data
923+ tag = . data
923924 } else if matches ( tag: . date, at: marker, until: reader. endIndex) {
924- return . date
925+ tag = . date
925926 }
926927 case UInt8 ( ascii: " f " ) : // false (boolean)
927928 if matches ( tag: . false , at: marker, until: reader. endIndex) {
928- return . false
929+ tag = . false
929930 }
930931 case UInt8 ( ascii: " i " ) : // integer
931932 if matches ( tag: . integer, at: marker, until: reader. endIndex) {
932- return . integer
933+ tag = . integer
933934 }
934935 case UInt8 ( ascii: " k " ) : // Key of a dictionary
935936 if matches ( tag: . key, at: marker, until: reader. endIndex) {
936- return . key
937+ tag = . key
937938 }
938939 case UInt8 ( ascii: " p " ) : // Plist
939940 if matches ( tag: . plist, at: marker, until: reader. endIndex) {
940- return . plist
941+ tag = . plist
941942 }
942943 case UInt8 ( ascii: " r " ) : // real
943944 if matches ( tag: . real, at: marker, until: reader. endIndex) {
944- return . real
945+ tag = . real
945946 }
946947 case UInt8 ( ascii: " s " ) : // String
947948 if matches ( tag: . string, at: marker, until: reader. endIndex) {
948- return . string
949+ tag = . string
949950 }
950951 case UInt8 ( ascii: " t " ) : // true (boolean)
951952 if matches ( tag: . true , at: marker, until: reader. endIndex) {
952- return . true
953+ tag = . true
953954 }
954- case . _space, . _tab, . _newline, . _return, . _closeangle:
955- throw XMLPlistError . malformedTag ( line: reader. lineNumber)
956955 default :
957956 break
958957 }
959- return nil
958+
959+ guard let tag else {
960+ return nil
961+ }
962+
963+ // Tag names must be delimited either by whitespace or a '>' or `/` character to be valid.
964+ reader. advance ( tag. tagLength)
965+ switch reader. peek ( ) {
966+ case . _closeangle, . _forwardslash, . _space, . _tab, . _newline, . _return:
967+ return tag
968+ default :
969+ return nil
970+ }
960971 }
961972
962973 mutating func peekXMLElement( ) throws -> ( XMLPlistTag , isEmpty: Bool ) {
963- guard let tag = try determineTag ( ) else {
964- let badTagStart = reader. readIndex
965- while let ch = reader. read ( ) , ch != . _closeangle { }
966- let badTagEnd = reader. readIndex
967- let markerStr = String . _tryFromUTF8 ( reader. fullBuffer [ badTagStart..< badTagEnd] ) ?? " <unparseable> "
974+ let tagStart = reader. readIndex
975+ guard let tag = try readTag ( ) else {
976+ var idx = reader. readIndex
977+ while idx < reader. endIndex, reader. char ( at: idx) != . _closeangle {
978+ reader. advance ( & idx)
979+ }
980+ let markerStr = String . _tryFromUTF8 ( reader. fullBuffer [ tagStart..< idx] ) ?? " <unparseable> "
968981 throw XMLPlistError . other ( " Encountered unknown tag \( markerStr) on line \( reader. lineNumber) " )
969982 }
970983
971- reader. advance ( tag. tagLength)
972-
984+ // Skip past any characters (whitespace or attributes) that may follow a valid tag name.
973985 while let ch = reader. read ( ) , ch != . _closeangle { }
974986 if reader. isAtEnd {
975987 throw XMLPlistError . malformedTag ( line: reader. lineNumber)
0 commit comments