1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.ini4j;
17
18 import org.ini4j.spi.IniFormatter;
19 import org.ini4j.spi.IniHandler;
20 import org.ini4j.spi.IniParser;
21 import org.ini4j.spi.RegBuilder;
22
23 import java.io.File;
24 import java.io.FileNotFoundException;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.InputStreamReader;
29 import java.io.InterruptedIOException;
30 import java.io.OutputStream;
31 import java.io.OutputStreamWriter;
32 import java.io.Reader;
33 import java.io.Writer;
34
35 import java.net.URL;
36
37 public class Reg extends BasicRegistry implements Registry, Persistable, Configurable
38 {
39 private static final long serialVersionUID = -1485602876922985912L;
40 protected static final String DEFAULT_SUFFIX = ".reg";
41 protected static final String TMP_PREFIX = "reg-";
42 private static final int STDERR_BUFF_SIZE = 8192;
43 private static final String PROP_OS_NAME = "os.name";
44 private static final boolean WINDOWS = Config.getSystemProperty(PROP_OS_NAME, "Unknown").startsWith("Windows");
45 private static final char CR = '\r';
46 private static final char LF = '\n';
47 private Config _config;
48 private File _file;
49
50 public Reg()
51 {
52 Config cfg = Config.getGlobal().clone();
53
54 cfg.setEscape(false);
55 cfg.setGlobalSection(false);
56 cfg.setEmptyOption(true);
57 cfg.setMultiOption(true);
58 cfg.setStrictOperator(true);
59 cfg.setEmptySection(true);
60 cfg.setPathSeparator(KEY_SEPARATOR);
61 cfg.setFileEncoding(FILE_ENCODING);
62 cfg.setLineSeparator(LINE_SEPARATOR);
63 _config = cfg;
64 }
65
66 public Reg(String registryKey) throws IOException
67 {
68 this();
69 read(registryKey);
70 }
71
72 public Reg(File input) throws IOException, InvalidFileFormatException
73 {
74 this();
75 _file = input;
76 load();
77 }
78
79 public Reg(URL input) throws IOException, InvalidFileFormatException
80 {
81 this();
82 load(input);
83 }
84
85 public Reg(InputStream input) throws IOException, InvalidFileFormatException
86 {
87 this();
88 load(input);
89 }
90
91 public Reg(Reader input) throws IOException, InvalidFileFormatException
92 {
93 this();
94 load(input);
95 }
96
97 public static boolean isWindows()
98 {
99 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 }