From 87b4dc13901e76a6c46d7eebef0b699fc8116cf9 Mon Sep 17 00:00:00 2001 From: danielpeintner Date: Wed, 24 Aug 2016 13:44:36 +0200 Subject: [PATCH] fix escaping and unescaping of EXI4JSON keys --- .../ct/exi/json/EXIforJSONGenerator.java | 49 +++++++++++++++++-- .../siemens/ct/exi/json/EXIforJSONParser.java | 36 ++++++++++++-- .../siemens/ct/exi/json/JSONDataTestsV2.java | 47 +++++++++++++++--- 3 files changed, 117 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/siemens/ct/exi/json/EXIforJSONGenerator.java b/src/main/java/com/siemens/ct/exi/json/EXIforJSONGenerator.java index 416de6a..5f03a2a 100644 --- a/src/main/java/com/siemens/ct/exi/json/EXIforJSONGenerator.java +++ b/src/main/java/com/siemens/ct/exi/json/EXIforJSONGenerator.java @@ -387,6 +387,8 @@ protected String escapeKey(String key) { // --> Conflict with existing EXI4JSON global schema element name key = String.valueOf(EXI4JSONConstants.ESCAPE_START_CHARACTER) + String.valueOf(EXI4JSONConstants.ESCAPE_END_CHARACTER) + key; + } else { + key = escapeNCNamePlus(key); } // TODO represent '_' itself @@ -421,24 +423,61 @@ public static String escapeNCNamePlus(String name) { // first character (special) if (isLetter(c)) { // OK + if (sb != null) { + sb.append(c); + } } else if (c == '_') { - // valid NCName, but needs to be escaped for EXI4JSON - + // NOT OK: valid NCName, but needs to be escaped for EXI4JSON + if (sb == null) { + sb = new StringBuilder(); + } + sb.append("_95."); } else { + // NOT OK if (sb == null) { sb = new StringBuilder(); } + sb.append(EXI4JSONConstants.ESCAPE_START_CHARACTER); + // Is this a UTF-16 surrogate pair? + if (Character.isHighSurrogate(c)) { + // use code-point and increment loop count (2 char's) + sb.append((int)name.codePointAt(i++)); + } else { + sb.append((int)c); + } + sb.append(EXI4JSONConstants.ESCAPE_END_CHARACTER); } } else { // rest of the characters - if (isNCNameChar(c)) { - // OK if(c == '_') { - // update + // NOT OK: valid NCName, but needs to be escaped for EXI4JSON + if (sb == null) { + sb = new StringBuilder(); + sb.append(name, 0, i); + } + sb.append("_95."); + } else { + // OK + if (sb != null) { + sb.append(c); + } } } else { // Not OK, fix + if (sb == null) { + sb = new StringBuilder(); + sb.append(name, 0, i); + } + sb.append(EXI4JSONConstants.ESCAPE_START_CHARACTER); + // Is this a UTF-16 surrogate pair? + if (Character.isHighSurrogate(c)) { + // use code-point and increment loop count (2 char's) + sb.append((int)name.codePointAt(i++)); + } else { + sb.append((int)c); + } + sb.append(EXI4JSONConstants.ESCAPE_END_CHARACTER); } } } diff --git a/src/main/java/com/siemens/ct/exi/json/EXIforJSONParser.java b/src/main/java/com/siemens/ct/exi/json/EXIforJSONParser.java index 5ea827b..9d6f663 100644 --- a/src/main/java/com/siemens/ct/exi/json/EXIforJSONParser.java +++ b/src/main/java/com/siemens/ct/exi/json/EXIforJSONParser.java @@ -320,14 +320,44 @@ protected void parseV2(InputStream isEXI4JSON, OutputStream osJSON) throws EXIEx } protected String unescapeKey(String key) { + StringBuilder sb = null; + // conflicting names if(key.length() > 2 && key.charAt(0) == EXI4JSONConstants.ESCAPE_START_CHARACTER && key.charAt(1) == EXI4JSONConstants.ESCAPE_END_CHARACTER) { key = key.substring(2); + } else { + // check whether there is an escape character + int i = 0; + while(i < key.length()) { + char c = key.charAt(i); + if(c == EXI4JSONConstants.ESCAPE_START_CHARACTER) { + int endIndex = key.indexOf(EXI4JSONConstants.ESCAPE_END_CHARACTER, i); + if(endIndex <= 0) { + throw new RuntimeException("Unexpected Escape Key: " + key); + } else { + int cp = Integer.parseInt(key.substring(i+1, endIndex)); + if(sb == null) { + sb = new StringBuilder(); + sb.append(key, 0, i); + } + sb.appendCodePoint(cp); + i += (endIndex-i); + } + } else { + // ok + if(sb != null) { + sb.append(c); + } + } + i++; + } } - // TODO represent '_' itself - // TODO Conflict with NCName character(s) - return key; + if(sb == null) { + return key; + } else { + return sb.toString(); + } } // public static void main(String[] args) throws EXIException, IOException { diff --git a/src/test/java/com/siemens/ct/exi/json/JSONDataTestsV2.java b/src/test/java/com/siemens/ct/exi/json/JSONDataTestsV2.java index c875dd6..74c48d2 100644 --- a/src/test/java/com/siemens/ct/exi/json/JSONDataTestsV2.java +++ b/src/test/java/com/siemens/ct/exi/json/JSONDataTestsV2.java @@ -73,13 +73,14 @@ public void testEscapeKey1() throws EXIException, IOException, JSONException { String key = EXI4JSONConstants.LOCALNAME_NUMBER; // "number" EXIforJSONGenerator e4jGenerator = new EXIforJSONGenerator(); String ekey = e4jGenerator.escapeKey(key); - + assertFalse(key.equals(ekey)); - assertTrue((String.valueOf(EXI4JSONConstants.ESCAPE_START_CHARACTER)+String.valueOf(EXI4JSONConstants.ESCAPE_END_CHARACTER)+EXI4JSONConstants.LOCALNAME_NUMBER).equals(ekey)); - + assertTrue((String.valueOf(EXI4JSONConstants.ESCAPE_START_CHARACTER) + + String.valueOf(EXI4JSONConstants.ESCAPE_END_CHARACTER) + EXI4JSONConstants.LOCALNAME_NUMBER) + .equals(ekey)); + EXIforJSONParser e4jParser = new EXIforJSONParser(); String ukey = e4jParser.unescapeKey(ekey); - assertTrue(ukey.equals(key)); } @@ -91,8 +92,10 @@ public void testEscapeKey2() throws EXIException, IOException, JSONException { assertFalse(key.equals(ekey)); assertTrue("a_32.number".equals(ekey)); - - // TODO + + EXIforJSONParser e4jParser = new EXIforJSONParser(); + String ukey = e4jParser.unescapeKey(ekey); + assertTrue(ukey.equals(key)); } @Test @@ -103,8 +106,12 @@ public void testEscapeKey3() throws EXIException, IOException, JSONException { assertFalse(key.equals(ekey)); assertTrue("_95.foo".equals(ekey)); + + EXIforJSONParser e4jParser = new EXIforJSONParser(); + String ukey = e4jParser.unescapeKey(ekey); + assertTrue(ukey.equals(key)); } - + @Test public void testEscapeKey4() throws EXIException, IOException, JSONException { String key = "foo_.A"; @@ -113,6 +120,32 @@ public void testEscapeKey4() throws EXIException, IOException, JSONException { assertFalse(key.equals(ekey)); assertTrue("foo_95..A".equals(ekey)); + + EXIforJSONParser e4jParser = new EXIforJSONParser(); + String ukey = e4jParser.unescapeKey(ekey); + assertTrue(ukey.equals(key)); + } + + @Test + public void testEscapeKey5() throws EXIException, IOException, JSONException { + // High surrogate pair + byte[] data = { 0, 0x41, // A + (byte) 0xD8, 1, // High surrogate + (byte) 0xDC, 2, // Low surrogate + 0, 0x42, // B + }; + + String key = new String(data, "UTF-16"); + + EXIforJSONGenerator e4jGenerator = new EXIforJSONGenerator(); + String ekey = e4jGenerator.escapeKey(key); + + assertFalse(key.equals(ekey)); + assertTrue("A_66562.B".equals(ekey)); + + EXIforJSONParser e4jParser = new EXIforJSONParser(); + String ukey = e4jParser.unescapeKey(ekey); + assertTrue(ukey.equals(key)); } }