Skip to content

Commit

Permalink
Fix collection of external entities depending on line ending (second
Browse files Browse the repository at this point in the history
try)

See redhat-developer/vscode-xml#262 (comment)

Signed-off-by: azerr [email protected]
  • Loading branch information
angelozerr authored and fbricon committed May 29, 2020
1 parent 03ca396 commit 291c6fa
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,15 @@ public String getComment(String attrName) {

private static class ScannedDTDEntityDecl extends DTDEntityDecl {

private static final char[] ENTITY = "<!ENTITY".toCharArray();

private final String entityName;
private final String value;
private final DTDDeclParameter nameParameter;

public ScannedDTDEntityDecl(String name, String value, ScannedEntity scannedEntity) {
public ScannedDTDEntityDecl(String entityName, String value, ScannedEntity scannedEntity) {
super(-1, -1);
this.entityName = name;
this.entityName = entityName;
this.value = value;
this.nameParameter = createNameParameter(name, scannedEntity);
this.nameParameter = createNameParameter(entityName, scannedEntity);
}

@Override
Expand All @@ -135,11 +133,18 @@ public String getNotationName() {
private static DTDDeclParameter createNameParameter(String name, ScannedEntity scannedEntity) {
String systemId = scannedEntity.entityLocation.getExpandedSystemId();
int lineNumber = scannedEntity.lineNumber - 1;
int endEntityColumnNumber = scannedEntity.columnNumber - 1;
int startNameColumnNumber = getEntityNameStartColumnNumber(name, scannedEntity);
return new DTDDeclParameter(null, -1, -1) {

@Override
public Range getTargetRange() {
if (startNameColumnNumber < 0) {
// It should never occur, but in case computation of start name column cannot be
// done, we use the end entity column.
return new Range(new Position(lineNumber, endEntityColumnNumber),
new Position(lineNumber, endEntityColumnNumber));
}
return new Range(new Position(lineNumber, startNameColumnNumber),
new Position(lineNumber, startNameColumnNumber + name.length()));
};
Expand All @@ -154,34 +159,37 @@ public String getTargetURI() {
/**
* Returns the colunm number where entity name starts (<!ENTITY |name )
*
* @param name the entity name
* @param entityName the entity name
* @param scannedEntity the scanned entity
* @return the colunm number where entity name starts (<!ENTITY |name )
*/
private static int getEntityNameStartColumnNumber(String name, ScannedEntity scannedEntity) {
private static int getEntityNameStartColumnNumber(String entityName, ScannedEntity scannedEntity) {
// offset of the end of the entity
int endEntityIndex = scannedEntity.startPosition + scannedEntity.position;
int startLineIndex = endEntityIndex - scannedEntity.columnNumber + 1;
// char array of the DTD content.
char[] ch = scannedEntity.ch;
int wordIndex = 0;
// loop for line text where entity is declared
// --> <!ENTITY name >
for (int i = startLineIndex; i < endEntityIndex; i++) {
int wordIndex = entityName.length(); //
int startEntityNameIndex = -1;
// Loop for characters from the end of the entity (>) to search the entity name start offset
// <!ENTITY name .....> |
for (int i = endEntityIndex; i >= 0; i--) {
char c = ch[i];
// Search the index after the <!ENTITY
if (wordIndex < ENTITY.length) {
if (c == ENTITY[wordIndex]) {
wordIndex++;
} else {
wordIndex = 0;
}
// current character matches the entity name
if (c == entityName.charAt(wordIndex - 1)) {
wordIndex--;
} else {
// <!ENTITY index id found, search the index where entity name starts.
if (c == name.charAt(0)) {
return i - startLineIndex;
}
wordIndex = entityName.length();
}
if (wordIndex == 0) {
startEntityNameIndex = i;
break;
}
}
return scannedEntity.columnNumber;
if (startEntityNameIndex > -1) {
return scannedEntity.columnNumber - (endEntityIndex - startEntityNameIndex)
+ scannedEntity.startPosition - 1;
}
return -1;
}
}

Expand Down Expand Up @@ -280,7 +288,7 @@ public void internalEntityDecl(String name, XMLString text, XMLString nonNormali
try {
entities.add(new ScannedDTDEntityDecl(name, text.toString(), fEntityManager.getCurrentEntity()));
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Error while extracting information for the entity '" + name + "'", e);
LOGGER.log(Level.SEVERE, "Error while extracting information for the internal entity '" + name + "'", e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,96 @@ public void externalWithIndent() throws BadLocationException, MalformedURIExcept
testDefinitionFor(xml, "test.xml", ll(dtdFileURI, r(6, 1, 6, 6), r(2, 9, 2, 12)));
}

@Test
public void externalWithDTDIndent() throws BadLocationException, MalformedURIException {
String dtdFileURI = getDTDFileURI("src/test/resources/dtd/base-indent.dtd");

// &external3;
String xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n" + //
"<!DOCTYPE root-element SYSTEM \"src/test/resources/dtd/base-indent.dtd\" [\r\n" + //
" <!ENTITY mdash \"&#x2014;\">\r\n" + //
"]>\r\n" + //
"<root-element>\r\n" + //
"\r\n &externa|l3;" + //
"</root-element>";
testDefinitionFor(xml, "test.xml", ll(dtdFileURI, r(6, 1, 6, 12), r(0, 9, 0, 18)));

// &external5;
xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n" + //
"<!DOCTYPE root-element SYSTEM \"src/test/resources/dtd/base-indent.dtd\" [\r\n" + //
" <!ENTITY mdash \"&#x2014;\">\r\n" + //
"]>\r\n" + //
"<root-element>\r\n" + //
"\r\n &externa|l5;" + //
"</root-element>";
testDefinitionFor(xml, "test.xml", ll(dtdFileURI, r(6, 1, 6, 12), r(0, 34, 0, 43)));

// &external;
xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n" + //
"<!DOCTYPE root-element SYSTEM \"src/test/resources/dtd/base-indent.dtd\" [\r\n" + //
" <!ENTITY mdash \"&#x2014;\">\r\n" + //
"]>\r\n" + //
"<root-element>\r\n" + //
"\r\n &externa|l;" + //
"</root-element>";
testDefinitionFor(xml, "test.xml", ll(dtdFileURI, r(6, 1, 6, 11), r(3, 15, 3, 23)));

// &external2;
xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n" + //
"<!DOCTYPE root-element SYSTEM \"src/test/resources/dtd/base-indent.dtd\" [\r\n" + //
" <!ENTITY mdash \"&#x2014;\">\r\n" + //
"]>\r\n" + //
"<root-element>\r\n" + //
"\r\n &externa|l2;" + //
"</root-element>";
testDefinitionFor(xml, "test.xml", ll(dtdFileURI, r(6, 1, 6, 12), r(4, 9, 4, 18)));
}

@Test
public void externalWithDTDNoIndent() throws BadLocationException, MalformedURIException {
String dtdFileURI = getDTDFileURI("src/test/resources/dtd/base-no-indent.dtd");

// &external3;
String xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n" + //
"<!DOCTYPE root-element SYSTEM \"src/test/resources/dtd/base-no-indent.dtd\" [\r\n" + //
" <!ENTITY mdash \"&#x2014;\">\r\n" + //
"]>\r\n" + //
"<root-element>\r\n" + //
"\r\n &externa|l3;" + //
"</root-element>";
testDefinitionFor(xml, "test.xml", ll(dtdFileURI, r(6, 1, 6, 12), r(0, 23, 0, 32)));

// &external5;
xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n" + //
"<!DOCTYPE root-element SYSTEM \"src/test/resources/dtd/base-no-indent.dtd\" [\r\n" + //
" <!ENTITY mdash \"&#x2014;\">\r\n" + //
"]>\r\n" + //
"<root-element>\r\n" + //
"\r\n &externa|l5;" + //
"</root-element>";
testDefinitionFor(xml, "test.xml", ll(dtdFileURI, r(6, 1, 6, 12), r(0, 48, 0, 57)));

// &external;
xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n" + //
"<!DOCTYPE root-element SYSTEM \"src/test/resources/dtd/base-no-indent.dtd\" [\r\n" + //
" <!ENTITY mdash \"&#x2014;\">\r\n" + //
"]>\r\n" + //
"<root-element>\r\n" + //
"\r\n &externa|l;" + //
"</root-element>";
testDefinitionFor(xml, "test.xml", ll(dtdFileURI, r(6, 1, 6, 11), r(3, 15, 3, 23)));

// &external2;
xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n" + //
"<!DOCTYPE root-element SYSTEM \"src/test/resources/dtd/base-no-indent.dtd\" [\r\n" + //
" <!ENTITY mdash \"&#x2014;\">\r\n" + //
"]>\r\n" + //
"<root-element>\r\n" + //
"\r\n &externa|l2;" + //
"</root-element>";
testDefinitionFor(xml, "test.xml", ll(dtdFileURI, r(6, 1, 6, 12), r(4, 9, 4, 18)));
}

private static String getDTDFileURI(String dtdURI) throws MalformedURIException {
return XMLEntityManager.expandSystemId(dtdURI, "test.xml", true).replace("///", "/");
}
Expand Down
5 changes: 5 additions & 0 deletions org.eclipse.lemminx/src/test/resources/dtd/base-indent.dtd
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<!ENTITY external3 "A B"><!ENTITY external5 "A B">
<!ENTITY external4 "A B">
<!ELEMENT root-element (#PCDATA)>
<!ENTITY external "A B">
<!ENTITY external2 "EXTERNALLY DECLARED ENTITY">
5 changes: 5 additions & 0 deletions org.eclipse.lemminx/src/test/resources/dtd/base-no-indent.dtd
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<!ENTITY external3 "A B"><!ENTITY external5 "A B">
<!ENTITY external4 "A B">
<!ELEMENT root-element (#PCDATA)>
<!ENTITY external "A B">
<!ENTITY external2 "EXTERNALLY DECLARED ENTITY">

0 comments on commit 291c6fa

Please sign in to comment.