/******************************************************************************* * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * 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. * *******************************************************************************/ package com.liferay.ide.core.properties; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.HashMap; import java.util.Map; /** * @author Gregory Amerson * * Most of the code in this file was copied from java.util.Properties class so it is not properly formatted */ public class PropertiesFileLookup { public static class KeyInfo { public final int offset; public final int length; public String value; public KeyInfo( int offset, int length ) { this.offset = offset; this.length = length; } } /** * copied from java.util.properties$LineReader */ class LineReader { public LineReader(Reader reader) { this.reader = reader; inCharBuf = new char[8192]; } char[] inCharBuf; char[] lineBuf = new char[1024]; int inLimit = 0; int inOff = 0; int total = 0; Reader reader; int[] readLine() throws IOException { int len = 0; char c = 0; boolean skipWhiteSpace = true; boolean isCommentLine = false; boolean isNewLine = true; boolean appendedLineBegin = false; boolean precedingBackslash = false; boolean skipLF = false; while (true) { if (inOff >= inLimit) { inLimit = reader.read(inCharBuf); inOff = 0; if (inLimit <= 0) { if (len == 0 || isCommentLine) { return new int[] { -1, total }; } return new int[] { len, total }; } } c = inCharBuf[inOff++]; total++; if (skipLF) { skipLF = false; if (c == '\n') { continue; } } if (skipWhiteSpace) { if (c == ' ' || c == '\t' || c == '\f') { continue; } if (!appendedLineBegin && (c == '\r' || c == '\n')) { continue; } skipWhiteSpace = false; appendedLineBegin = false; } if (isNewLine) { isNewLine = false; if (c == '#' || c == '!') { isCommentLine = true; continue; } } if (c != '\n' && c != '\r') { lineBuf[len++] = c; if (len == lineBuf.length) { int newLength = lineBuf.length * 2; if (newLength < 0) { newLength = Integer.MAX_VALUE; } char[] buf = new char[newLength]; System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length); lineBuf = buf; } //flip the preceding backslash flag if (c == '\\') { precedingBackslash = !precedingBackslash; } else { precedingBackslash = false; } } else { // reached EOL if (isCommentLine || len == 0) { isCommentLine = false; isNewLine = true; skipWhiteSpace = true; len = 0; continue; } if (inOff >= inLimit) { inLimit = reader.read(inCharBuf); inOff = 0; if (inLimit <= 0) { return new int[] { len, total }; } } if (precedingBackslash) { len -= 1; //skip the leading whitespace characters in following line skipWhiteSpace = true; appendedLineBegin = true; precedingBackslash = false; if (c == '\r') { skipLF = true; } } else { return new int[] { len, total }; } } } } } final Map<String, KeyInfo> lookup = new HashMap<String, KeyInfo>(); public PropertiesFileLookup( InputStream input ) { try { parse( input, null, false ); } catch( IOException e ) { } finally { try { input.close(); } catch( IOException e ) { } } } public PropertiesFileLookup( InputStream input, String initialLookup, boolean loadValues ) { try { parse( input, initialLookup, loadValues ); } catch( IOException e ) { } finally { try { input.close(); } catch( IOException e ) { } } } private void parse( InputStream input, String initialLookup, boolean loadValues ) throws IOException { final LineReader lr = new LineReader( new InputStreamReader( input ) ); char[] convtBuf = new char[1024]; int[] limit; int keyLen; int valueStart; char c; boolean hasSep; boolean precedingBackslash; while ((limit = lr.readLine())[0] >= 0) { c = 0; keyLen = 0; valueStart = limit[0]; hasSep = false; //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">"); precedingBackslash = false; while (keyLen < limit[0]) { c = lr.lineBuf[keyLen]; //need check if escaped. if ((c == '=' || c == ':') && !precedingBackslash) { valueStart = keyLen + 1; hasSep = true; break; } else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) { valueStart = keyLen + 1; break; } if (c == '\\') { precedingBackslash = !precedingBackslash; } else { precedingBackslash = false; } keyLen++; } if( loadValues ) { while (valueStart < limit[0]) { c = lr.lineBuf[valueStart]; if (c != ' ' && c != '\t' && c != '\f') { if (!hasSep && (c == '=' || c == ':')) { hasSep = true; } else { break; } } valueStart++; } } String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf); KeyInfo info = new KeyInfo( limit[1] - limit[0] - 1, keyLen ); if( loadValues ) { info.value = loadConvert(lr.lineBuf, valueStart, limit[0] - valueStart, convtBuf); } lookup.put( key, info ); if( key.equals( initialLookup ) ) { return; } } } /** * Copied from java.util.Properties */ private String loadConvert (char[] in, int off, int len, char[] convtBuf) { if (convtBuf.length < len) { int newLen = len * 2; if (newLen < 0) { newLen = Integer.MAX_VALUE; } convtBuf = new char[newLen]; } char aChar; char[] out = convtBuf; int outLen = 0; int end = off + len; while (off < end) { aChar = in[off++]; if (aChar == '\\') { aChar = in[off++]; if(aChar == 'u') { // Read the xxxx int value=0; for (int i=0; i<4; i++) { aChar = in[off++]; switch (aChar) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': value = (value << 4) + aChar - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': value = (value << 4) + 10 + aChar - 'a'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': value = (value << 4) + 10 + aChar - 'A'; break; default: throw new IllegalArgumentException("Malformed \\uxxxx encoding."); //$NON-NLS-1$ } } out[outLen++] = (char)value; } else { if (aChar == 't') aChar = '\t'; else if (aChar == 'r') aChar = '\r'; else if (aChar == 'n') aChar = '\n'; else if (aChar == 'f') aChar = '\f'; out[outLen++] = aChar; } } else { out[outLen++] = aChar; } } return new String (out, 0, outLen); } public KeyInfo getKeyInfo( String keyValue ) { return this.lookup.get( keyValue ); } }