/* * 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. */ options { STATIC = false; } PARSER_BEGIN(PropertyListParser) package org.apache.commons.configuration2.plist; import java.util.Date; import java.util.List; import java.util.ArrayList; import org.apache.commons.configuration2.HierarchicalConfiguration; import org.apache.commons.configuration2.tree.ImmutableNode; import org.apache.commons.codec.binary.Hex; /** * JavaCC based parser for the PropertyList format. * * @author Emmanuel Bourg * @version $Id$ */ class PropertyListParser { /** * Remove the quotes at the beginning and at the end of the specified String. */ protected String removeQuotes(String s) { if (s == null) { return null; } if (s.startsWith("\"") && s.endsWith("\"") && s.length() >= 2) { s = s.substring(1, s.length() - 1); } return s; } protected String unescapeQuotes(String s) { return s.replaceAll("\\\\\"", "\""); } /** * Remove the white spaces and the data delimiters from the specified * string and parse it as a byte array. */ protected byte[] filterData(String s) throws ParseException { if (s == null) { return null; } // remove the delimiters if (s.startsWith("<") && s.endsWith(">") && s.length() >= 2) { s = s.substring(1, s.length() - 1); } // remove the white spaces s = s.replaceAll("\\s", ""); // add a leading 0 to ensure well formed bytes if (s.length() % 2 != 0) { s = "0" + s; } // parse and return the bytes try { return Hex.decodeHex(s.toCharArray()); } catch (Exception e) { throw (ParseException) new ParseException("Unable to parse the byte[] : " + e.getMessage()); } } /** * Parse a date formatted as <*D2002-03-22 11:30:00 +0100> */ protected Date parseDate(String s) throws ParseException { return PropertyListConfiguration.parseDate(s); } } PARSER_END(PropertyListParser) SKIP : { " " | "\t" | "\n" | "\r" } // Handle comments MORE : { "/*": IN_COMMENT } < IN_COMMENT > MORE : { < ~[] > } < IN_COMMENT > SKIP : { "*/": DEFAULT } MORE : { "//": IN_SINGLE_LINE_COMMENT } < IN_SINGLE_LINE_COMMENT > SPECIAL_TOKEN : { < SINGLE_LINE_COMMENT: "\n"|"\r"|"\r\n" > : DEFAULT } < IN_SINGLE_LINE_COMMENT > MORE : { < ~[] > } TOKEN : { } TOKEN : { } TOKEN : { } TOKEN : { } TOKEN : { } TOKEN : { } TOKEN : { } TOKEN : { " > } TOKEN : { } TOKEN : { < QUOTE : "\"" > } TOKEN : { < #LETTER : ~[" ", "\t", "\n", "\r", "(", ")", ",", "{", "}", ";", "=", "\""] > } TOKEN : { < #WHITE : " " | "\t" | "\n" | "\r" > } TOKEN : { < #HEXA : ["0"-"9", "a"-"f", "A"-"F"] > } TOKEN : { < DATA : ( | )* > } TOKEN : { < DATE : (["0"-"9"] | ":" | " " | "+" | "-" | "Z")* > } TOKEN : { < STRING : ()+ > } TOKEN : { < QUOTED_STRING : ( | | | | | | | | | )* > } TOKEN : { < ESCAPED_QUOTE : "\\\"" > } PropertyListConfiguration parse() : { PropertyListConfiguration configuration = null; } { configuration = Dictionary() { return configuration; } } PropertyListConfiguration Dictionary() : { ImmutableNode.Builder builder = new ImmutableNode.Builder(); ImmutableNode child = null; } { ( child = Property() { if (child.getValue() instanceof HierarchicalConfiguration) { // prune & graft the nested configuration to the parent configuration @SuppressWarnings("unchecked") // we created this configuration HierarchicalConfiguration conf = (HierarchicalConfiguration) child.getValue(); ImmutableNode root = conf.getNodeModel().getNodeHandler().getRootNode(); ImmutableNode.Builder childBuilder = new ImmutableNode.Builder(); childBuilder.name(child.getNodeName()).value(root.getValue()) .addChildren(root.getChildren()); builder.addChild(childBuilder.create()); } else { builder.addChild(child); } } )* { return new PropertyListConfiguration(builder.create()); } } ImmutableNode Property() : { String key = null; Object value = null; ImmutableNode.Builder node = new ImmutableNode.Builder(); } { key = String() { node.name(key); } value = Element() { node.value(value); } ()? { return node.create(); } } Object Element() : { Object value = null; } { LOOKAHEAD(2) value = Array() { return value; } | value = Dictionary() { return value; } | value = String() { return value; } | value = Data() { return value; } | value = Date() { return value; } } List Array() : { List list = new ArrayList(); Object element = null; } { ( element = Element() { list.add(element); } ( element = Element() { list.add(element); } )* )? { return list; } } String String() : { Token token = null; String value = null; } { token = { return unescapeQuotes(removeQuotes(token.image)); } | token = { return token.image; } } byte[] Data() : { Token token; } { token = { return filterData(token.image); } } Date Date() : { Token token; } { token = { return parseDate(token.image); } }