| /* |
| * 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 : { <ARRAY_BEGIN : "(" > } |
| TOKEN : { <ARRAY_END : ")" > } |
| TOKEN : { <ARRAY_SEPARATOR : "," > } |
| |
| TOKEN : { <DICT_BEGIN : "{" > } |
| TOKEN : { <DICT_END : "}" > } |
| TOKEN : { <DICT_SEPARATOR : ";" > } |
| TOKEN : { <EQUAL : "=" > } |
| |
| TOKEN : { <DATA_START : "<" > } |
| TOKEN : { <DATA_END : ">" > } |
| |
| TOKEN : { <DATE_START : "<*D" > } |
| |
| TOKEN : { < QUOTE : "\"" > } |
| TOKEN : { < #LETTER : ~[" ", "\t", "\n", "\r", "(", ")", ",", "{", "}", ";", "=", "\""] > } |
| TOKEN : { < #WHITE : " " | "\t" | "\n" | "\r" > } |
| TOKEN : { < #HEXA : ["0"-"9", "a"-"f", "A"-"F"] > } |
| TOKEN : { < DATA : <DATA_START> (<HEXA> | <WHITE>)* <DATA_END> > } |
| TOKEN : { < DATE : <DATE_START> (["0"-"9"] | ":" | " " | "+" | "-" | "Z")* <DATA_END> > } |
| TOKEN : { < STRING : (<LETTER>)+ > } |
| TOKEN : { < QUOTED_STRING : |
| <QUOTE> |
| (<LETTER> | <WHITE> | <ESCAPED_QUOTE> | <EQUAL> |
| | <ARRAY_BEGIN> | <ARRAY_END> | <ARRAY_SEPARATOR> |
| | <DICT_BEGIN> | <DICT_END> | <DICT_SEPARATOR>)* <QUOTE> > } |
| TOKEN : { < ESCAPED_QUOTE : "\\\"" > } |
| |
| PropertyListConfiguration parse() : |
| { |
| PropertyListConfiguration configuration = null; |
| } |
| { |
| configuration = Dictionary() |
| <EOF> |
| { return configuration; } |
| } |
| |
| PropertyListConfiguration Dictionary() : |
| { |
| ImmutableNode.Builder builder = new ImmutableNode.Builder(); |
| ImmutableNode child = null; |
| } |
| { |
| <DICT_BEGIN> |
| ( |
| child = Property() |
| { |
| if (child.getValue() instanceof HierarchicalConfiguration) |
| { |
| // prune & graft the nested configuration to the parent configuration |
| @SuppressWarnings("unchecked") // we created this configuration |
| HierarchicalConfiguration<ImmutableNode> conf = |
| (HierarchicalConfiguration<ImmutableNode>) 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); |
| } |
| } |
| )* |
| <DICT_END> |
| { |
| return new PropertyListConfiguration(builder.create()); |
| } |
| } |
| |
| ImmutableNode Property() : |
| { |
| String key = null; |
| Object value = null; |
| ImmutableNode.Builder node = new ImmutableNode.Builder(); |
| } |
| { |
| key = String() |
| { node.name(key); } |
| <EQUAL> |
| value = Element() |
| { node.value(value); } |
| (<DICT_SEPARATOR>)? |
| { 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<Object> list = new ArrayList<Object>(); |
| Object element = null; |
| } |
| { |
| <ARRAY_BEGIN> |
| ( |
| element = Element() |
| { list.add(element); } |
| ( |
| <ARRAY_SEPARATOR> |
| element = Element() |
| { list.add(element); } |
| )* |
| )? |
| <ARRAY_END> |
| { return list; } |
| } |
| |
| String String() : |
| { |
| Token token = null; |
| String value = null; |
| } |
| { |
| token = <QUOTED_STRING> |
| { return unescapeQuotes(removeQuotes(token.image)); } |
| | |
| token = <STRING> |
| { return token.image; } |
| } |
| |
| byte[] Data() : |
| { |
| Token token; |
| } |
| { |
| token = <DATA> |
| { return filterData(token.image); } |
| } |
| |
| Date Date() : |
| { |
| Token token; |
| } |
| { |
| token = <DATE> |
| { return parseDate(token.image); } |
| } |