001: // HttpBag.java
002: // $Id: HttpBag.java,v 1.11 2000/08/16 21:37:59 ylafon Exp $
003: // (c) COPYRIGHT MIT and INRIA, 1997.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.www.http;
007:
008: import java.util.Enumeration;
009:
010: import org.w3c.util.ArrayDictionary;
011:
012: /**
013: * Internal representation of protocol headers conforming to the bag spec.
014: * The <strong>bag</strong> specification is part of the Protocol Extension
015: * Protocol defined by w3c, it can be found
016: * <a href="http://www.w3.org/hypertext/WWW/TR/WD-http-pep.html>here</a>.
017: */
018:
019: public class HttpBag extends BasicValue {
020: boolean isToplevel = false;
021: String name = null;
022: ArrayDictionary items = null;
023:
024: protected final void updateByteValue() {
025: HttpBuffer buf = new HttpBuffer();
026: if (isToplevel) {
027: // Dump this bag as a list of bags:
028: Enumeration e = items.elements();
029: boolean s = true;
030: while (e.hasMoreElements()) {
031: HttpBag bag = (HttpBag) e.nextElement();
032: // Append separator if needed:
033: if (s)
034: s = false;
035: else
036: buf.append((byte) ',');
037: // Dump the bag now:
038: bag.appendValue(buf);
039: }
040: } else {
041: buf.append((byte) '{');
042: buf.append(name);
043: buf.append((byte) ' ');
044: // Append all items:
045: Enumeration e = items.keys();
046: boolean s = true;
047: while (e.hasMoreElements()) {
048: // Append separator after first item only:
049: if (s)
050: s = false;
051: else
052: buf.append((byte) ' ');
053: // Dump the item:
054: String name = (String) e.nextElement();
055: Object value = items.get(name);
056: if (value instanceof Boolean) {
057: buf.append(name);
058: } else if (value instanceof HttpBag) {
059: ((HttpBag) value).appendValue(buf);
060: } else {
061: String msg = "Invalid bag item value, key=\""
062: + name + "\".";
063: throw new HttpInvalidValueException(msg);
064: }
065: }
066: buf.append((byte) '}');
067: }
068: raw = buf.getByteCopy();
069: roff = 0;
070: rlen = raw.length;
071: }
072:
073: /**
074: * parse bag.
075: * @exception HttpParserException if parsing failed.
076: */
077: protected HttpBag parseBag(ParseState ps)
078: throws HttpParserException {
079: StringBuffer sb = new StringBuffer();
080: int i = ps.ioff;
081: byte b = raw[i];
082:
083: // skip spaces, check for opening bracket
084: while ((i < ps.bufend) && ((b = raw[i]) <= 32))
085: i++;
086: if (i >= ps.bufend)
087: return null;
088: if (b != '{')
089: error("Invalid Bag format (no {).");
090: // skip spaces, bag list separators, get the bag name
091: for (++i; (i < ps.bufend) && ((b = raw[i]) <= 32); i++)
092: ;
093: if (i >= ps.bufend)
094: error("Invalid Bag format (no name).");
095: while ((i < ps.bufend) && ((b = raw[i]) > 32) && (b != '}')) {
096: sb.append((char) b);
097: i++;
098: }
099: HttpBag bag = new HttpBag(true, sb.toString());
100: // get items:
101: while (i < ps.bufend) {
102: b = raw[i];
103: if (b <= 32) {
104: i++;
105: continue;
106: } else if (b == '}') {
107: ps.ooff = i + 1;
108: return bag;
109: } else if (b == '{') {
110: ParseState inc = new ParseState(i, ps.bufend);
111: HttpBag subbag = parseBag(inc);
112: bag.items.put(subbag.name, subbag);
113: i = inc.ooff;
114: } else if (b == '\"') {
115: // get quoted string (FIXME, escape chars !)
116: sb.setLength(0);
117: i++;
118: while ((i < ps.bufend) && ((b = raw[i]) != '\"')) {
119: sb.append((char) b);
120: i++;
121: }
122: bag.items.put(sb.toString(), Boolean.TRUE);
123: i++;
124: } else {
125: // get token (FIXME, see token spec and tspecials)
126: sb.setLength(0);
127: while ((i < ps.bufend) && ((b = raw[i]) > 32)
128: && (b != '}')) {
129: sb.append((char) b);
130: i++;
131: }
132: bag.addItem(sb.toString());
133: }
134: }
135: return bag;
136: }
137:
138: /**
139: * parse.
140: * @exception HttpParserException if parsing failed.
141: */
142: protected final void parse() throws HttpParserException {
143: int i = roff;
144: // Parses a list of bags:
145: isToplevel = true;
146: HttpBag top = this ;
147: while (i < rlen) {
148: switch (raw[i]) {
149: case (byte) '{':
150: ParseState ps = new ParseState(i, rlen);
151: HttpBag bag = parseBag(ps);
152: top.items.put(bag.name, bag);
153: i = ps.ooff;
154: break;
155: case (byte) ' ':
156: case (byte) '\t':
157: case (byte) ',':
158: i++;
159: break;
160: default:
161: error("Unexpected separator \"" + raw[i] + "\".");
162: }
163: }
164: }
165:
166: public Object getValue() {
167: return this ;
168: }
169:
170: /**
171: * Get this bag names
172: * @return The name of this bag.
173: */
174:
175: public String getName() {
176: validate();
177: return name;
178: }
179:
180: /**
181: * Add a named bag into this bag.
182: * @param bag The bag to add (in case item is a bag).
183: */
184:
185: public void addBag(HttpBag subbag) {
186: validate();
187: items.put(subbag.getName(), subbag);
188: }
189:
190: /**
191: * Does this bag have a named sub-bag of the given name ?
192: * @param name The name of the sub-bag to be tested for.
193: * @return <strong>true</strong> if this sub-bag exists.
194: */
195:
196: public boolean hasBag(String name) {
197: validate();
198: Object item = items.get(name);
199: if ((item != null) && (item instanceof HttpBag))
200: return true;
201: return false;
202: }
203:
204: /**
205: * Get a named sub-bag from this bag.
206: * @param name The name of the sub-bag to get.
207: * @return A bag instance, or <strong>null</strong> if none was found.
208: */
209:
210: public HttpBag getBag(String name) {
211: validate();
212: if (hasBag(name))
213: return (HttpBag) items.get(name);
214: return null;
215: }
216:
217: /**
218: * Add an item into this bag.
219: * @param name The new item name.
220: */
221:
222: public void addItem(String name) {
223: validate();
224: items.put(name, Boolean.TRUE);
225: }
226:
227: /**
228: * Add a sub-bag to this bag.
229: * @param subbag The sub-bag to add.
230: */
231:
232: public void addItem(HttpBag subbag) {
233: validate();
234: items.put(subbag.getName(), subbag);
235: }
236:
237: /**
238: * Does this bag contains the given item, being a bag or a simple word.
239: * @param name The name of the item to test.
240: * @return <strong>true</strong> if the bag contains the given item,
241: * <strong>false</strong> otherwise.
242: */
243:
244: public boolean hasItem(String name) {
245: validate();
246: return items.get(name) != null;
247: }
248:
249: /**
250: * Remove an item from that bag.
251: * @param name The name of the item to remove.
252: */
253:
254: public void removeItem(String name) {
255: validate();
256: items.remove(name);
257: }
258:
259: /**
260: * Get all named items from this bag.
261: * This include both named sub-bags and items by their own.
262: */
263:
264: public Enumeration keys() {
265: validate();
266: return items.keys();
267: }
268:
269: /**
270: * Is that a top level bag or not ?
271: * @return A boolean, <strong>true</strong> if the bag was a toplevel
272: * bag.
273: */
274:
275: public boolean isToplevelBag() {
276: return isToplevel;
277: }
278:
279: HttpBag() {
280: isValid = false;
281: this .items = new ArrayDictionary(5, 5);
282: }
283:
284: HttpBag(boolean isValid, String name) {
285: this .isValid = isValid;
286: this .name = name;
287: this .items = new ArrayDictionary(5, 5);
288: }
289: }
|