![JAR search and dependency download from the Maven repository](/logo.png)
org.apache.royale.compiler.internal.resourcebundles.PropertiesFileParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of compiler Show documentation
Show all versions of compiler Show documentation
The Apache Royale Compiler
/*
*
* 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.royale.compiler.internal.resourcebundles;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.royale.compiler.common.ISourceLocation;
import org.apache.royale.compiler.common.SourceLocation;
import org.apache.royale.compiler.constants.IMetaAttributeConstants;
import org.apache.royale.compiler.internal.parsing.as.ASParser;
import org.apache.royale.compiler.internal.tree.as.ClassReferenceNode;
import org.apache.royale.compiler.internal.tree.as.EmbedNode;
import org.apache.royale.compiler.internal.tree.as.ExpressionNodeBase;
import org.apache.royale.compiler.internal.tree.as.LiteralNode;
import org.apache.royale.compiler.internal.tree.as.metadata.MetaTagsNode;
import org.apache.royale.compiler.internal.tree.properties.ResourceBundleEntryNode;
import org.apache.royale.compiler.internal.tree.properties.ResourceBundleFileNode;
import org.apache.royale.compiler.problems.FileNotFoundProblem;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.problems.InternalCompilerProblem2;
import org.apache.royale.compiler.problems.ParserProblem;
import org.apache.royale.compiler.problems.ResourceBundleMalformedEncodingProblem;
import org.apache.royale.compiler.tree.as.ILiteralNode.LiteralType;
import org.apache.royale.compiler.tree.metadata.IMetaTagNode;
import org.apache.royale.compiler.workspaces.IWorkspace;
/**
* Properties parser that reads a properties file in Unicode.
*/
public class PropertiesFileParser
{
public static final Pattern CLASS_REFERENCE_REGEX = Pattern.compile("ClassReference\\((.*)\\)");
public static final Pattern EMBED_REGEX = Pattern.compile(IMetaAttributeConstants.ATTRIBUTE_EMBED + "\\(.*\\)");
/**
* Characters we skip in certain places
*/
private static final String WHITESPACE = " \t\n\r\f";
/**
* Characters that terminate a key
*/
private static String SPLITTERS = "=: \t";
/**
* Characters that terminate a value
*/
private static final String TERMINATORS = "\n\r\f";
/**
* Path of the file that is parsed.
*/
private String filePath;
/**
* File node for the properties file being parsed
*/
private ResourceBundleFileNode fileNode;
/**
* Collection that is used to store problems that occur during parsing.
*/
private Collection problems;
private IWorkspace workspace;
/**
* Constructor
*/
public PropertiesFileParser(IWorkspace workspace) {
this.workspace = workspace;
}
/**
* This method attempts to parse a .properties file
* using the same rules as Java, except that the file
* is assumed to have UTF-8 encoding.
*
* Let indicates optional whitespace and required whitespace.
*
* Comment lines have the form # or !
* If # or ! isn't the first non-whitespace character on a line,
* it doesn't start a comment.
*
* Key/value pairs have the form key=value
* or key:value or keyvalue
* In other words, you can use an equal sign, a colon,
* or just whitespace to separate the key from the value.
*
* Trailing whitespace is not stripped from the value.
*
* You can use standard escape sequences
* like \n, \r, \t, \u1234, and \\.
*
* Backslash-space is an escape sequence for a space;
* for example, if a value needs to start with a space
* you must write it as backslash-space or it will be
* interpreted as optional whitespace preceding the value.
* However, you don't need to escape spaces within a value.
*
* You can continue a line by ending it with a backslash.
* Leading whitespace on the next line is stripped.
*
* Backslashes that aren't part of an escape sequence are removed.
* For example, \A is just A.
*
* You don't need to escape a double-quote or a single-quote
* (but it doesn't hurt to do so).
*
* @param filePath path of the properties file to parse.
* @param locale locale of the file if it is locale dependent, otherweise null
* @param reader reader that wraps an open stream to the file to parse.
* @param problems collection that is used to store problems that occur
* during parsing
*/
public ResourceBundleFileNode parse(String filePath, String locale,
Reader reader, Collection problems) {
this.filePath = filePath;
this.problems = problems;
try
{
fileNode = new ResourceBundleFileNode(workspace, filePath, locale);
parse(new BufferedReader(reader));
return fileNode;
}
catch(FileNotFoundException ex)
{
ICompilerProblem problem = new FileNotFoundProblem(filePath);
problems.add(problem);
}
catch (IOException ex)
{
ICompilerProblem problem = new InternalCompilerProblem2(filePath, ex, "PropertiesFileParser");
problems.add(problem);
}
finally
{
if (reader != null)
{
try
{
reader.close();
}
catch (IOException ex)
{
}
}
}
return null;
}
/**
* Parses the properties file.
*
* @param br buffered reader to read the properties file.
* @throws IOException
*/
private void parse(BufferedReader br) throws IOException
{
String line;
StringBuilder buffer = new StringBuilder(100);
int lineNumber = 0;
int comment_length=0;
String sep = System.getProperty("line.separator");
int sep_len = sep.length();
int offset = 0;
while((line=br.readLine())!=null) {
lineNumber++;
int len = line.length();
offset+=len;
int start=0;
// TODO: Clean this up some day by using:
// http://commons.apache.org/io/api-release/org/apache/commons/io/input/BOMInputStream.html
// skip the Unicode BOM; UTF-8 is indicated by the byte sequence
// EF BB BF, which is the UTF-8 encoding of the character U+FEFF)
if (lineNumber == 1 && len > 0 && line.charAt(0) == '\uFEFF') {
line = line.substring(1);
len = line.length();
offset = len;
}
// find first non-whitespace char
for(;start 1 && line.charAt(line.length()-1)=='\\') {
buffer.setLength(buffer.length()-1); // remove the backslash
line=br.readLine();
if(line!=null) {
int new_start = 0;
len = line.length();
// find first non-whitespace char
for(;new_start < len &&
WHITESPACE.indexOf(line.charAt(new_start))!=-1;
new_start++);
// add to buffer
buffer.append(line.substring(new_start));
}
}
String propLine = buffer.toString();
String com_key = loadProperty(propLine, lineNumber, offset, start);
if(comment_length!=0 && com_key != null) {
comment_length=0;
}
buffer.setLength(0);
}
}
/**
* Parses a line in a property file.
*
* @param prop
* @param lineNumber
* @return
*/
private String loadProperty(String property, int lineNumber, int startOffset, int column)
{
String key;
String value;
int prop_len=property.length();
int prop_index=0;
// key
for(; prop_index problems)
{
LiteralNode keyNode = new LiteralNode(LiteralType.STRING, key, keySource);
ExpressionNodeBase valueNode = null;
Matcher matcher;
if ((matcher = CLASS_REFERENCE_REGEX.matcher(value)).matches())
{
valueNode = processClassReference(matcher, valueSource, problems);
}
else if ((matcher = EMBED_REGEX.matcher(value)).matches())
{
valueNode = processEmbed(value, valueSource, problems);
}
else
{
valueNode = new LiteralNode(LiteralType.STRING, value, valueSource);
}
if(valueNode != null)
fileNode.addItem(new ResourceBundleEntryNode(keyNode, valueNode));
}
/**
* Process a ClassReference directive that occurs in a properties file.
*
* @param matcher matcher that has already identified a ClassReference directive in a value.
* @param sourceLocation location where this directive occurred in the file
* @param problems collection to add problems if encountered during
* processing.
* @return a {@link ClassReferenceNode} instance that represents this
* occurrence or null
if any problem occurs.
*/
private ClassReferenceNode processClassReference(Matcher matcher, SourceLocation sourceLocation,
Collection problems)
{
try
{
String qName = matcher.group(1).trim();
if (qName.equals("null"))
{
return new ClassReferenceNode(null, sourceLocation);
}
if ((qName.charAt(0) == '"') && (qName.indexOf('"', 1) == qName.length() - 1))
{
qName = qName.substring(1, qName.length() - 1);
return new ClassReferenceNode(qName, sourceLocation);
}
}
catch(Exception e)
{
//do nothing, problem will be reported next.
}
ParserProblem problem = new ParserProblem(sourceLocation);
problems.add(problem);
return null;
}
/**
* Process a Embed directive that occurs in a properties file.
*
* @param value Embed directive to process
* @param sourceLocation location where this directive occurred in the file
* @param problems collection to add problems if encountered during
* processing.
* @return a {@link EmbedNode} instance that represents this
* occurrence or null
if any problem occurs.
*/
private EmbedNode processEmbed(String value, SourceLocation sourceLocation,
Collection problems)
{
StringBuilder sb = new StringBuilder();
sb.append("[");
sb.append(value);
sb.append("]");
MetaTagsNode metaTagsNode = ASParser.parseMetadata(
workspace, sb.toString(), sourceLocation.getSourcePath(), sourceLocation.getAbsoluteStart(),
sourceLocation.getLine(), sourceLocation.getColumn(), problems);
if (metaTagsNode == null)
return null;
IMetaTagNode embedMetaTagNode = metaTagsNode.getTagByName(IMetaAttributeConstants.ATTRIBUTE_EMBED);
if (embedMetaTagNode == null)
return null;
EmbedNode embedNode = new EmbedNode(filePath, embedMetaTagNode, fileNode);
embedNode.setSourceLocation(sourceLocation);
return embedNode;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy