class DSLParser {

    private static Map<String, String> parseQuery(final String query) {
        final Map<String, String> parameters = new HashMap<>();
        if (query == null || query.trim().isEmpty()) {
            return parameters;
        }

        final byte[] bytes = query.getBytes(StandardCharsets.UTF_8);

        int pos = 0;
        int end = bytes.length;

        String name;
        String value;
        while (pos < end) {
            int nameStart = pos;
            int nameEnd = -1;
            int valueStart = -1;
            int valueEnd = -1;

            boolean parsingName = true;
            boolean decodeName = false;
            boolean decodeValue = false;
            boolean parameterComplete = false;

            do {
                switch (bytes[pos]) {
                case '=':
                    if (parsingName) {
                        nameEnd = pos;
                        parsingName = false;
                        valueStart = ++pos;
                    } else {
                        pos++;
                    }
                    break;
                case '&':
                    if (parsingName) {
                        // Name finished. No value.
                        nameEnd = pos;
                    } else {
                        // Value finished
                        valueEnd = pos;
                    }
                    parameterComplete = true;
                    pos++;
                    break;
                case '%':
                case '+':
                    // Decoding required
                    if (parsingName) {
                        decodeName = true;
                    } else {
                        decodeValue = true;
                    }
                    pos++;
                    break;
                default:
                    pos++;
                    break;
                }
            } while (!parameterComplete && pos < end);

            if (pos == end) {
                if (nameEnd == -1) {
                    nameEnd = pos;
                } else if (valueStart > -1 && valueEnd == -1) {
                    valueEnd = pos;
                }
            }

            if (nameEnd <= nameStart) {
                continue;
            }

            name = new String(bytes, nameStart, nameEnd - nameStart);
            if (decodeName) {
                name = decode(name);
            }
            if (valueStart >= 0) {
                value = new String(bytes, valueStart, valueEnd - valueStart);
                if (decodeValue) {
                    value = decode(value);
                }
            } else {
                value = "true"; // tomcat defaults to "", but for us (configuration) true is likely better
            }

            parameters.put(name, value);
        }
        return parameters;
    }

}