View Javadoc

1   /*
2    *  Copyright 2006 Simon Raess
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  package net.sf.beep4j.internal.message;
17  
18  import java.nio.ByteBuffer;
19  import java.nio.CharBuffer;
20  import java.nio.charset.Charset;
21  import java.util.BitSet;
22  
23  import net.sf.beep4j.Message;
24  
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  
28  public class DefaultMessageParser implements MessageParser {
29  
30  	private static final Logger LOG = LoggerFactory.getLogger(MessageParser.class);
31  	
32  	private static final BitSet fieldChars;
33  	
34      static {
35          fieldChars = new BitSet();
36          for (int i = 0x21; i <= 0x39; i++) {
37              fieldChars.set(i);
38          }
39          for (int i = 0x3b; i <= 0x7e; i++) {
40              fieldChars.set(i);
41          }
42      }
43  
44  	public Message parse(ByteBuffer buffer) {
45  		buffer.mark();
46  		int pos = 0;
47  		byte prev = 0;
48  		boolean armed = true;
49  		while (buffer.hasRemaining()) {
50  			byte current = buffer.get();
51  			if (prev == (byte) '\r' && current == (byte) '\n') {
52  				if (armed) {
53  					pos = buffer.position();
54  					break;
55  				}
56  				armed = true;
57  			} else if (current != '\r') {
58  				armed = false;
59  			}
60  			prev = current;
61  		}
62  		
63  		LOG.debug("message body starts at offset " + buffer.position());
64  		
65  		ByteBuffer content = buffer.slice();
66  		
67  		buffer.reset();
68  		buffer.limit(pos);
69  
70  		MessageHeader header = parseHeader(buffer);
71  		
72  		return new DefaultMessage(header, content);
73  	}
74  	
75      private MessageHeader parseHeader(ByteBuffer buffer) {
76  		StringBuffer sb = new StringBuffer();
77  		
78  		Charset charset = Charset.forName("US-ASCII");
79  		CharBuffer chars = charset.decode(buffer);
80  		sb.append(chars);
81  
82  		int start = 0;
83  		int pos = 0;
84  
85  		MessageHeader header = new MessageHeader();
86  		
87  		while (pos < sb.length()) {
88  			while (pos < sb.length() && sb.charAt(pos) != '\r') {
89  				pos++;
90  			}
91  			if (pos < sb.length() - 1 && sb.charAt(pos + 1) != '\n') {
92  				pos++;
93  				continue;
94  			}
95  
96  			if (pos >= sb.length() - 2 || fieldChars.get(sb.charAt(pos + 2))) {
97  
98  				/*
99  				 * field should be the complete field data excluding the 
100 				 * trailing \r\n.
101 				 */
102 				String field = sb.substring(start, pos);
103 				start = pos + 2;
104 
105 				/*
106 				 * Check for a valid field.
107 				 */
108 				int index = field.indexOf(':');
109 				boolean valid = false;
110 				if (index != -1 && fieldChars.get(field.charAt(0))) {
111 					valid = true;
112 					String fieldName = field.substring(0, index).trim();
113 					for (int i = 0; i < fieldName.length(); i++) {
114 						if (!fieldChars.get(fieldName.charAt(i))) {
115 							valid = false;
116 							break;
117 						}
118 					}
119 
120 					if (valid) {
121 						header.addHeader(fieldName, field.substring(index + 1));
122 					}
123 				}
124 			}
125 
126 			pos += 2;
127 		}
128 
129 		return header;
130 	}
131 
132 }