
net.named_data.jndn.util.BoostInfoParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jndn-android-with-async-io Show documentation
Show all versions of jndn-android-with-async-io Show documentation
jNDN is a new implementation of a Named Data Networking client library written in Java. It is wire format compatible with the new NDN-TLV encoding, with NDNx and PARC's CCNx.
/**
* Copyright (C) 2015-2017 Regents of the University of California.
* @author: Jeff Thompson
* From PyNDN boost_info_parser by Adeola Bannis.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
* A copy of the GNU Lesser General Public License is in the file COPYING.
*/
package net.named_data.jndn.util;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
/**
* A BoostInfoParser reads files in Boost's INFO format and constructs a
* BoostInfoTree.
*/
public class BoostInfoParser {
/**
* Add the contents of the file to the root BoostInfoTree.
* @param fileName The path to the INFO file.
* @return The new root BoostInfoTree.
*/
public BoostInfoTree
read(String fileName) throws IOException
{
BufferedReader stream = new BufferedReader(new FileReader(fileName));
// Use "try/finally instead of "try-with-resources" or "using"
// which are not supported before Java 7.
try {
read(stream, root_);
} finally {
stream.close();
}
return root_;
}
/**
* Add the contents of the input string to the root BoostInfoTree.
* @param input The contents of the INFO file, with lines separated by "\n" or
* "\r\n".
* @param inputName Used for log messages, etc.
* @return The new root BoostInfoTree.
* @throws IOException
*/
public BoostInfoTree
read(String input, String inputName) throws IOException
{
BufferedReader stream = new BufferedReader(new StringReader(input));
read(stream, root_);
return root_;
}
/**
* Write the root tree of this BoostInfoParser as file in Boost's INFO format.
* @param fileName The output path.
*/
public final void
write(String fileName) throws IOException
{
BufferedWriter writer = new BufferedWriter(new FileWriter(fileName));
try {
writer.write("" + root_);
writer.flush();
}
finally{
writer.close();
}
}
/**
* Get the root tree of this parser.
* @return The root BoostInfoTree.
*/
public final BoostInfoTree
getRoot() { return root_; }
/**
* Similar to Python's shlex.split, split s into an array of strings which are
* separated by whitespace, treating a string within quotes as a single entity
* regardless of whitespace between the quotes. Also allow a backslash to
* escape the next character.
* @param s The input string to split.
* @param result This appends the split strings to result which is a list of
* String. This does not first clear the list.
*/
private static void
shlex_split(String s, ArrayList result)
{
if (s.length() == 0)
return;
String whiteSpace = " \t\n\r";
int iStart = 0;
while (true) {
// Move iStart past whitespace.
while (whiteSpace.indexOf(s.charAt(iStart)) >= 0) {
++iStart;
if (iStart >= s.length())
// Done.
return;
}
// Move iEnd to the end of the token.
int iEnd = iStart;
boolean inQuotation = false;
String token = "";
while (true) {
if (s.charAt(iEnd) == '\\') {
// Append characters up to the backslash, skip the backslash and
// move iEnd past the escaped character.
token += s.substring(iStart, iEnd);
iStart = iEnd + 1;
iEnd = iStart;
if (iEnd >= s.length()) {
// An unusual case: A backslash at the end of the string.
break;
}
}
else {
if (inQuotation) {
if (s.charAt(iEnd) == '\"') {
// Append characters up to the end quote and skip.
token += s.substring(iStart, iEnd);
iStart = iEnd + 1;
inQuotation = false;
}
}
else {
if (s.charAt(iEnd) == '\"') {
// Append characters up to the start quote and skip.
token += s.substring(iStart, iEnd);
iStart = iEnd + 1;
inQuotation = true;
}
else {
if (whiteSpace.indexOf(s.charAt(iEnd)) >= 0)
break;
}
}
}
++iEnd;
if (iEnd >= s.length())
break;
}
token += s.substring(iStart, iEnd);
result.add(token);
if (iEnd >= s.length())
// Done.
return;
iStart = iEnd;
}
}
/**
* Internal import method with an explicit context node.
* @param stream The stream for reading the INFO content.
* @param ctx The node currently being populated.
* @return The ctx.
*/
private BoostInfoTree
read(BufferedReader stream, BoostInfoTree ctx) throws IOException
{
String line = null;
while ((line = stream.readLine()) != null)
ctx = parseLine(line.trim(), ctx);
return ctx;
}
/**
* Internal helper method for parsing INFO files line by line.
*/
private BoostInfoTree
parseLine(String line, BoostInfoTree context) throws IOException
{
// Skip blank lines and comments.
int commentStart = line.indexOf(';');
if (commentStart >= 0)
line = line.substring(0, commentStart).trim();
if (line.length() == 0)
return context;
// Usually we are expecting key and optional value.
// Use ArrayList without generics so it works with older Java compilers.
ArrayList strings = new ArrayList();
shlex_split(line, strings);
boolean isSectionStart = false;
boolean isSectionEnd = false;
for (int i = 0; i < strings.size(); ++i) {
isSectionStart = (isSectionStart || "{".equals(strings.get(i)));
isSectionEnd = (isSectionEnd || "}".equals(strings.get(i)));
}
if (!isSectionStart && !isSectionEnd) {
String key = strings.get(0);
String val = "";
if (strings.size() > 1)
val = strings.get(1);
// If it is an "#include", load the new file instead of inserting keys.
if ("#include".equals(key)) {
BufferedReader stream = new BufferedReader(new FileReader(val));
// Use "try/finally instead of "try-with-resources" or "using"
// which are not supported before Java 7.
try {
context = read(stream, context);
} finally {
stream.close();
}
}
else
context.createSubtree(key, val);
return context;
}
// OK, who is the joker who put a { on the same line as the key name?!
int sectionStart = line.indexOf('{');
if (sectionStart > 0) {
String firstPart = line.substring(0, sectionStart);
String secondPart = line.substring(sectionStart);
BoostInfoTree ctx = parseLine(firstPart, context);
return parseLine(secondPart, ctx);
}
// If we encounter a {, we are beginning a new context.
// TODO: Error if there was already a subcontext here.
if (line.charAt(0) == '{') {
context = context.getLastChild();
return context;
}
// If we encounter a }, we are ending a list context.
if (line.charAt(0) == '}') {
context = context.getParent();
return context;
}
throw new Error("BoostInfoParser: input line is malformed");
}
private BoostInfoTree root_ = new BoostInfoTree();
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy