diff options
author | Mark Spruiell <mes@zeroc.com> | 2002-08-28 01:16:24 +0000 |
---|---|---|
committer | Mark Spruiell <mes@zeroc.com> | 2002-08-28 01:16:24 +0000 |
commit | 71c8c443160e2dbaae3faec9fe3c0f0193d4d692 (patch) | |
tree | a6b61d979a34b2e791f97bb5f44f1220efa3b286 /java/src | |
parent | improving xerces workaround (diff) | |
download | ice-71c8c443160e2dbaae3faec9fe3c0f0193d4d692.tar.bz2 ice-71c8c443160e2dbaae3faec9fe3c0f0193d4d692.tar.xz ice-71c8c443160e2dbaae3faec9fe3c0f0193d4d692.zip |
adding encoding for references, identities
Diffstat (limited to 'java/src')
-rw-r--r-- | java/src/Ice/Util.java | 52 | ||||
-rw-r--r-- | java/src/IceInternal/Reference.java | 79 | ||||
-rw-r--r-- | java/src/IceInternal/ReferenceFactory.java | 148 | ||||
-rw-r--r-- | java/src/IceInternal/StringUtil.java | 270 |
4 files changed, 493 insertions, 56 deletions
diff --git a/java/src/Ice/Util.java b/java/src/Ice/Util.java index d19e6f00ea9..d5050e923fb 100644 --- a/java/src/Ice/Util.java +++ b/java/src/Ice/Util.java @@ -107,17 +107,52 @@ public final class Util stringToIdentity(String s) { Identity ident = new Identity(); - int pos = s.indexOf('/'); - if(pos != -1) + + // + // Find unescaped separator + // + int slash = 0; + while((slash = s.indexOf('/', slash)) != -1) { - ident.category = s.substring(0, pos); - ident.name = s.substring(pos + 1); + if(slash == 0 || s.charAt(slash - 1) != '\\') + { + break; + } + slash++; } - else + + if(slash == -1) { + StringHolder token = new StringHolder(); + if(!IceInternal.StringUtil.decodeString(s, 0, 0, token)) + { + throw new SystemException(); + } ident.category = ""; - ident.name = s; + ident.name = token.value; } + else + { + StringHolder token = new StringHolder(); + if(!IceInternal.StringUtil.decodeString(s, 0, slash, token)) + { + throw new SystemException(); + } + ident.category = token.value; + if(slash + 1 < s.length()) + { + if(!IceInternal.StringUtil.decodeString(s, slash + 1, 0, token)) + { + throw new SystemException(); + } + ident.name = token.value; + } + else + { + ident.name = ""; + } + } + return ident; } @@ -126,11 +161,12 @@ public final class Util { if(ident.category.length() == 0) { - return ident.name; + return IceInternal.StringUtil.encodeString(ident.name, "/"); } else { - return ident.category + '/' + ident.name; + return IceInternal.StringUtil.encodeString(ident.category, "/") + '/' + + IceInternal.StringUtil.encodeString(ident.name, "/"); } } diff --git a/java/src/IceInternal/Reference.java b/java/src/IceInternal/Reference.java index a9dfeebbf19..a105c3fb139 100644 --- a/java/src/IceInternal/Reference.java +++ b/java/src/IceInternal/Reference.java @@ -153,22 +153,53 @@ public final class Reference toString() { StringBuffer s = new StringBuffer(); - s.append(Ice.Util.identityToString(identity)); + + // + // If the encoded identity string contains characters which + // the reference parser uses as separators, then we enclose + // the identity string in quotes. + // + String id = Ice.Util.identityToString(identity); + if(StringUtil.findFirstOf(id, " \t\n\r:@") != -1) + { + s.append('"'); + s.append(id); + s.append('"'); + } + else + { + s.append(id); + } if(facet.length > 0) { + StringBuffer f = new StringBuffer(); + for(int i = 0; i < facet.length ; i++) + { + f.append(StringUtil.encodeString(facet[i], "/")); + if(i < facet.length - 1) + { + f.append('/'); + } + } + + // + // If the encoded facet string contains characters which + // the reference parser uses as separators, then we enclose + // the facet string in quotes. + // s.append(" -f "); - for(int i = 0; i < facet.length ; i++) - { - // - // TODO: Escape for whitespace and slashes. - // - s.append(facet[i]); - if(i < facet.length - 1) - { - s.append('/'); - } - } + String fs = f.toString(); + if(StringUtil.findFirstOf(fs, " \t\n\r:@") != -1) + { + s.append('"'); + s.append(fs); + s.append('"'); + } + else + { + s.append(fs); + } } switch(mode) @@ -224,10 +255,26 @@ public final class Reference s.append(endpoints[i].toString()); } } - else - { - s.append(" @ " + adapterId); - } + else + { + String a = StringUtil.encodeString(adapterId, null); + // + // If the encoded adapter id string contains characters which + // the reference parser uses as separators, then we enclose + // the adapter id string in quotes. + // + s.append(" @ "); + if(StringUtil.findFirstOf(a, " \t\n\r") != -1) + { + s.append('"'); + s.append(a); + s.append('"'); + } + else + { + s.append(a); + } + } return s.toString(); } diff --git a/java/src/IceInternal/ReferenceFactory.java b/java/src/IceInternal/ReferenceFactory.java index 56fd4f7a771..ffbb05d0442 100644 --- a/java/src/IceInternal/ReferenceFactory.java +++ b/java/src/IceInternal/ReferenceFactory.java @@ -81,10 +81,30 @@ public final class ReferenceFactory throw new Ice.ProxyParseException(); } - end = StringUtil.findFirstOf(s, delim + ":@", beg); + // + // Extract the identity, which may be enclosed in single + // or double quotation marks. + // + String idstr = null; + end = StringUtil.checkQuote(s, beg); if(end == -1) { - end = s.length(); + throw new Ice.ProxyParseException(); + } + else if(end == 0) + { + end = StringUtil.findFirstOf(s, delim + ":@", beg); + if(end == -1) + { + end = s.length(); + } + idstr = s.substring(beg, end); + } + else + { + beg++; // Skip leading quote + idstr = s.substring(beg, end); + end++; // Skip trailing quote } if(beg == end) @@ -92,7 +112,7 @@ public final class ReferenceFactory throw new Ice.ProxyParseException(); } - Ice.Identity ident = Ice.Util.stringToIdentity(s.substring(beg, end)); + Ice.Identity ident = Ice.Util.stringToIdentity(idstr); java.util.ArrayList facet = new java.util.ArrayList(); int mode = Reference.ModeTwoway; boolean secure = false; @@ -129,16 +149,39 @@ public final class ReferenceFactory throw new Ice.ProxyParseException(); } + // + // Check for the presence of an option argument. The + // argument may be enclosed in single or double + // quotation marks. + // String argument = null; int argumentBeg = StringUtil.findFirstNotOf(s, delim, end); - if(argumentBeg != -1 && s.charAt(argumentBeg) != '-') + if(argumentBeg != -1) { - beg = argumentBeg; - end = StringUtil.findFirstOf(s, delim + ":@", beg); - if(end == -1) + final char ch = s.charAt(argumentBeg); + if(ch != '@' && ch != ':' && ch != '-') { - end = s.length(); - argument = s.substring(beg, end); + beg = argumentBeg; + end = StringUtil.checkQuote(s, beg); + if(end == -1) + { + throw new Ice.ProxyParseException(); + } + else if(end == 0) + { + end = StringUtil.findFirstOf(s, delim + ":@", beg); + if(end == -1) + { + end = s.length(); + } + argument = s.substring(beg, end); + } + else + { + beg++; // Skip leading quote + argument = s.substring(beg, end); + end++; // Skip trailing quote + } } } @@ -152,27 +195,55 @@ public final class ReferenceFactory { if(argument == null) { - throw new Ice.EndpointParseException(); + throw new Ice.ProxyParseException(); } - // - // TODO: Escape for whitespace and slashes. - // + final int argLen = argument.length(); + Ice.StringHolder token = new Ice.StringHolder(); + int argBeg = 0; - while(argBeg < argument.length()) + while(argBeg < argLen) { - int argEnd = argument.indexOf('/', argBeg); + // + // Skip slashes + // + argBeg = StringUtil.findFirstNotOf(argument, "/", argBeg); + if(argBeg == -1) + { + break; + } + + // + // Find unescaped slash + // + int argEnd = argBeg; + while((argEnd = argument.indexOf('/', argEnd)) != -1) + { + if(argument.charAt(argEnd - 1) != '\\') + { + break; + } + argEnd++; + } + if(argEnd == -1) { - facet.add(argument.substring(argBeg)); + argEnd = argLen; } - else + + if(!IceInternal.StringUtil.decodeString(argument, argBeg, argEnd, token)) { - facet.add(argument.substring(argBeg, argEnd)); - ++argEnd; + throw new Ice.ProxyParseException(); } - argBeg = argEnd; + facet.add(token.value); + argBeg = argEnd + 1; + } + + if(facet.size() == 0) + { + throw new Ice.ProxyParseException(); } + break; } @@ -180,7 +251,7 @@ public final class ReferenceFactory { if(argument != null) { - throw new Ice.EndpointParseException(); + throw new Ice.ProxyParseException(); } mode = Reference.ModeTwoway; break; @@ -190,7 +261,7 @@ public final class ReferenceFactory { if(argument != null) { - throw new Ice.EndpointParseException(); + throw new Ice.ProxyParseException(); } mode = Reference.ModeOneway; break; @@ -200,7 +271,7 @@ public final class ReferenceFactory { if(argument != null) { - throw new Ice.EndpointParseException(); + throw new Ice.ProxyParseException(); } mode = Reference.ModeBatchOneway; break; @@ -210,7 +281,7 @@ public final class ReferenceFactory { if(argument != null) { - throw new Ice.EndpointParseException(); + throw new Ice.ProxyParseException(); } mode = Reference.ModeDatagram; break; @@ -220,7 +291,7 @@ public final class ReferenceFactory { if(argument != null) { - throw new Ice.EndpointParseException(); + throw new Ice.ProxyParseException(); } mode = Reference.ModeBatchDatagram; break; @@ -230,7 +301,7 @@ public final class ReferenceFactory { if(argument != null) { - throw new Ice.EndpointParseException(); + throw new Ice.ProxyParseException(); } secure = true; break; @@ -240,7 +311,7 @@ public final class ReferenceFactory { if(argument != null) { - throw new Ice.EndpointParseException(); + throw new Ice.ProxyParseException(); } compress = true; break; @@ -280,20 +351,33 @@ public final class ReferenceFactory beg = StringUtil.findFirstNotOf(s, delim, beg + 1); if(beg == -1) { - beg = end + 1; + throw new Ice.ProxyParseException(); } - end = StringUtil.findFirstOf(s, delim, beg); + end = StringUtil.checkQuote(s, beg); if(end == -1) { - end = s.length(); + throw new Ice.ProxyParseException(); + } + else if(end == 0) + { + end = StringUtil.findFirstOf(s, delim, beg); + if(end == -1) + { + end = s.length(); + } + } + else + { + beg++; // Skip leading quote } - adapter = s.substring(beg, end); - if(adapter.length() == 0) + Ice.StringHolder token = new Ice.StringHolder(); + if(!IceInternal.StringUtil.decodeString(s, beg, end, token) || token.value.length() == 0) { throw new Ice.ProxyParseException(); } + adapter = token.value; } } diff --git a/java/src/IceInternal/StringUtil.java b/java/src/IceInternal/StringUtil.java index 8a64798de37..119506b3f96 100644 --- a/java/src/IceInternal/StringUtil.java +++ b/java/src/IceInternal/StringUtil.java @@ -75,4 +75,274 @@ public final class StringUtil return -1; } + + private static void + encodeChar(byte b, StringBuffer s, String special) + { + switch(b) + { + case (byte)'\\': + { + s.append("\\\\"); + break; + } + case (byte)'\'': + { + s.append("\\'"); + break; + } + case (byte)'"': + { + s.append("\\\""); + break; + } + case (byte)'\b': + { + s.append("\\b"); + break; + } + case (byte)'\f': + { + s.append("\\f"); + break; + } + case (byte)'\n': + { + s.append("\\n"); + break; + } + case (byte)'\r': + { + s.append("\\r"); + break; + } + case (byte)'\t': + { + s.append("\\t"); + break; + } + default: + { + if(b <= (byte)31 || b == (byte)127) // Bytes are signed in Java (-128 to 127) + { + s.append('\\'); + String octal = Integer.toOctalString(b); + // + // Add leading zeroes so that we avoid problems during + // decoding. For example, consider the encoded string + // \0013 (i.e., a character with value 1 followed by + // the character '3'). If the leading zeroes were omitted, + // the result would be incorrectly interpreted by the + // decoder as a single character with value 11. + // + for(int j = octal.length(); j < 3; j++) + { + s.append('0'); + } + s.append(octal); + } + else if(special != null && special.indexOf((char)b) != -1) + { + s.append('\\'); + encodeChar(b, s, null); + } + else + { + s.append((char)b); + } + } + } + } + + // + // Encodes a string into UTF8, escaping all characters outside the range [32-126] + // as well as any special characters determined by the caller. + // + public static String + encodeString(String s, String special) + { + byte[] bytes = null; + try + { + bytes = s.getBytes("UTF8"); + } + catch(java.io.UnsupportedEncodingException ex) + { + assert(false); + return null; + } + + StringBuffer result = new StringBuffer(bytes.length); + + for(int i = 0; i < bytes.length; i++) + { + encodeChar(bytes[i], result, special); + } + + return result.toString(); + } + + // + // Decodes a UTF8 string. Decoding starts at the given start position + // (inclusive) and stops at the given end position (exclusive). If the end + // position is zero, then the remainder of the string is used. Upon success, + // the result parameter holds the decoded string and true is returned. + // A return value of false indicates an error was detected in the encoding. + // + public static boolean + decodeString(String s, int start, int end, Ice.StringHolder result) + { + final int len = s.length(); + if(end == 0) + { + end = len; + } + assert(start >= 0); + assert(end <= len); + assert(start < end); + + byte[] bytes = new byte[len]; + int bc = 0; + while(start < end) + { + char ch = s.charAt(start); + if(ch == '\\') + { + start++; + if(start == end) + { + return false; // Missing character + } + ch = s.charAt(start); + switch(ch) + { + case '\\': + { + bytes[bc++] = (byte)'\\'; + break; + } + case '\'': + case '"': + { + bytes[bc++] = (byte)ch; + break; + } + case 'b': + { + bytes[bc++] = (byte)'\b'; + break; + } + case 'f': + { + bytes[bc++] = (byte)'\f'; + break; + } + case 'n': + { + bytes[bc++] = (byte)'\n'; + break; + } + case 'r': + { + bytes[bc++] = (byte)'\r'; + break; + } + case 't': + { + bytes[bc++] = (byte)'\t'; + break; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + int count = 0; + int val = 0; + while(count < 3 && start < end && s.charAt(start) >= '0' && s.charAt(start) <= '9') + { + val <<= 3; + val |= s.charAt(start) - '0'; + start++; + count++; + } + if(val > 255) + { + return false; // Octal value out of range + } + bytes[bc++] = (byte)val; + continue; // don't increment start + } + default: + { + byte b = (byte)ch; + if(b <= (byte)31 || b == (byte)127) // Bytes are signed in Java (-128 to 127) + { + return false; // Malformed encoding + } + else + { + bytes[bc++] = b; + } + } + } + } + else + { + bytes[bc++] = (byte)ch; + } + start++; + } + + try + { + result.value = new String(bytes, 0, bc, "UTF8"); + } + catch(java.io.UnsupportedEncodingException ex) + { + assert(false); + } + + return true; + } + + public static int + checkQuote(String s) + { + return checkQuote(s, 0); + } + + // + // If a single or double quotation mark is found at the start position, + // then the position of the matching closing quote is returned. If no + // quotation mark is found at the start position, then 0 is returned. + // If no matching closing quote is found, then -1 is returned. + // + public static int + checkQuote(String s, int start) + { + char quoteChar = s.charAt(start); + if(quoteChar == '"' || quoteChar == '\'') + { + start++; + final int len = s.length(); + int pos; + while(start < len && (pos = s.indexOf(quoteChar, start)) != -1) + { + if(s.charAt(pos - 1) != '\\') + { + return pos; + } + start = pos + 1; + } + return -1; // Unmatched quote + } + return 0; // Not quoted + } } |