Skip to content

Commit 87b4dc1

Browse files
fix escaping and unescaping of EXI4JSON keys
1 parent 7bb8a8c commit 87b4dc1

File tree

3 files changed

+117
-15
lines changed

3 files changed

+117
-15
lines changed

src/main/java/com/siemens/ct/exi/json/EXIforJSONGenerator.java

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,8 @@ protected String escapeKey(String key) {
387387
// --> Conflict with existing EXI4JSON global schema element name
388388
key = String.valueOf(EXI4JSONConstants.ESCAPE_START_CHARACTER)
389389
+ String.valueOf(EXI4JSONConstants.ESCAPE_END_CHARACTER) + key;
390+
} else {
391+
key = escapeNCNamePlus(key);
390392
}
391393

392394
// TODO represent '_' itself
@@ -421,24 +423,61 @@ public static String escapeNCNamePlus(String name) {
421423
// first character (special)
422424
if (isLetter(c)) {
423425
// OK
426+
if (sb != null) {
427+
sb.append(c);
428+
}
424429
} else if (c == '_') {
425-
// valid NCName, but needs to be escaped for EXI4JSON
426-
430+
// NOT OK: valid NCName, but needs to be escaped for EXI4JSON
431+
if (sb == null) {
432+
sb = new StringBuilder();
433+
}
434+
sb.append("_95.");
427435
} else {
436+
// NOT OK
428437
if (sb == null) {
429438
sb = new StringBuilder();
430439
}
440+
sb.append(EXI4JSONConstants.ESCAPE_START_CHARACTER);
441+
// Is this a UTF-16 surrogate pair?
442+
if (Character.isHighSurrogate(c)) {
443+
// use code-point and increment loop count (2 char's)
444+
sb.append((int)name.codePointAt(i++));
445+
} else {
446+
sb.append((int)c);
447+
}
448+
sb.append(EXI4JSONConstants.ESCAPE_END_CHARACTER);
431449
}
432450
} else {
433451
// rest of the characters
434-
435452
if (isNCNameChar(c)) {
436-
// OK
437453
if(c == '_') {
438-
// update
454+
// NOT OK: valid NCName, but needs to be escaped for EXI4JSON
455+
if (sb == null) {
456+
sb = new StringBuilder();
457+
sb.append(name, 0, i);
458+
}
459+
sb.append("_95.");
460+
} else {
461+
// OK
462+
if (sb != null) {
463+
sb.append(c);
464+
}
439465
}
440466
} else {
441467
// Not OK, fix
468+
if (sb == null) {
469+
sb = new StringBuilder();
470+
sb.append(name, 0, i);
471+
}
472+
sb.append(EXI4JSONConstants.ESCAPE_START_CHARACTER);
473+
// Is this a UTF-16 surrogate pair?
474+
if (Character.isHighSurrogate(c)) {
475+
// use code-point and increment loop count (2 char's)
476+
sb.append((int)name.codePointAt(i++));
477+
} else {
478+
sb.append((int)c);
479+
}
480+
sb.append(EXI4JSONConstants.ESCAPE_END_CHARACTER);
442481
}
443482
}
444483
}

src/main/java/com/siemens/ct/exi/json/EXIforJSONParser.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,14 +320,44 @@ protected void parseV2(InputStream isEXI4JSON, OutputStream osJSON) throws EXIEx
320320
}
321321

322322
protected String unescapeKey(String key) {
323+
StringBuilder sb = null;
324+
323325
// conflicting names
324326
if(key.length() > 2 && key.charAt(0) == EXI4JSONConstants.ESCAPE_START_CHARACTER && key.charAt(1) == EXI4JSONConstants.ESCAPE_END_CHARACTER) {
325327
key = key.substring(2);
328+
} else {
329+
// check whether there is an escape character
330+
int i = 0;
331+
while(i < key.length()) {
332+
char c = key.charAt(i);
333+
if(c == EXI4JSONConstants.ESCAPE_START_CHARACTER) {
334+
int endIndex = key.indexOf(EXI4JSONConstants.ESCAPE_END_CHARACTER, i);
335+
if(endIndex <= 0) {
336+
throw new RuntimeException("Unexpected Escape Key: " + key);
337+
} else {
338+
int cp = Integer.parseInt(key.substring(i+1, endIndex));
339+
if(sb == null) {
340+
sb = new StringBuilder();
341+
sb.append(key, 0, i);
342+
}
343+
sb.appendCodePoint(cp);
344+
i += (endIndex-i);
345+
}
346+
} else {
347+
// ok
348+
if(sb != null) {
349+
sb.append(c);
350+
}
351+
}
352+
i++;
353+
}
326354
}
327-
// TODO represent '_' itself
328-
// TODO Conflict with NCName character(s)
329355

330-
return key;
356+
if(sb == null) {
357+
return key;
358+
} else {
359+
return sb.toString();
360+
}
331361
}
332362

333363
// public static void main(String[] args) throws EXIException, IOException {

src/test/java/com/siemens/ct/exi/json/JSONDataTestsV2.java

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,14 @@ public void testEscapeKey1() throws EXIException, IOException, JSONException {
7373
String key = EXI4JSONConstants.LOCALNAME_NUMBER; // "number"
7474
EXIforJSONGenerator e4jGenerator = new EXIforJSONGenerator();
7575
String ekey = e4jGenerator.escapeKey(key);
76-
76+
7777
assertFalse(key.equals(ekey));
78-
assertTrue((String.valueOf(EXI4JSONConstants.ESCAPE_START_CHARACTER)+String.valueOf(EXI4JSONConstants.ESCAPE_END_CHARACTER)+EXI4JSONConstants.LOCALNAME_NUMBER).equals(ekey));
79-
78+
assertTrue((String.valueOf(EXI4JSONConstants.ESCAPE_START_CHARACTER)
79+
+ String.valueOf(EXI4JSONConstants.ESCAPE_END_CHARACTER) + EXI4JSONConstants.LOCALNAME_NUMBER)
80+
.equals(ekey));
81+
8082
EXIforJSONParser e4jParser = new EXIforJSONParser();
8183
String ukey = e4jParser.unescapeKey(ekey);
82-
8384
assertTrue(ukey.equals(key));
8485
}
8586

@@ -91,8 +92,10 @@ public void testEscapeKey2() throws EXIException, IOException, JSONException {
9192

9293
assertFalse(key.equals(ekey));
9394
assertTrue("a_32.number".equals(ekey));
94-
95-
// TODO
95+
96+
EXIforJSONParser e4jParser = new EXIforJSONParser();
97+
String ukey = e4jParser.unescapeKey(ekey);
98+
assertTrue(ukey.equals(key));
9699
}
97100

98101
@Test
@@ -103,8 +106,12 @@ public void testEscapeKey3() throws EXIException, IOException, JSONException {
103106

104107
assertFalse(key.equals(ekey));
105108
assertTrue("_95.foo".equals(ekey));
109+
110+
EXIforJSONParser e4jParser = new EXIforJSONParser();
111+
String ukey = e4jParser.unescapeKey(ekey);
112+
assertTrue(ukey.equals(key));
106113
}
107-
114+
108115
@Test
109116
public void testEscapeKey4() throws EXIException, IOException, JSONException {
110117
String key = "foo_.A";
@@ -113,6 +120,32 @@ public void testEscapeKey4() throws EXIException, IOException, JSONException {
113120

114121
assertFalse(key.equals(ekey));
115122
assertTrue("foo_95..A".equals(ekey));
123+
124+
EXIforJSONParser e4jParser = new EXIforJSONParser();
125+
String ukey = e4jParser.unescapeKey(ekey);
126+
assertTrue(ukey.equals(key));
127+
}
128+
129+
@Test
130+
public void testEscapeKey5() throws EXIException, IOException, JSONException {
131+
// High surrogate pair
132+
byte[] data = { 0, 0x41, // A
133+
(byte) 0xD8, 1, // High surrogate
134+
(byte) 0xDC, 2, // Low surrogate
135+
0, 0x42, // B
136+
};
137+
138+
String key = new String(data, "UTF-16");
139+
140+
EXIforJSONGenerator e4jGenerator = new EXIforJSONGenerator();
141+
String ekey = e4jGenerator.escapeKey(key);
142+
143+
assertFalse(key.equals(ekey));
144+
assertTrue("A_66562.B".equals(ekey));
145+
146+
EXIforJSONParser e4jParser = new EXIforJSONParser();
147+
String ukey = e4jParser.unescapeKey(ekey);
148+
assertTrue(ukey.equals(key));
116149
}
117150

118151
}

0 commit comments

Comments
 (0)