%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.commons.configuration.plist.PropertyListConfiguration |
|
|
1 | /* |
|
2 | * Copyright 2005 The Apache Software Foundation. |
|
3 | * |
|
4 | * Licensed under the Apache License, Version 2.0 (the "License") |
|
5 | * you may not use this file except in compliance with the License. |
|
6 | * You may obtain a copy of the License at |
|
7 | * |
|
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 | * |
|
10 | * Unless required by applicable law or agreed to in writing, software |
|
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 | * See the License for the specific language governing permissions and |
|
14 | * limitations under the License. |
|
15 | */ |
|
16 | ||
17 | package org.apache.commons.configuration.plist; |
|
18 | ||
19 | import java.io.File; |
|
20 | import java.io.PrintWriter; |
|
21 | import java.io.Reader; |
|
22 | import java.io.Writer; |
|
23 | import java.net.URL; |
|
24 | import java.util.ArrayList; |
|
25 | import java.util.Iterator; |
|
26 | import java.util.List; |
|
27 | import java.util.Map; |
|
28 | ||
29 | import org.apache.commons.codec.binary.Hex; |
|
30 | import org.apache.commons.configuration.AbstractHierarchicalFileConfiguration; |
|
31 | import org.apache.commons.configuration.Configuration; |
|
32 | import org.apache.commons.configuration.ConfigurationException; |
|
33 | import org.apache.commons.configuration.HierarchicalConfiguration; |
|
34 | import org.apache.commons.configuration.MapConfiguration; |
|
35 | import org.apache.commons.lang.StringUtils; |
|
36 | ||
37 | /** |
|
38 | * NeXT / OpenStep style configuration. |
|
39 | * (http://developer.apple.com/documentation/Cocoa/Conceptual/PropertyLists/Concepts/OldStylePListsConcept.html) |
|
40 | * |
|
41 | * <p>Example:</p> |
|
42 | * <pre> |
|
43 | * { |
|
44 | * foo = "bar"; |
|
45 | * |
|
46 | * array = ( value1, value2, value3 ); |
|
47 | * |
|
48 | * data = <4f3e0145ab>; |
|
49 | * |
|
50 | * nested = |
|
51 | * { |
|
52 | * key1 = value1; |
|
53 | * key2 = value; |
|
54 | * nested = |
|
55 | * { |
|
56 | * foo = bar |
|
57 | * } |
|
58 | * } |
|
59 | * } |
|
60 | * </pre> |
|
61 | * |
|
62 | * @since 1.2 |
|
63 | * |
|
64 | * @author Emmanuel Bourg |
|
65 | * @version $Revision$, $Date: 2005-12-06 04:10:27 +0100 (Tue, 06 Dec 2005) $ |
|
66 | */ |
|
67 | public class PropertyListConfiguration extends AbstractHierarchicalFileConfiguration |
|
68 | { |
|
69 | /** Size of the indentation for the generated file. */ |
|
70 | private static final int INDENT_SIZE = 4; |
|
71 | ||
72 | /** |
|
73 | * Creates an empty PropertyListConfiguration object which can be |
|
74 | * used to synthesize a new plist file by adding values and |
|
75 | * then saving(). |
|
76 | 126 | */ |
77 | public PropertyListConfiguration() |
|
78 | 252 | { |
79 | 252 | } |
80 | ||
81 | /** |
|
82 | * Creates and loads the property list from the specified file. |
|
83 | * |
|
84 | * @param fileName The name of the plist file to load. |
|
85 | * @throws ConfigurationException Error while loading the plist file |
|
86 | */ |
|
87 | public PropertyListConfiguration(String fileName) throws ConfigurationException |
|
88 | { |
|
89 | 0 | super(fileName); |
90 | 0 | } |
91 | ||
92 | /** |
|
93 | * Creates and loads the property list from the specified file. |
|
94 | * |
|
95 | * @param file The plist file to load. |
|
96 | * @throws ConfigurationException Error while loading the plist file |
|
97 | 1 | */ |
98 | 1 | public PropertyListConfiguration(File file) throws ConfigurationException |
99 | { |
|
100 | 2 | super(file); |
101 | 2 | } |
102 | ||
103 | /** |
|
104 | * Creates and loads the property list from the specified URL. |
|
105 | * |
|
106 | * @param url The location of the plist file to load. |
|
107 | * @throws ConfigurationException Error while loading the plist file |
|
108 | */ |
|
109 | public PropertyListConfiguration(URL url) throws ConfigurationException |
|
110 | { |
|
111 | 0 | super(url); |
112 | 0 | } |
113 | 15 | |
114 | public void load(Reader in) throws ConfigurationException |
|
115 | { |
|
116 | 30 | PropertyListParser parser = new PropertyListParser(in); |
117 | 15 | try |
118 | 14 | { |
119 | 14 | |
120 | 30 | HierarchicalConfiguration config = parser.parse(); |
121 | 28 | setRoot(config.getRoot()); |
122 | 29 | } |
123 | catch (ParseException e) |
|
124 | 14 | { |
125 | 2 | throw new ConfigurationException(e); |
126 | } |
|
127 | 28 | } |
128 | 1 | |
129 | 1 | public void save(Writer out) throws ConfigurationException |
130 | 1 | { |
131 | 3 | PrintWriter writer = new PrintWriter(out); |
132 | 2 | printNode(writer, 0, getRoot()); |
133 | 2 | writer.flush(); |
134 | 2 | } |
135 | ||
136 | /** |
|
137 | * Append a node to the writer, indented according to a specific level. |
|
138 | 22 | */ |
139 | private void printNode(PrintWriter out, int indentLevel, Node node) |
|
140 | 22 | { |
141 | 44 | String padding = StringUtils.repeat(" ", indentLevel * INDENT_SIZE); |
142 | 19 | |
143 | 44 | if (node.getName() != null) |
144 | { |
|
145 | 38 | out.print(padding + quoteString(node.getName()) + " = "); |
146 | 22 | } |
147 | 22 | |
148 | 64 | // get all non trivial nodes |
149 | 44 | List children = new ArrayList(node.getChildren()); |
150 | 64 | Iterator it = children.iterator(); |
151 | 148 | while (it.hasNext()) |
152 | { |
|
153 | 41 | Node child = (Node) it.next(); |
154 | 40 | if (child.getValue() == null && (child.getChildren() == class="keyword">null || child.getChildren().isEmpty())) |
155 | { |
|
156 | 2 | it.remove(); |
157 | 22 | } |
158 | } |
|
159 | ||
160 | 51 | if (!children.isEmpty()) |
161 | { |
|
162 | 6 | // skip a line, except for the root dictionary |
163 | 14 | if (indentLevel > 0) |
164 | { |
|
165 | 19 | out.println(); |
166 | } |
|
167 | ||
168 | 21 | out.println(padding + "{"); |
169 | 33 | |
170 | // display the children |
|
171 | 33 | it = children.iterator(); |
172 | 66 | while (it.hasNext()) |
173 | 19 | { |
174 | 38 | Node child = (Node) it.next(); |
175 | ||
176 | 57 | printNode(out, indentLevel + 1, child); |
177 | 19 | |
178 | // add a semi colon for elements that are not dictionaries |
|
179 | 53 | Object value = child.getValue(); |
180 | 38 | if (value != null && !(value instanceof Map) && !(value instanceof Configuration)) |
181 | { |
|
182 | 30 | out.println(";"); |
183 | 19 | } |
184 | ||
185 | 6 | // skip a line after arrays and dictionaries |
186 | 38 | if (it.hasNext() && (value == null || value instanceof List)) |
187 | { |
|
188 | 12 | out.println(); |
189 | 7 | } |
190 | } |
|
191 | ||
192 | 21 | out.print(padding + "}"); |
193 | ||
194 | 4 | // line feed if the dictionary is not in an array |
195 | 14 | if (node.getParent() != null) |
196 | { |
|
197 | 8 | out.println(); |
198 | } |
|
199 | } |
|
200 | 15 | else |
201 | 15 | { |
202 | // display the leaf value |
|
203 | 52 | Object value = node.getValue(); |
204 | 30 | printValue(out, indentLevel, value); |
205 | } |
|
206 | 44 | } |
207 | ||
208 | /** |
|
209 | * Append a value to the writer, indented according to a specific level. |
|
210 | 26 | */ |
211 | private void printValue(PrintWriter out, int indentLevel, Object value) |
|
212 | 26 | { |
213 | 52 | String padding = StringUtils.repeat(" ", indentLevel * INDENT_SIZE); |
214 | 6 | |
215 | 58 | if (value instanceof List) |
216 | 23 | { |
217 | 12 | out.print("( "); |
218 | 23 | Iterator it = ((List) value).iterator(); |
219 | 57 | while (it.hasNext()) |
220 | { |
|
221 | 28 | printValue(out, indentLevel + 1, it.next()); |
222 | 22 | if (it.hasNext()) |
223 | { |
|
224 | 18 | out.print(", "); |
225 | } |
|
226 | 20 | } |
227 | 12 | out.print(" )"); |
228 | 2 | } |
229 | 40 | else if (value instanceof HierarchicalConfiguration) |
230 | 18 | { |
231 | 4 | printNode(out, indentLevel, ((HierarchicalConfiguration) value).getRoot()); |
232 | } |
|
233 | 36 | else if (value instanceof Configuration) |
234 | { |
|
235 | // display a flat Configuration as a dictionary |
|
236 | 0 | out.println(); |
237 | 0 | out.println(padding + "{"); |
238 | ||
239 | 0 | Configuration config = (Configuration) value; |
240 | 0 | Iterator it = config.getKeys(); |
241 | 0 | while (it.hasNext()) |
242 | { |
|
243 | 0 | String key = (String) it.next(); |
244 | 0 | Node node = new Node(key); |
245 | 0 | node.setValue(config.getProperty(key)); |
246 | ||
247 | 0 | printNode(out, indentLevel + 1, node); |
248 | 0 | out.println(";"); |
249 | 18 | } |
250 | 0 | out.println(padding + "}"); |
251 | } |
|
252 | 36 | else if (value instanceof Map) |
253 | { |
|
254 | // display a Map as a dictionary |
|
255 | 18 | Map map = (Map) value; |
256 | 0 | printValue(out, indentLevel, new MapConfiguration(map)); |
257 | 2 | } |
258 | 36 | else if (value instanceof byte[]) |
259 | 16 | { |
260 | 4 | out.print("<" + new String(Hex.encodeHex((byte[]) value)) + ">"); |
261 | 16 | } |
262 | 32 | else if (value != null) |
263 | 26 | { |
264 | 32 | out.print(quoteString(String.valueOf(value))); |
265 | } |
|
266 | 52 | } |
267 | ||
268 | /** |
|
269 | * Quote the specified string if necessary, that's if the string contains: |
|
270 | * <ul> |
|
271 | * <li>a space character (' ', '\t', '\r', '\n')</li> |
|
272 | * <li>a quote '"'</li> |
|
273 | * <li>special characters in plist files ('(', ')', '{', '}', '=', ';', ',')</li> |
|
274 | * </ul> |
|
275 | * Quotes within the string are escaped. |
|
276 | * |
|
277 | * <p>Examples:</p> |
|
278 | * <ul> |
|
279 | * <li>abcd -> abcd</li> |
|
280 | * <li>ab cd -> "ab cd"</li> |
|
281 | * <li>foo"bar -> "foo\"bar"</li> |
|
282 | * <li>foo;bar -> "foo;bar"</li> |
|
283 | * </ul> |
|
284 | 40 | */ |
285 | String quoteString(String s) |
|
286 | 1 | { |
287 | 80 | if (s == null) |
288 | { |
|
289 | 41 | return null; |
290 | } |
|
291 | ||
292 | 78 | if (s.indexOf(' ') != -1 |
293 | || s.indexOf('\t') != -1 |
|
294 | || s.indexOf('\r') != -1 |
|
295 | || s.indexOf('\n') != -1 |
|
296 | || s.indexOf('"') != -1 |
|
297 | || s.indexOf('(') != -1 |
|
298 | || s.indexOf(')') != -1 |
|
299 | || s.indexOf('{') != -1 |
|
300 | || s.indexOf('}') != -1 |
|
301 | || s.indexOf('=') != -1 |
|
302 | 5 | || s.indexOf(',') != -1 |
303 | 5 | || s.indexOf(';') != -1) |
304 | { |
|
305 | 10 | s = StringUtils.replace(s, "\"", "\\\""); |
306 | 49 | s = "\"" + s + "\""; |
307 | } |
|
308 | ||
309 | 78 | return s; |
310 | } |
|
311 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |