/* * file: Record.java * author: Bruno Gasnier * copyright: (c) Packwood Software 2002-2011 * date: 2011-02-16 */ /* * This library 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 2.1 of the License, or (at your * option) any later version. * * This library 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 library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ package net.sf.mpxj.primavera; import java.util.ArrayList; import java.util.List; /** * Represents and parses Primavera compound record data. */ class Record { /** * Constructor. Parse an entire string. * * @param text string to parse */ protected Record(String text) { this(text, 0, text.length()); } /** * Constructor. Parse a segment of a string. * * @param text string to parse * @param start start position * @param end end position */ protected Record(String text, int start, int end) { parse(text, start, end); } /** * Retrieve the field represented by this record. * * @return field */ public String getField() { return m_field; } /** * Retrieve the value represented by this record. * * @return value */ public String getValue() { return m_value; } /** * Retrieve all child records. * * @return list of child records */ public List<Record> getChildren() { return m_records; } /** * Retrieve a child record by name. * * @param key child record name * @return child record */ public Record getChild(String key) { Record result = null; if (key != null) { for (Record record : m_records) { if (key.equals(record.getField())) { result = record; break; } } } return result; } /** * Parse a block of text into records. * * @param text text to parse * @param start start index * @param end end index */ private void parse(String text, int start, int end) { int closing = getClosingParenthesisPosition(text, start); if (closing == -1 || closing > end) { throw new IllegalStateException("Error in parenthesis hierarchy"); } if (!text.startsWith("(0||")) { throw new IllegalStateException("Not a valid record"); } int valueStart = getNextOpeningParenthesisPosition(text, start); int valueStop = getClosingParenthesisPosition(text, valueStart); int dictStart = getNextOpeningParenthesisPosition(text, valueStop); int dictStop = getClosingParenthesisPosition(text, dictStart); parse(text, start + 4, valueStart, valueStop, dictStart, dictStop); } /** * Parse a block of text into records. * * @param text text to be parsed * @param start start index * @param valueStart value start index * @param valueStop value end index * @param dictStart dictionary start index * @param dictStop dictionary end index */ private void parse(String text, int start, int valueStart, int valueStop, int dictStart, int dictStop) { m_field = text.substring(start, valueStart); if (valueStop - valueStart <= 1) { m_value = null; } else { m_value = text.substring(valueStart + 1, valueStop); } if (dictStop - dictStart > 1) { for (int s = getNextOpeningParenthesisPosition(text, dictStart); s >= 0 && s < dictStop;) { int e = getClosingParenthesisPosition(text, s); m_records.add(new Record(text, s, e)); s = getNextOpeningParenthesisPosition(text, e); } } } /** * Look for the closing parenthesis corresponding to the one at position * represented by the opening index. * * @param text input expression * @param opening opening parenthesis index * @return closing parenthesis index */ private int getClosingParenthesisPosition(String text, int opening) { if (text.charAt(opening) != '(') { return -1; } int count = 0; for (int i = opening; i < text.length(); i++) { char c = text.charAt(i); switch (c) { case '(': { ++count; break; } case ')': { --count; if (count == 0) { return i; } break; } } } return -1; } /** * Retrieve the position of the next opening parenthesis. * * @param text text being parsed * @param position start position * @return index of parenthesis */ private int getNextOpeningParenthesisPosition(String text, int position) { return text.indexOf('(', position + 1); } /** * {@inheritDoc} */ @Override public String toString() { return this.toString(1); } /** * Method to build hierarchical string representation - called recursively. * * @param spaces number of spaces to use to format the string * @return formatted string */ protected String toString(int spaces) { StringBuilder result = new StringBuilder("(0||" + (m_field == null ? "" : m_field) + "(" + (m_value == null ? "" : m_value) + ")("); for (Record record : m_records) { if (spaces != 0) { result.append(SEPARATOR); for (int i = 0; i < spaces * 2; i++) { result.append(" "); } } result.append(record.toString(spaces + 1)); } result.append("))"); return result.toString(); } private String m_field; private String m_value; private List<Record> m_records = new ArrayList<Record>(); private static final String SEPARATOR = new String(new byte[] { 0x7f, 0x7f }); }