preliminary checkin of documentation files
[mir.git] / source / mir / util / StructuredContentParser.java
1 /*
2  * Copyright (C) 2001, 2002 The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30
31 package mir.util;
32
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Vector;
37
38
39 /**
40  * <p>Title: </p>
41  * <p>Description:
42  *   Class to parse structured content:
43  *   <tt>
44  *      {
45  *        name = 'Countries'
46  *        countries = [ spain 'united kingdom' germany ]
47  *        cities = {
48  *          spain = [ 'madrid' barcelona bilbao ]
49  *          'united kingdom' = [ 'london' 'lancaster' ]
50  *          germany = [ 'berlin' 'bremen' ]
51  *        }
52  *      }
53  *   </tt>
54  *
55  *   And put it into a <code>String</code>/<code>Map</code>/<code>List</code> structure.
56  *  </p>
57  *  <p>
58  *    Parsing is be very optimistic: no exception is ever to be thrown.
59  *  </p>
60  */
61 public class StructuredContentParser {
62   public StructuredContentParser() {
63   }
64
65   private static class Scanner {
66     private String data;
67     private int position;
68
69     public Scanner(String aData) {
70       data = aData;
71       position = 0;
72     }
73
74     public String scanIdentifier() {
75       StringBuffer result = new StringBuffer();
76
77       while (!isAtEnd() && Character.isJavaIdentifierPart(peek())) {
78         result.append(scan());
79       }
80
81       return result.toString();
82     }
83
84     public String scanString() {
85       StringBuffer result = new StringBuffer();
86       char delimiter='\'';
87
88       if (!isAtEnd()) {
89         delimiter=scan();
90       }
91
92       boolean finished = false;
93
94       while (!finished && !isAtEnd()) {
95         char data = scan();
96
97         if (data == delimiter) {
98           if (!isAtEnd() && peek() == delimiter) {
99             scan();
100             result.append(data);
101           }
102           else
103             finished=true;
104         }
105         else
106           result.append(data);
107       }
108
109       return result.toString();
110     }
111
112     public void skipSpace() {
113       while (!isAtEnd() && Character.isWhitespace(peek()))
114         scan();
115     }
116
117     public boolean isAtEnd() {
118       return position >= data.length();
119     }
120
121     public char peek() {
122       if (!isAtEnd()) {
123         return data.charAt(position);
124       }
125       else
126         return '\0';
127     }
128
129     public char scan() {
130       if (!isAtEnd()) {
131         char result = data.charAt(position);
132         position++;
133         return result;
134       }
135       else
136         return '\0';
137     }
138   }
139
140   public static List parseList(Scanner aScanner) {
141     List result = new Vector();
142     aScanner.skipSpace();
143     if (aScanner.peek() == '[')
144       aScanner.scan();
145     aScanner.skipSpace();
146     Object object = parseObject(aScanner);
147
148     while (object != null) {
149       result.add(object);
150       aScanner.skipSpace();
151       object = parseObject(aScanner);
152     }
153
154     aScanner.skipSpace();
155     if (aScanner.peek() == ']')
156       aScanner.scan();
157
158     return result;
159   }
160
161   public static Map parseMap(Scanner aScanner) {
162     Map result = new HashMap();
163     aScanner.skipSpace();
164     if (aScanner.peek() == '{')
165       aScanner.scan();
166     aScanner.skipSpace();
167     Object key = parseObject(aScanner);
168     aScanner.skipSpace();
169     if (aScanner.peek() == '=')
170       aScanner.scan();
171     aScanner.skipSpace();
172     Object value = parseObject(aScanner);
173
174
175     while (key != null && value!=null) {
176       result.put(key, value);
177       aScanner.skipSpace();
178       key = parseObject(aScanner);
179       aScanner.skipSpace();
180       if (aScanner.peek() == '=')
181         aScanner.scan();
182       aScanner.skipSpace();
183       value = parseObject(aScanner);
184     }
185
186     aScanner.skipSpace();
187     if (aScanner.peek() == '}')
188       aScanner.scan();
189
190     return result;
191   }
192
193   public static Object parseObject(Scanner aScanner) {
194    aScanner.skipSpace();
195
196     if (!aScanner.isAtEnd()) {
197       char data = aScanner.peek();
198
199       if (data == '[')
200         return parseList(aScanner);
201       if (data == '{')
202         return parseMap(aScanner);
203       if (data == '\'' || data == '"')
204         return aScanner.scanString();
205       if (Character.isJavaIdentifierPart(data))
206         return aScanner.scanIdentifier();
207     }
208
209     return null;
210   }
211
212   public static Object parse(String aData) {
213     Scanner scanner = new Scanner(aData);
214
215     return parseObject(scanner);
216   }
217
218   public static String constructStringLiteral(String aString) {
219     final char[] CHARACTERS_TO_ESCAPE = { '\'' };
220     final String[] ESCAPE_CODES = { "\'\'" };
221
222     return "'" +  StringRoutines.replaceStringCharacters(aString, CHARACTERS_TO_ESCAPE, ESCAPE_CODES) + "'";
223   }
224 }