Skip to content

Commit

Permalink
Fix #140: Entity decoding broken if it crosses a chunk
Browse files Browse the repository at this point in the history
  • Loading branch information
renggli committed Mar 26, 2022
1 parent ca19b86 commit 8afc3a4
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 2 deletions.
25 changes: 25 additions & 0 deletions lib/src/xml_events/events/text.dart
@@ -1,3 +1,4 @@
import '../../xml/entities/entity_mapping.dart';
import '../../xml/utils/node_type.dart';
import '../event.dart';
import '../visitor.dart';
Expand All @@ -20,3 +21,27 @@ class XmlTextEvent extends XmlEvent {
@override
bool operator ==(Object other) => other is XmlTextEvent && other.text == text;
}

/// Internal event of an XML text node that is lazily decoded.
class XmlRawTextEvent extends XmlEvent implements XmlTextEvent {
XmlRawTextEvent(this.raw, this.entityMapping);

final String raw;

final XmlEntityMapping entityMapping;

@override
late final String text = entityMapping.decode(raw);

@override
XmlNodeType get nodeType => XmlNodeType.TEXT;

@override
void accept(XmlEventVisitor visitor) => visitor.visitTextEvent(this);

@override
int get hashCode => Object.hash(nodeType, text);

@override
bool operator ==(Object other) => other is XmlTextEvent && other.text == text;
}
2 changes: 1 addition & 1 deletion lib/src/xml_events/parser.dart
Expand Up @@ -38,7 +38,7 @@ class XmlEventParser {

Parser<XmlTextEvent> characterData() =>
XmlCharacterDataParser(XmlToken.openElement, 1)
.map((each) => XmlTextEvent(entityMapping.decode(each)));
.map((each) => XmlRawTextEvent(each, entityMapping));

Parser<XmlStartElementEvent> startElement() => [
XmlToken.openElement.toParser(),
Expand Down
6 changes: 5 additions & 1 deletion lib/src/xml_events/streams/normalizer.dart
Expand Up @@ -37,10 +37,14 @@ class _XmlNormalizeEventsSink extends ChunkedConversionSink<List<XmlEvent>> {
for (var i = 0; i < buffer.length - 1;) {
final event1 = buffer[i], event2 = buffer[i + 1];
if (event1 is XmlTextEvent && event2 is XmlTextEvent) {
final event = XmlTextEvent(event1.text + event2.text);
// Combine text nodes, decode the combined input.
final event = event1 is XmlRawTextEvent && event2 is XmlRawTextEvent
? XmlRawTextEvent(event1.raw + event2.raw, event1.entityMapping)
: XmlTextEvent(event1.text + event2.text);
// Propagate annotations.
event.attachBuffer(event1.buffer);
event.attachLocation(event1.start, event2.stop);
assert(event1.parent == event2.parent);
event.attachParent(event1.parent);
// Update the buffer.
buffer[i] = event;
Expand Down

0 comments on commit 8afc3a4

Please sign in to comment.