* @throws MalformedURLException If the string could not be parsed.
*/
public FreenetURI(String URI, boolean noTrim) throws MalformedURLException {
// this.uniqueHashCode = super.hashCode();
if(URI == null)
throw new MalformedURLException("No URI specified");
if(!noTrim)
URI = URI.trim();
// Strip ?max-size, ?type etc.
// Un-encoded ?'s are illegal.
int x = URI.indexOf('?');
if(x > -1)
URI = URI.substring(0, x);
if(URI.indexOf('@') < 0 || URI.indexOf('/') < 0)
// Encoded URL?
try {
URI = URLDecoder.decode(URI, false);
} catch(URLEncodedFormatException e) {
throw new MalformedURLException("Invalid URI: no @ or /, or @ or / is escaped but there are invalid escapes");
}
URI = URI_PREFIX.matcher(URI).replaceFirst("");
// decode keyType
int atchar = URI.indexOf('@');
if(atchar == -1)
throw new MalformedURLException("There is no @ in that URI! (" + URI + ')');
String _keyType = URI.substring(0, atchar).toUpperCase();
URI = URI.substring(atchar + 1);
boolean validKeyType = false;
for(int i = 0; i < VALID_KEY_TYPES.length; i++) {
if (_keyType.equals(VALID_KEY_TYPES[i])) {
validKeyType = true;
_keyType = VALID_KEY_TYPES[i];
break;
}
}
keyType = _keyType;
if(!validKeyType)
throw new MalformedURLException("Invalid key type: " + keyType);
boolean isSSK = "SSK".equals(keyType);
boolean isUSK = "USK".equals(keyType);
boolean isKSK = "KSK".equals(keyType);
// decode metaString
ArrayList<String> sv = null;
int slash2;
sv = new ArrayList<String>();
if (isKSK) URI = "/" + URI; // ensure that KSK docNames are decoded
while ((slash2 = URI.lastIndexOf('/')) != -1) {
String s;
try {
s = URLDecoder.decode(URI.substring(slash2 + 1 /* "/".length() */), true);
} catch(URLEncodedFormatException e) {
throw (MalformedURLException)new MalformedURLException(e.toString()).initCause(e);
}
if(s != null)
sv.add(s);
URI = URI.substring(0, slash2);
}
// sv is *backwards*
// this makes for more efficient handling
// SSK@ = create a random SSK
if(sv.isEmpty() && (isUSK || isKSK))
throw new MalformedURLException("No docname for " + keyType);
if((isSSK || isUSK || isKSK) && !sv.isEmpty()) {
docName = sv.remove(sv.size() - 1);
if(isUSK) {
if(sv.isEmpty())
throw new MalformedURLException("No suggested edition number for USK");
try {
suggestedEdition = Long.parseLong(sv.remove(sv.size() - 1));
} catch(NumberFormatException e) {
throw (MalformedURLException)new MalformedURLException("Invalid suggested edition: " + e).initCause(e);
}
} else
suggestedEdition = -1;
} else {
// docName not necessary, nor is it supported, for CHKs.
docName = null;
suggestedEdition = -1;
}
if(!sv.isEmpty()) {
metaStr = new String[sv.size()];
for(int i = 0; i < metaStr.length; i++) {
metaStr[i] = sv.get(metaStr.length - 1 - i).intern();
if(metaStr[i] == null)
throw new NullPointerException();
}
} else
metaStr = null;
if(isKSK) {
routingKey = extra = cryptoKey = null;
return;
}
// strip 'file extensions' from CHKs
// added by aum (david@rebirthing.co.nz)
if("CHK".equals(keyType)) {
int idx = URI.lastIndexOf('.');
if(idx != -1)
URI = URI.substring(0, idx);
}
// URI now contains: routingKey[,cryptoKey][,metaInfo]
StringTokenizer st = new StringTokenizer(URI, ",");
try {
if(st.hasMoreTokens()) {
routingKey = Base64.decode(st.nextToken());
if(routingKey.length != 32 && keyType.equals("CHK"))
throw new MalformedURLException("Bad URI: Routing key should be 32 bytes long");
} else {
routingKey = cryptoKey = extra = null;
return;
}
if(!st.hasMoreTokens()) {
cryptoKey = extra = null;
return;
}
// Can be cryptokey or name-value pair.
String t = st.nextToken();
cryptoKey = Base64.decode(t);
if(cryptoKey.length != 32)
throw new MalformedURLException("Bad URI: Routing key should be 32 bytes long");
if(!st.hasMoreTokens()) {
extra = null;
return;
}
extra = Base64.decode(st.nextToken());
} catch(IllegalBase64Exception e) {
throw new MalformedURLException("Invalid Base64 quantity: " + e);
}
if (logDEBUG) Logger.debug(this, "Created from parse: "+toString()+" from "+URI, new Exception("debug"));
}