/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.sling.resourceresolver.impl.params; import java.util.LinkedHashMap; import java.util.Map; class ParametersParser { private enum ParamsState { INIT, NAME, EQUALS, VALUE, QUOTED_VALUE, QUOTE_END } private StringBuilder name; private StringBuilder value; private Map<String, String> parameters = new LinkedHashMap<String, String>(); private boolean invalid; /** * Parses parameters string, eg.: {@code ;x=123;a='1.0'}. The result of the method is available in * {@link #parameters} and {@link #invalid}. * * @param chars Array containing path with parameters. * @param from Index of the first character of the parameters substring (it must be a semicolon). * @param dotAllowed If true, the dot in parameter value won't stop parsing. * @return Index of the first character not related to parameters. */ public int parseParameters(final char[] chars, final int from, final boolean dotAllowed) { resetCurrentParameter(); parameters.clear(); invalid = false; ParamsState state = ParamsState.INIT; for (int i = from; i <= chars.length; i++) { final char c; if (i == chars.length) { c = 0; } else { c = chars[i]; } switch (state) { case INIT: if (c == ';') { state = ParamsState.NAME; } else if (c == '.' || c == '/' || c == 0) { invalid = true; return i; } break; case NAME: if (c == '=') { state = ParamsState.EQUALS; } else if (c == '.' || c == '/' || c == 0) { invalid = true; return i; } else if (c == ';') { resetCurrentParameter(); } else { name.append(c); } break; case EQUALS: if (c == '\'') { state = ParamsState.QUOTED_VALUE; } else if (c == '.' || c == '/' || c == 0) { addParameter(); // empty one return i; } else if (c == ';') { state = ParamsState.NAME; // empty one addParameter(); } else { state = ParamsState.VALUE; value.append(c); } break; case QUOTED_VALUE: if (c == '\'') { state = ParamsState.QUOTE_END; addParameter(); } else if (c == 0) { invalid = true; return i; } else { value.append(c); } break; case VALUE: if (c == ';') { state = ParamsState.NAME; addParameter(); } else if ((c == '.' && !dotAllowed) || c == '/' || c == 0) { addParameter(); return i; } else { value.append(c); } break; case QUOTE_END: if (c == ';') { state = ParamsState.NAME; } else { return i; } } } return chars.length; } /** * @return Parsed parameters. */ public Map<String, String> getParameters() { return parameters; } /** * @return True if the {@link #parseParameters(char[], int, boolean)} method failed. */ public boolean isInvalid() { return invalid; } private void resetCurrentParameter() { name = new StringBuilder(); value = new StringBuilder(); } private void addParameter() { parameters.put(name.toString(), value.toString()); name = new StringBuilder(); value = new StringBuilder(); } }