java/alt2xml-in-ini/src/cz/frantovo/alt2xml/in/ini/Reader.java
author František Kučera <franta-hg@frantovo.cz>
Sat, 06 Sep 2014 19:36:22 +0200
changeset 82 547f1246fe35
parent 81 a4335757acf1
child 83 06e866769478
permissions -rw-r--r--
in-ini: quoted/apostrophed values might have comments
     1 /**
     2  * Alt2XML
     3  * Copyright © 2014 František Kučera (frantovo.cz)
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, either version 3 of the License, or
     8  * (at your option) any later version.
     9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License
    16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
    17  */
    18 package cz.frantovo.alt2xml.in.ini;
    19 
    20 import cz.frantovo.alt2xml.AbstractAlt2XmlReader;
    21 import cz.frantovo.alt2xml.in.Alt2ContentHandler;
    22 import java.io.BufferedReader;
    23 import java.io.IOException;
    24 import java.io.InputStreamReader;
    25 import java.util.ArrayList;
    26 import java.util.List;
    27 import java.util.logging.Level;
    28 import java.util.logging.Logger;
    29 import java.util.regex.Matcher;
    30 import java.util.regex.Pattern;
    31 import org.xml.sax.InputSource;
    32 import org.xml.sax.SAXException;
    33 
    34 /**
    35  *
    36  * @author Ing. František Kučera (frantovo.cz)
    37  */
    38 public class Reader extends AbstractAlt2XmlReader {
    39 
    40 	public static final String ROOT_ELEMENT = "ini";
    41 	private static final Logger log = Logger.getLogger(Reader.class.getName());
    42 
    43 	@Override
    44 	public void parse(InputSource input) throws IOException, SAXException {
    45 		outputStart();
    46 
    47 		try (BufferedReader br = new BufferedReader(new InputStreamReader(input.getByteStream()))) {
    48 			FileContext fc = new FileContext(contentHandler);
    49 			for (String currentLine = br.readLine(); currentLine != null; currentLine = br.readLine()) {
    50 				for (LINE_TYPE lineType : LINE_TYPE.values()) {
    51 					boolean lineProcessed = lineType.processLine(currentLine, fc);
    52 					if (lineProcessed) {
    53 						break;
    54 					}
    55 				}
    56 			}
    57 			fc.outputEndSection(fc.lastSection);
    58 
    59 		}
    60 
    61 		outputEnd();
    62 	}
    63 
    64 	private void outputStart() throws SAXException {
    65 		contentHandler.startDocument();
    66 		contentHandler.lineBreak();
    67 		contentHandler.startElement(null, null, ROOT_ELEMENT, null);
    68 		contentHandler.lineBreak();
    69 	}
    70 
    71 	private void outputEnd() throws SAXException {
    72 		contentHandler.endElement(null, null, "ini");
    73 		contentHandler.lineBreak();
    74 		contentHandler.endDocument();
    75 	}
    76 
    77 	private static class FileContext {
    78 
    79 		private final Alt2ContentHandler contentHandler;
    80 		private String lastSection;
    81 
    82 		public FileContext(Alt2ContentHandler contentHandler) {
    83 			this.contentHandler = contentHandler;
    84 		}
    85 
    86 		protected void outputStartSection(String name) throws SAXException {
    87 			contentHandler.indentation(1);
    88 			contentHandler.startElement(null, null, name, null);
    89 			contentHandler.lineBreak();
    90 		}
    91 
    92 		protected void outputEndSection(String name) throws SAXException {
    93 			if (name != null) {
    94 				contentHandler.indentation(1);
    95 				contentHandler.endElement(null, null, name);
    96 				contentHandler.lineBreak();
    97 			}
    98 		}
    99 	}
   100 
   101 	private static class LineContext {
   102 
   103 		private final Matcher matcher;
   104 
   105 		public LineContext(Matcher matcher) {
   106 			this.matcher = matcher;
   107 		}
   108 	}
   109 
   110 	private enum LINE_TYPE {
   111 
   112 		COMMENT("\\s*(;|#)\\s*(.*)") {
   113 					@Override
   114 					public void processLine(LineContext lc, FileContext fc) throws SAXException {
   115 						// TODO: comment → LexicalHandler
   116 						log.log(Level.FINER, "Comment: {0}", lc.matcher.group(2));
   117 					}
   118 
   119 				},
   120 		SECTION("\\s*\\[\\s*([^\\s\\]]+)\\s*\\]\\s*") {
   121 					@Override
   122 					public void processLine(LineContext lc, FileContext fc) throws SAXException {
   123 						String name = lc.matcher.group(1);
   124 						fc.outputEndSection(fc.lastSection);
   125 						fc.outputStartSection(name);
   126 						fc.lastSection = name;
   127 					}
   128 
   129 				},
   130 		ENTRY(
   131 				"\\s*([^=\\s]+)\\s*=\\s*\"([^\"]+)\"", // quoted value → include spaces
   132 				"\\s*([^=\\s]+)\\s*=\\s*\"([^\"]+)\"\\s*(;|#)*\\s*(.*)", // quoted value → include spaces | with comment
   133 				"\\s*([^=\\s]+)\\s*=\\s*'([^']+)'", // apostrophed value → include spaces | with comment
   134 				"\\s*([^=\\s]+)\\s*=\\s*'([^']+)'\\s*(;|#)*\\s*(.*)", // apostrophed value → include spaces
   135 				"\\s*([^=\\s]+)\\s*=\\s*(.+)" // unquoted value → strip spaces
   136 		) {
   137 					@Override
   138 					public void processLine(LineContext lc, FileContext fc) throws SAXException {
   139 						String key = lc.matcher.group(1);
   140 						String value = lc.matcher.group(2);
   141 
   142 						if (lc.matcher.groupCount() == 4) {
   143 							String comment = lc.matcher.group(4);
   144 							// TODO: comment → LexicalHandler
   145 							log.log(Level.WARNING, "Comment for entry „{0}“ is: {1}", new Object[]{key, comment});
   146 						}
   147 
   148 						fc.contentHandler.indentation(2);
   149 						fc.contentHandler.textElement(value, null, null, key, null);
   150 						fc.contentHandler.lineBreak();
   151 
   152 					}
   153 
   154 				},;
   155 
   156 		private LINE_TYPE(String... patterns) {
   157 			for (String pattern : patterns) {
   158 				this.patterns.add(Pattern.compile(pattern));
   159 			}
   160 		}
   161 
   162 		private final List<Pattern> patterns = new ArrayList<>();
   163 
   164 		protected boolean processLine(String currentLine, FileContext fileContext) throws SAXException {
   165 			for (Pattern pattern : patterns) {
   166 				Matcher m = pattern.matcher(currentLine);
   167 				if (m.matches()) {
   168 					log.log(Level.FINEST, "Line „{0}“ matches pattern „{1}“", new Object[]{currentLine, pattern});
   169 					processLine(new LineContext(m), fileContext);
   170 					return true;
   171 				}
   172 			}
   173 			return false;
   174 		}
   175 
   176 		public abstract void processLine(LineContext lc, FileContext fc) throws SAXException;
   177 	}
   178 
   179 }