Source Code Cross Referenced for EditableProperties.java in  » IDE-Netbeans » project.ant » org » netbeans » spi » project » support » ant » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » project.ant » org.netbeans.spi.project.support.ant 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003:         *
004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005:         *
006:         * The contents of this file are subject to the terms of either the GNU
007:         * General Public License Version 2 only ("GPL") or the Common
008:         * Development and Distribution License("CDDL") (collectively, the
009:         * "License"). You may not use this file except in compliance with the
010:         * License. You can obtain a copy of the License at
011:         * http://www.netbeans.org/cddl-gplv2.html
012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013:         * specific language governing permissions and limitations under the
014:         * License.  When distributing the software, include this License Header
015:         * Notice in each file and include the License file at
016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
017:         * particular file as subject to the "Classpath" exception as provided
018:         * by Sun in the GPL Version 2 section of the License file that
019:         * accompanied this code. If applicable, add the following below the
020:         * License Header, with the fields enclosed by brackets [] replaced by
021:         * your own identifying information:
022:         * "Portions Copyrighted [year] [name of copyright owner]"
023:         *
024:         * Contributor(s):
025:         *
026:         * The Original Software is NetBeans. The Initial Developer of the Original
027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028:         * Microsystems, Inc. All Rights Reserved.
029:         *
030:         * If you wish your version of this file to be governed by only the CDDL
031:         * or only the GPL Version 2, indicate your decision by adding
032:         * "[Contributor] elects to include this software in this distribution
033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
034:         * single choice of license, a recipient has the option to distribute
035:         * your version of this file under either the CDDL, the GPL Version 2 or
036:         * to extend the choice of license to its licensees as provided above.
037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
038:         * Version 2 license, then the option applies only if the new code is
039:         * made subject to such option by the copyright holder.
040:         */
041:
042:        package org.netbeans.spi.project.support.ant;
043:
044:        import java.io.BufferedReader;
045:        import java.io.BufferedWriter;
046:        import java.io.IOException;
047:        import java.io.InputStream;
048:        import java.io.InputStreamReader;
049:        import java.io.OutputStream;
050:        import java.io.OutputStreamWriter;
051:        import java.util.AbstractMap;
052:        import java.util.AbstractSet;
053:        import java.util.ArrayList;
054:        import java.util.Arrays;
055:        import java.util.HashMap;
056:        import java.util.Iterator;
057:        import java.util.LinkedList;
058:        import java.util.List;
059:        import java.util.ListIterator;
060:        import java.util.Map;
061:        import java.util.NoSuchElementException;
062:        import java.util.Set;
063:
064:        // XXX: consider adding getInitialComment() and setInitialComment() methods
065:        // (useful e.g. for GeneratedFilesHelper)
066:
067:        /**
068:         * Similar to {@link java.util.Properties} but designed to retain additional
069:         * information needed for safe hand-editing.
070:         * Useful for various <samp>*.properties</samp> in a project:
071:         * <ol>
072:         * <li>Can associate comments with particular entries.
073:         * <li>Order of entries preserved during modifications whenever possible.
074:         * <li>VCS-friendly: lines which are not semantically modified are not textually modified.
075:         * <li>Can automatically insert line breaks in new or modified values at positions
076:         *     that are likely to be semantically meaningful, e.g. between path components
077:         * </ol>
078:         * The file format (including encoding etc.) is compatible with the regular JRE implementation.
079:         * Only (non-null) String is supported for keys and values.
080:         * This class is not thread-safe; use only from a single thread, or use {@link java.util.Collections#synchronizedMap}.
081:         * @author Jesse Glick, David Konecny
082:         */
083:        public final class EditableProperties extends
084:                AbstractMap<String, String> implements  Cloneable {
085:
086:            /** List of Item instances as read from the properties file. Order is important.
087:             * Saving properties will save then in this order. */
088:            private final LinkedList<Item> items;
089:
090:            /** Map of [property key, Item instance] for faster access. */
091:            private final Map<String, Item> itemIndex;
092:
093:            private final boolean alphabetize;
094:
095:            private static final String keyValueSeparators = "=: \t\r\n\f";
096:
097:            private static final String strictKeyValueSeparators = "=:";
098:
099:            private static final String whiteSpaceChars = " \t\r\n\f";
100:
101:            private static final String commentChars = "#!";
102:
103:            private static final String INDENT = "    ";
104:
105:            // parse states:
106:            private static final int WAITING_FOR_KEY_VALUE = 1;
107:            private static final int READING_KEY_VALUE = 2;
108:
109:            /**
110:             * Creates empty instance whose items will not be alphabetized.
111:             */
112:            public EditableProperties() {
113:                this (/* mentioned in #64174 - documented default */false);
114:            }
115:
116:            /**
117:             * Creates empty instance.
118:             * @param alphabetize alphabetize new items according to key or not
119:             */
120:            public EditableProperties(boolean alphabetize) {
121:                this .alphabetize = alphabetize;
122:                items = new LinkedList<Item>();
123:                itemIndex = new HashMap<String, Item>();
124:            }
125:
126:            /**
127:             * Creates instance from an existing map. No comments will be defined.
128:             * Any order from the existing map will be retained,
129:             * and further additions will not be alphabetized.
130:             * @param map a map from String to String
131:             */
132:            public EditableProperties(Map<String, String> map) {
133:                this (false);
134:                putAll(map);
135:            }
136:
137:            /**
138:             * Creates new instance from an existing one.
139:             * @param ep an instance of EditableProperties
140:             */
141:            private EditableProperties(EditableProperties ep) {
142:                // #64174: use a simple deep copy for speed
143:                alphabetize = ep.alphabetize;
144:                items = new LinkedList<Item>();
145:                itemIndex = new HashMap<String, Item>(
146:                        ep.items.size() * 4 / 3 + 1);
147:                for (Item _i : ep.items) {
148:                    Item i = (Item) _i.clone();
149:                    items.add(i);
150:                    itemIndex.put(i.getKey(), i);
151:                }
152:            }
153:
154:            /**
155:             * Returns a set view of the mappings ordered according to their file 
156:             * position.  Each element in this set is a Map.Entry. See
157:             * {@link AbstractMap#entrySet} for more details.
158:             * @return set with Map.Entry instances.
159:             */
160:            public Set<Map.Entry<String, String>> entrySet() {
161:                return new SetImpl(this );
162:            }
163:
164:            /**
165:             * Load properties from a stream.
166:             * @param stream an input stream
167:             * @throws IOException if the contents are malformed or the stream could not be read
168:             */
169:            public void load(InputStream stream) throws IOException {
170:                int state = WAITING_FOR_KEY_VALUE;
171:                BufferedReader input = new BufferedReader(
172:                        new InputStreamReader(stream, "ISO-8859-1"));
173:                List<String> tempList = new LinkedList<String>();
174:                String line;
175:                int commentLinesCount = 0;
176:                // Read block of lines and create instance of Item for each.
177:                // Separator is: either empty line or valid end of proeprty declaration
178:                while (null != (line = input.readLine())) {
179:                    tempList.add(line);
180:                    boolean empty = isEmpty(line);
181:                    boolean comment = isComment(line);
182:                    if (state == WAITING_FOR_KEY_VALUE) {
183:                        if (empty) {
184:                            // empty line: create Item without any key
185:                            createNonKeyItem(tempList);
186:                            commentLinesCount = 0;
187:                        } else {
188:                            if (comment) {
189:                                commentLinesCount++;
190:                            } else {
191:                                state = READING_KEY_VALUE;
192:                            }
193:                        }
194:                    }
195:                    if (state == READING_KEY_VALUE && !isContinue(line)) {
196:                        // valid end of property declaration: create Item for it
197:                        createKeyItem(tempList, commentLinesCount);
198:                        state = WAITING_FOR_KEY_VALUE;
199:                        commentLinesCount = 0;
200:                    }
201:                }
202:                if (tempList.size() > 0) {
203:                    if (state == READING_KEY_VALUE) {
204:                        // value was not ended correctly? ignore.
205:                        createKeyItem(tempList, commentLinesCount);
206:                    } else {
207:                        createNonKeyItem(tempList);
208:                    }
209:                }
210:            }
211:
212:            /**
213:             * Store properties to a stream.
214:             * @param stream an output stream
215:             * @throws IOException if the stream could not be written to
216:             */
217:            public void store(OutputStream stream) throws IOException {
218:                boolean previousLineWasEmpty = true;
219:                BufferedWriter output = new BufferedWriter(
220:                        new OutputStreamWriter(stream, "ISO-8859-1"));
221:                for (Item item : items) {
222:                    if (item.isSeparate() && !previousLineWasEmpty) {
223:                        output.newLine();
224:                    }
225:                    String line = null;
226:                    Iterator<String> it = item.getRawData().iterator();
227:                    while (it.hasNext()) {
228:                        line = it.next();
229:                        output.write(line);
230:                        output.newLine();
231:                    }
232:                    if (line != null) {
233:                        previousLineWasEmpty = isEmpty(line);
234:                    }
235:                }
236:                output.flush();
237:            }
238:
239:            @Override
240:            public String put(String key, String value) {
241:                if (key == null || value == null) {
242:                    throw new NullPointerException();
243:                }
244:                Item item = itemIndex.get(key);
245:                String result = null;
246:                if (item != null) {
247:                    result = item.getValue();
248:                    item.setValue(value);
249:                } else {
250:                    item = new Item(key, value);
251:                    addItem(item, alphabetize);
252:                }
253:                return result;
254:            }
255:
256:            /**
257:             * Convenience method to get a property as a string.
258:             * Same as {@link #get}; only here because of pre-generic code.
259:             * @param key a property name; cannot be null nor empty
260:             * @return the property value, or null if it was not defined
261:             */
262:            public String getProperty(String key) {
263:                return get(key);
264:            }
265:
266:            /**
267:             * Convenience method to set a property.
268:             * Same as {@link #put}; only here because of pre-generic code.
269:             * @param key a property name; cannot be null nor empty
270:             * @param value the desired value; cannot be null
271:             * @return previous value of the property or null if there was not any
272:             */
273:            public String setProperty(String key, String value) {
274:                return put(key, value);
275:            }
276:
277:            /**
278:             * Sets a property to a value broken into segments for readability.
279:             * Same behavior as {@link #setProperty(String,String)} with the difference that each item
280:             * will be stored on its own line of text. {@link #getProperty} will simply concatenate
281:             * all the items into one string, so generally separators
282:             * (such as <samp>:</samp> for path-like properties) must be included in
283:             * the items (for example, at the end of all but the last item).
284:             * @param key a property name; cannot be null nor empty
285:             * @param value the desired value; cannot be null; can be empty array
286:             * @return previous value of the property or null if there was not any
287:             */
288:            public String setProperty(String key, String[] value) {
289:                String result = get(key);
290:                if (key == null || value == null) {
291:                    throw new NullPointerException();
292:                }
293:                List<String> valueList = Arrays.asList(value);
294:                Item item = itemIndex.get(key);
295:                if (item != null) {
296:                    item.setValue(valueList);
297:                } else {
298:                    addItem(new Item(key, valueList), alphabetize);
299:                }
300:                return result;
301:            }
302:
303:            /**
304:             * Returns comment associated with the property. The comment lines are
305:             * returned as defined in properties file, that is comment delimiter is
306:             * included. Comment for property is defined as: continuous block of lines
307:             * starting with comment delimiter which are followed by property
308:             * declaration (no empty line separator allowed).
309:             * @param key a property name; cannot be null nor empty
310:             * @return array of String lines as specified in properties file; comment
311:             *    delimiter character is included
312:             */
313:            public String[] getComment(String key) {
314:                Item item = itemIndex.get(key);
315:                if (item == null) {
316:                    return new String[0];
317:                }
318:                return item.getComment();
319:            }
320:
321:            /**
322:             * Create comment for the property.
323:             * <p>Note: if a comment includes non-ISO-8859-1 characters, they will be written
324:             * to disk using Unicode escapes (and {@link #getComment} will interpret
325:             * such escapes), but of course they will be unreadable for humans.
326:             * @param key a property name; cannot be null nor empty
327:             * @param comment lines of comment which will be written just above
328:             *    the property; no reformatting; comment lines must start with 
329:             *    comment delimiter; cannot be null; cannot be emty array
330:             * @param separate whether the comment should be separated from previous
331:             *    item by empty line
332:             */
333:            public void setComment(String key, String[] comment,
334:                    boolean separate) {
335:                // XXX: check validity of comment parameter
336:                Item item = itemIndex.get(key);
337:                if (item == null) {
338:                    throw new IllegalArgumentException(
339:                            "Cannot set comment for non-existing property "
340:                                    + key);
341:                }
342:                item.setComment(comment, separate);
343:            }
344:
345:            @Override
346:            public Object clone() {
347:                return cloneProperties();
348:            }
349:
350:            /**
351:             * Create an exact copy of this properties object.
352:             * @return a clone of this object
353:             */
354:            public EditableProperties cloneProperties() {
355:                return new EditableProperties(this );
356:            }
357:
358:            // non-key item is block of empty lines/comment not associated with any property
359:            private void createNonKeyItem(List<String> lines) {
360:                // First check that previous item is not non-key item.
361:                if (!items.isEmpty()) {
362:                    Item item = items.getLast();
363:                    if (item.getKey() == null) {
364:                        // it is non-key item:  merge them
365:                        item.addCommentLines(lines);
366:                        lines.clear();
367:                        return;
368:                    }
369:                }
370:                // create new non-key item
371:                Item item = new Item(lines);
372:                addItem(item, false);
373:                lines.clear();
374:            }
375:
376:            // opposite to non-key item: item with valid property declaration and 
377:            // perhaps some comment lines
378:            private void createKeyItem(List<String> lines, int commentLinesCount) {
379:                Item item = new Item(lines.subList(0, commentLinesCount), lines
380:                        .subList(commentLinesCount, lines.size()));
381:                addItem(item, false);
382:                lines.clear();
383:            }
384:
385:            private void addItem(Item item, boolean sort) {
386:                String key = item.getKey();
387:                if (sort) {
388:                    assert key != null;
389:                    ListIterator<Item> it = items.listIterator();
390:                    while (it.hasNext()) {
391:                        String k = it.next().getKey();
392:                        if (k != null && k.compareToIgnoreCase(key) > 0) {
393:                            it.previous();
394:                            it.add(item);
395:                            itemIndex.put(key, item);
396:                            return;
397:                        }
398:                    }
399:                }
400:                items.add(item);
401:                if (key != null) {
402:                    itemIndex.put(key, item);
403:                }
404:            }
405:
406:            private void removeItem(Item item) {
407:                items.remove(item);
408:                if (item.getKey() != null) {
409:                    itemIndex.remove(item.getKey());
410:                }
411:            }
412:
413:            // does property declaration continue on next line?
414:            private boolean isContinue(String line) {
415:                int index = line.length() - 1;
416:                int slashCount = 0;
417:                while (index >= 0 && line.charAt(index) == '\\') {
418:                    slashCount++;
419:                    index--;
420:                }
421:                // if line ends with odd number of backslash then property definition 
422:                // continues on next line
423:                return (slashCount % 2 != 0);
424:            }
425:
426:            // does line start with comment delimiter? (whitespaces are ignored)
427:            private static boolean isComment(String line) {
428:                line = trimLeft(line);
429:                if (line.length() != 0
430:                        && commentChars.indexOf(line.charAt(0)) != -1) {
431:                    return true;
432:                } else {
433:                    return false;
434:                }
435:            }
436:
437:            // is line empty? (whitespaces are ignored)
438:            private static boolean isEmpty(String line) {
439:                return trimLeft(line).length() == 0;
440:            }
441:
442:            // remove all whitespaces from left
443:            private static String trimLeft(String line) {
444:                int start = 0;
445:                while (start < line.length()) {
446:                    if (whiteSpaceChars.indexOf(line.charAt(start)) == -1) {
447:                        break;
448:                    }
449:                    start++;
450:                }
451:                return line.substring(start);
452:            }
453:
454:            /**
455:             * Representation of one item read from properties file. It can be either
456:             * valid property declaration with associated comment or chunk of empty
457:             * lines or lines with comment which are not associated with any property.
458:             */
459:            private static class Item implements  Cloneable {
460:
461:                /** Lines of comment as read from properties file and as they will be
462:                 * written back to properties file. */
463:                private List<String> commentLines;
464:
465:                /** Lines with property name and value declaration as read from 
466:                 * properties file and as they will be written back to properties file. */
467:                private List<String> keyValueLines;
468:
469:                /** Property key */
470:                private String key;
471:
472:                /** Property value */
473:                private String value;
474:
475:                /** Should this property be separated from previous one by at least
476:                 * one empty line. */
477:                private boolean separate;
478:
479:                // constructor only for cloning
480:                private Item() {
481:                }
482:
483:                /**
484:                 * Create instance which does not have any key and value - just 
485:                 * some empty or comment lines. This item is READ-ONLY.
486:                 */
487:                public Item(List<String> commentLines) {
488:                    this .commentLines = new ArrayList<String>(commentLines);
489:                }
490:
491:                /**
492:                 * Create instance from the lines of comment and property declaration.
493:                 * Property name and value will be split.
494:                 */
495:                public Item(List<String> commentLines,
496:                        List<String> keyValueLines) {
497:                    this .commentLines = new ArrayList<String>(commentLines);
498:                    this .keyValueLines = new ArrayList<String>(keyValueLines);
499:                    parse(keyValueLines);
500:                }
501:
502:                /**
503:                 * Create new instance with key and value.
504:                 */
505:                public Item(String key, String value) {
506:                    this .key = key;
507:                    this .value = value;
508:                }
509:
510:                /**
511:                 * Create new instance with key and value.
512:                 */
513:                public Item(String key, List<String> value) {
514:                    this .key = key;
515:                    setValue(value);
516:                }
517:
518:                // backdoor for merging non-key items
519:                void addCommentLines(List<String> lines) {
520:                    assert key == null;
521:                    commentLines.addAll(lines);
522:                }
523:
524:                public String[] getComment() {
525:                    String[] res = new String[commentLines.size()];
526:                    for (int i = 0; i < res.length; i++) {
527:                        // #60249: the comment might have Unicode chars in escapes.
528:                        res[i] = decodeUnicode(commentLines.get(i));
529:                    }
530:                    return res;
531:                }
532:
533:                public void setComment(String[] commentLines, boolean separate) {
534:                    this .separate = separate;
535:                    this .commentLines = new ArrayList<String>(
536:                            commentLines.length);
537:                    for (int i = 0; i < commentLines.length; i++) {
538:                        // #60249 again - write only ISO-8859-1.
539:                        this .commentLines.add(encodeUnicode(commentLines[i]));
540:                    }
541:                }
542:
543:                public String getKey() {
544:                    return key;
545:                }
546:
547:                public String getValue() {
548:                    return value;
549:                }
550:
551:                public void setValue(String value) {
552:                    this .value = value;
553:                    keyValueLines = null;
554:                }
555:
556:                public void setValue(List<String> value) {
557:                    StringBuffer val = new StringBuffer();
558:                    List<String> l = new ArrayList<String>();
559:                    if (!value.isEmpty()) {
560:                        l.add(encode(key, true) + "=\\"); // NOI18N
561:                        Iterator<String> it = value.iterator();
562:                        while (it.hasNext()) {
563:                            String s = it.next();
564:                            val.append(s);
565:                            s = encode(s, false);
566:                            l
567:                                    .add(it.hasNext() ? INDENT + s + '\\'
568:                                            : INDENT + s); // NOI18N
569:                        }
570:                    } else {
571:                        // #45061: for no vals, use just "prop="
572:                        l.add(encode(key, true) + '='); // NOI18N
573:                    }
574:                    this .value = val.toString();
575:                    keyValueLines = l;
576:                }
577:
578:                public boolean isSeparate() {
579:                    return separate;
580:                }
581:
582:                /**
583:                 * Returns persistent image of this property.
584:                 */
585:                public List<String> getRawData() {
586:                    List<String> l = new ArrayList<String>();
587:                    if (commentLines != null) {
588:                        l.addAll(commentLines);
589:                    }
590:                    if (keyValueLines == null) {
591:                        keyValueLines = new ArrayList<String>();
592:                        if (key != null && value != null) {
593:                            keyValueLines.add(encode(key, true) + "="
594:                                    + encode(value, false));
595:                        }
596:                    }
597:                    l.addAll(keyValueLines);
598:                    return l;
599:                }
600:
601:                private void parse(List<String> keyValueLines) {
602:                    // merge lines into one:
603:                    String line = mergeLines(keyValueLines);
604:                    // split key and value
605:                    splitKeyValue(line);
606:                }
607:
608:                private String mergeLines(List<String> lines) {
609:                    String line = ""; // XXX use StringBuilder instead
610:                    Iterator<String> it = lines.iterator();
611:                    while (it.hasNext()) {
612:                        String l = trimLeft(it.next());
613:                        // if this is not the last line then remove last backslash
614:                        if (it.hasNext()) {
615:                            assert l.endsWith("\\") : lines;
616:                            l = l.substring(0, l.length() - 1);
617:                        }
618:                        line += l;
619:                    }
620:                    return line;
621:                }
622:
623:                private void splitKeyValue(String line) {
624:                    int separatorIndex = 0;
625:                    while (separatorIndex < line.length()) {
626:                        char ch = line.charAt(separatorIndex);
627:                        if (ch == '\\') {
628:                            // ignore next one character
629:                            separatorIndex++;
630:                        } else {
631:                            if (keyValueSeparators.indexOf(ch) != -1) {
632:                                break;
633:                            }
634:                        }
635:                        separatorIndex++;
636:                    }
637:                    key = decode(line.substring(0, separatorIndex));
638:                    line = trimLeft(line.substring(separatorIndex));
639:                    if (line.length() == 0) {
640:                        value = "";
641:                        return;
642:                    }
643:                    if (strictKeyValueSeparators.indexOf(line.charAt(0)) != -1) {
644:                        line = trimLeft(line.substring(1));
645:                    }
646:                    value = decode(line);
647:                }
648:
649:                private static String decode(String input) {
650:                    char ch;
651:                    int len = input.length();
652:                    StringBuffer output = new StringBuffer(len);
653:                    for (int x = 0; x < len; x++) {
654:                        ch = input.charAt(x);
655:                        if (ch != '\\') {
656:                            output.append(ch);
657:                            continue;
658:                        }
659:                        x++;
660:                        if (x == len) {
661:                            // backslash at the end? syntax error: ignore it
662:                            continue;
663:                        }
664:                        ch = input.charAt(x);
665:                        if (ch == 'u') {
666:                            if (x + 5 > len) {
667:                                // unicode character not finished? syntax error: ignore
668:                                output.append(input.substring(x - 1));
669:                                x += 4;
670:                                continue;
671:                            }
672:                            String val = input.substring(x + 1, x + 5);
673:                            try {
674:                                output.append((char) Integer.parseInt(val, 16));
675:                            } catch (NumberFormatException e) {
676:                                // #46234: handle gracefully
677:                                output.append(input.substring(x - 1, x + 5));
678:                            }
679:                            x += 4;
680:                        } else {
681:                            if (ch == 't')
682:                                ch = '\t';
683:                            else if (ch == 'r')
684:                                ch = '\r';
685:                            else if (ch == 'n')
686:                                ch = '\n';
687:                            else if (ch == 'f')
688:                                ch = '\f';
689:                            output.append(ch);
690:                        }
691:                    }
692:                    return output.toString();
693:                }
694:
695:                private static String encode(String input, boolean escapeSpace) {
696:                    int len = input.length();
697:                    StringBuffer output = new StringBuffer(len * 2);
698:
699:                    for (int x = 0; x < len; x++) {
700:                        char ch = input.charAt(x);
701:                        switch (ch) {
702:                        case ' ':
703:                            if (x == 0 || escapeSpace) {
704:                                output.append('\\');
705:                            }
706:                            output.append(' ');
707:                            break;
708:                        case '\\':
709:                            output.append("\\\\");
710:                            break;
711:                        case '\t':
712:                            output.append("\\t");
713:                            break;
714:                        case '\n':
715:                            output.append("\\n");
716:                            break;
717:                        case '\r':
718:                            output.append("\\r");
719:                            break;
720:                        case '\f':
721:                            output.append("\\f");
722:                            break;
723:                        default:
724:                            if ((ch < 0x0020) || (ch > 0x007e)) {
725:                                output.append("\\u");
726:                                String hex = Integer.toHexString(ch);
727:                                for (int i = 0; i < 4 - hex.length(); i++) {
728:                                    output.append('0');
729:                                }
730:                                output.append(hex);
731:                            } else {
732:                                output.append(ch);
733:                            }
734:                        }
735:                    }
736:                    return output.toString();
737:                }
738:
739:                private static String decodeUnicode(String input) {
740:                    char ch;
741:                    int len = input.length();
742:                    StringBuffer output = new StringBuffer(len);
743:                    for (int x = 0; x < len; x++) {
744:                        ch = input.charAt(x);
745:                        if (ch != '\\') {
746:                            output.append(ch);
747:                            continue;
748:                        }
749:                        x++;
750:                        if (x == len) {
751:                            // backslash at the end? syntax error: ignore it
752:                            continue;
753:                        }
754:                        ch = input.charAt(x);
755:                        if (ch == 'u') {
756:                            if (x + 5 > len) {
757:                                // unicode character not finished? syntax error: ignore
758:                                output.append(input.substring(x - 1));
759:                                x += 4;
760:                                continue;
761:                            }
762:                            String val = input.substring(x + 1, x + 5);
763:                            try {
764:                                output.append((char) Integer.parseInt(val, 16));
765:                            } catch (NumberFormatException e) {
766:                                // #46234: handle gracefully
767:                                output.append(input.substring(x - 1, x + 5));
768:                            }
769:                            x += 4;
770:                        } else {
771:                            output.append(ch);
772:                        }
773:                    }
774:                    return output.toString();
775:                }
776:
777:                private static String encodeUnicode(String input) {
778:                    int len = input.length();
779:                    StringBuffer output = new StringBuffer(len * 2);
780:                    for (int x = 0; x < len; x++) {
781:                        char ch = input.charAt(x);
782:                        if ((ch < 0x0020) || (ch > 0x007e)) {
783:                            output.append("\\u"); // NOI18N
784:                            String hex = Integer.toHexString(ch);
785:                            for (int i = 0; i < 4 - hex.length(); i++) {
786:                                output.append('0');
787:                            }
788:                            output.append(hex);
789:                        } else {
790:                            output.append(ch);
791:                        }
792:                    }
793:                    return output.toString();
794:                }
795:
796:                @Override
797:                public Object clone() {
798:                    Item item = new Item();
799:                    if (keyValueLines != null) {
800:                        item.keyValueLines = new ArrayList<String>(
801:                                keyValueLines);
802:                    }
803:                    if (commentLines != null) {
804:                        item.commentLines = new ArrayList<String>(commentLines);
805:                    }
806:                    item.key = key;
807:                    item.value = value;
808:                    item.separate = separate;
809:                    return item;
810:                }
811:
812:            }
813:
814:            private static class SetImpl extends
815:                    AbstractSet<Map.Entry<String, String>> {
816:
817:                private EditableProperties props;
818:
819:                public SetImpl(EditableProperties props) {
820:                    this .props = props;
821:                }
822:
823:                public Iterator<Map.Entry<String, String>> iterator() {
824:                    return new IteratorImpl(props);
825:                }
826:
827:                public int size() {
828:                    return props.items.size();
829:                }
830:
831:            }
832:
833:            private static class IteratorImpl implements 
834:                    Iterator<Map.Entry<String, String>> {
835:
836:                private final EditableProperties props;
837:                private ListIterator<Item> delegate;
838:
839:                public IteratorImpl(EditableProperties props) {
840:                    this .props = props;
841:                    delegate = props.items.listIterator();
842:                }
843:
844:                public boolean hasNext() {
845:                    return findNext() != null;
846:                }
847:
848:                public Map.Entry<String, String> next() {
849:                    Item item = findNext();
850:                    if (item == null) {
851:                        throw new NoSuchElementException();
852:                    }
853:                    delegate.next();
854:                    return new MapEntryImpl(item);
855:                }
856:
857:                public void remove() {
858:                    delegate.previous();
859:                    Item item = findNext();
860:                    if (item == null) {
861:                        throw new IllegalStateException();
862:                    }
863:                    int index = delegate.nextIndex();
864:                    props.items.remove(item);
865:                    props.itemIndex.remove(item.getKey());
866:                    delegate = props.items.listIterator(index);
867:                }
868:
869:                private Item findNext() {
870:                    while (delegate.hasNext()) {
871:                        Item item = delegate.next();
872:                        if (item.getKey() != null && item.getValue() != null) {
873:                            // Found one. Back up!
874:                            delegate.previous();
875:                            return item;
876:                        }
877:                    }
878:                    return null;
879:                }
880:
881:            }
882:
883:            private static class MapEntryImpl implements 
884:                    Map.Entry<String, String> {
885:
886:                private Item item;
887:
888:                public MapEntryImpl(Item item) {
889:                    this .item = item;
890:                }
891:
892:                public String getKey() {
893:                    return item.getKey();
894:                }
895:
896:                public String getValue() {
897:                    return item.getValue();
898:                }
899:
900:                public String setValue(String value) {
901:                    String result = item.getValue();
902:                    item.setValue(value);
903:                    return result;
904:                }
905:
906:            }
907:
908:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.