001/* 002 * Copyright 2005,2009 Ivan SZKIBA 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ini4j; 017 018import org.ini4j.spi.IniFormatter; 019import org.ini4j.spi.IniHandler; 020import org.ini4j.spi.IniParser; 021import org.ini4j.spi.RegBuilder; 022 023import java.io.File; 024import java.io.FileNotFoundException; 025import java.io.FileOutputStream; 026import java.io.IOException; 027import java.io.InputStream; 028import java.io.InputStreamReader; 029import java.io.InterruptedIOException; 030import java.io.OutputStream; 031import java.io.OutputStreamWriter; 032import java.io.Reader; 033import java.io.Writer; 034 035import java.net.URL; 036 037public class Reg extends BasicRegistry implements Registry, Persistable, Configurable 038{ 039 private static final long serialVersionUID = -1485602876922985912L; 040 protected static final String DEFAULT_SUFFIX = ".reg"; 041 protected static final String TMP_PREFIX = "reg-"; 042 private static final int STDERR_BUFF_SIZE = 8192; 043 private static final String PROP_OS_NAME = "os.name"; 044 private static final boolean WINDOWS = Config.getSystemProperty(PROP_OS_NAME, "Unknown").startsWith("Windows"); 045 private static final char CR = '\r'; 046 private static final char LF = '\n'; 047 private Config _config; 048 private File _file; 049 050 public Reg() 051 { 052 Config cfg = Config.getGlobal().clone(); 053 054 cfg.setEscape(false); 055 cfg.setGlobalSection(false); 056 cfg.setEmptyOption(true); 057 cfg.setMultiOption(true); 058 cfg.setStrictOperator(true); 059 cfg.setEmptySection(true); 060 cfg.setPathSeparator(KEY_SEPARATOR); 061 cfg.setFileEncoding(FILE_ENCODING); 062 cfg.setLineSeparator(LINE_SEPARATOR); 063 _config = cfg; 064 } 065 066 public Reg(String registryKey) throws IOException 067 { 068 this(); 069 read(registryKey); 070 } 071 072 public Reg(File input) throws IOException, InvalidFileFormatException 073 { 074 this(); 075 _file = input; 076 load(); 077 } 078 079 public Reg(URL input) throws IOException, InvalidFileFormatException 080 { 081 this(); 082 load(input); 083 } 084 085 public Reg(InputStream input) throws IOException, InvalidFileFormatException 086 { 087 this(); 088 load(input); 089 } 090 091 public Reg(Reader input) throws IOException, InvalidFileFormatException 092 { 093 this(); 094 load(input); 095 } 096 097 public static boolean isWindows() 098 { 099 return WINDOWS; 100 } 101 102 @Override public Config getConfig() 103 { 104 return _config; 105 } 106 107 public void setConfig(Config value) 108 { 109 _config = value; 110 } 111 112 @Override public File getFile() 113 { 114 return _file; 115 } 116 117 @Override public void setFile(File value) 118 { 119 _file = value; 120 } 121 122 @Override public void load() throws IOException, InvalidFileFormatException 123 { 124 if (_file == null) 125 { 126 throw new FileNotFoundException(); 127 } 128 129 load(_file); 130 } 131 132 @Override public void load(InputStream input) throws IOException, InvalidFileFormatException 133 { 134 load(new InputStreamReader(input, getConfig().getFileEncoding())); 135 } 136 137 @Override public void load(URL input) throws IOException, InvalidFileFormatException 138 { 139 load(new InputStreamReader(input.openStream(), getConfig().getFileEncoding())); 140 } 141 142 @Override public void load(Reader input) throws IOException, InvalidFileFormatException 143 { 144 int newline = 2; 145 StringBuilder buff = new StringBuilder(); 146 147 for (int c = input.read(); c != -1; c = input.read()) 148 { 149 if (c == LF) 150 { 151 newline--; 152 if (newline == 0) 153 { 154 break; 155 } 156 } 157 else if ((c != CR) && (newline != 1)) 158 { 159 buff.append((char) c); 160 } 161 } 162 163 if (buff.length() == 0) 164 { 165 throw new InvalidFileFormatException("Missing version header"); 166 } 167 168 if (!buff.toString().equals(getVersion())) 169 { 170 throw new InvalidFileFormatException("Unsupported version: " + buff.toString()); 171 } 172 173 IniParser.newInstance(getConfig()).parse(input, newBuilder()); 174 } 175 176 @Override public void load(File input) throws IOException, InvalidFileFormatException 177 { 178 load(input.toURI().toURL()); 179 } 180 181 public void read(String registryKey) throws IOException 182 { 183 File tmp = createTempFile(); 184 185 try 186 { 187 regExport(registryKey, tmp); 188 load(tmp); 189 } 190 finally 191 { 192 tmp.delete(); 193 } 194 } 195 196 @Override public void store() throws IOException 197 { 198 if (_file == null) 199 { 200 throw new FileNotFoundException(); 201 } 202 203 store(_file); 204 } 205 206 @Override public void store(OutputStream output) throws IOException 207 { 208 store(new OutputStreamWriter(output, getConfig().getFileEncoding())); 209 } 210 211 @Override public void store(Writer output) throws IOException 212 { 213 output.write(getVersion()); 214 output.write(getConfig().getLineSeparator()); 215 output.write(getConfig().getLineSeparator()); 216 store(IniFormatter.newInstance(output, getConfig())); 217 } 218 219 @Override public void store(File output) throws IOException 220 { 221 OutputStream stream = new FileOutputStream(output); 222 223 store(stream); 224 stream.close(); 225 } 226 227 public void write() throws IOException 228 { 229 File tmp = createTempFile(); 230 231 try 232 { 233 store(tmp); 234 regImport(tmp); 235 } 236 finally 237 { 238 tmp.delete(); 239 } 240 } 241 242 protected IniHandler newBuilder() 243 { 244 return RegBuilder.newInstance(this); 245 } 246 247 @Override boolean isTreeMode() 248 { 249 return getConfig().isTree(); 250 } 251 252 @Override char getPathSeparator() 253 { 254 return getConfig().getPathSeparator(); 255 } 256 257 @Override boolean isPropertyFirstUpper() 258 { 259 return getConfig().isPropertyFirstUpper(); 260 } 261 262 void exec(String[] args) throws IOException 263 { 264 Process proc = Runtime.getRuntime().exec(args); 265 266 try 267 { 268 int status = proc.waitFor(); 269 270 if (status != 0) 271 { 272 Reader in = new InputStreamReader(proc.getErrorStream()); 273 char[] buff = new char[STDERR_BUFF_SIZE]; 274 int n = in.read(buff); 275 276 in.close(); 277 throw new IOException(new String(buff, 0, n).trim()); 278 } 279 } 280 catch (InterruptedException x) 281 { 282 throw (IOException) (new InterruptedIOException().initCause(x)); 283 } 284 } 285 286 private File createTempFile() throws IOException 287 { 288 File ret = File.createTempFile(TMP_PREFIX, DEFAULT_SUFFIX); 289 290 ret.deleteOnExit(); 291 292 return ret; 293 } 294 295 private void regExport(String registryKey, File file) throws IOException 296 { 297 requireWindows(); 298 exec(new String[] { "cmd", "/c", "reg", "export", registryKey, file.getAbsolutePath() }); 299 } 300 301 private void regImport(File file) throws IOException 302 { 303 requireWindows(); 304 exec(new String[] { "cmd", "/c", "reg", "import", file.getAbsolutePath() }); 305 } 306 307 private void requireWindows() 308 { 309 if (!WINDOWS) 310 { 311 throw new UnsupportedOperationException("Unsupported operating system or runtime environment"); 312 } 313 } 314}