/**************************************************************** | |
* Licensed to the Apache Software Foundation (ASF) under one * | |
* or more contributor license agreements. See the NOTICE file * | |
* distributed with this work for additional information * | |
* regarding copyright ownership. The ASF licenses this file * | |
* to you under the Apache License, Version 2.0 (the * | |
* "License"); you may not use this file except in compliance * | |
* with the License. You may obtain a copy of the License at * | |
* * | |
* http://www.apache.org/licenses/LICENSE-2.0 * | |
* * | |
* Unless required by applicable law or agreed to in writing, * | |
* software distributed under the License is distributed on an * | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * | |
* KIND, either express or implied. See the License for the * | |
* specific language governing permissions and limitations * | |
* under the License. * | |
****************************************************************/ | |
options { | |
static=false; | |
JDK_VERSION = "1.5"; | |
OUTPUT_DIRECTORY = "../../../../../../../../../target/generated-sources/javacc"; | |
//DEBUG_PARSER = true; | |
//DEBUG_TOKEN_MANAGER = true; | |
} | |
PARSER_BEGIN(StructuredFieldParser) | |
/**************************************************************** | |
* Licensed to the Apache Software Foundation (ASF) under one * | |
* or more contributor license agreements. See the NOTICE file * | |
* distributed with this work for additional information * | |
* regarding copyright ownership. The ASF licenses this file * | |
* to you under the Apache License, Version 2.0 (the * | |
* "License"); you may not use this file except in compliance * | |
* with the License. You may obtain a copy of the License at * | |
* * | |
* http://www.apache.org/licenses/LICENSE-2.0 * | |
* * | |
* Unless required by applicable law or agreed to in writing, * | |
* software distributed under the License is distributed on an * | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * | |
* KIND, either express or implied. See the License for the * | |
* specific language governing permissions and limitations * | |
* under the License. * | |
****************************************************************/ | |
package org.apache.james.mime4j.field.structured.parser; | |
/** | |
* Parses generic structure fields. | |
* Unfolds and removes comments. | |
*/ | |
public class StructuredFieldParser { | |
private boolean preserveFolding = false; | |
/** | |
* Should the \r\n folding sequence be preserved? | |
*/ | |
public boolean isFoldingPreserved() { | |
return preserveFolding; | |
} | |
/** | |
* Sets whether the \r\n folding sequence should be preserved. | |
*/ | |
public void setFoldingPreserved(boolean preserveFolding) { | |
this.preserveFolding = preserveFolding; | |
} | |
/** | |
* Unfolds the input and removes comments. | |
* @return unfolded header value with comments removed | |
*/ | |
public String parse() throws ParseException { | |
try { | |
return doParse(); | |
} catch (TokenMgrError e) { | |
// An issue with the TOKENiser | |
// but it's not polite to throw an Error | |
// when executing on a server | |
throw new ParseException(e); | |
} | |
} | |
} | |
PARSER_END(StructuredFieldParser) | |
private String doParse() : | |
{ | |
Token t; | |
StringBuffer buffer = new StringBuffer(50); | |
boolean whitespace = false; | |
boolean first = true; | |
} | |
{ | |
( | |
t = <CONTENT> | |
{ | |
if (first) { | |
first = false; | |
} else if (whitespace) { | |
buffer.append(" "); | |
whitespace = false; | |
} | |
buffer.append(t.image); | |
} | |
| | |
t = <STRING_CONTENT> | |
{ | |
buffer.append(t.image); | |
} | |
| | |
t = <QUOTEDSTRING> | |
{ | |
if (first) { | |
first = false; | |
} else if (whitespace) { | |
buffer.append(" "); | |
whitespace = false; | |
} | |
buffer.append(t.image); | |
} | |
| | |
t = <FOLD> | |
{ | |
if (preserveFolding) buffer.append("\r\n"); | |
} | |
| | |
t = <WS> | |
{ | |
whitespace = true; | |
} | |
)* | |
{return buffer.toString();} | |
} | |
TOKEN_MGR_DECLS : | |
{ | |
// Keeps track of how many levels of comment nesting | |
// we've encountered. This is only used when the 2nd | |
// level is reached, for example ((this)), not (this). | |
// This is because the outermost level must be treated | |
// specially anyway, because the outermost ")" has a | |
// different token type than inner ")" instances. | |
int commentNest; | |
} | |
SKIP : | |
{ | |
// starts a comment | |
"(" : INCOMMENT | |
} | |
<INCOMMENT> SKIP : | |
{ | |
// ends a comment | |
")" : DEFAULT | |
// if this is ever changed to not be a SKIP, need | |
// to make sure matchedToken.token = token.toString() | |
// is called. | |
} | |
<INCOMMENT> SKIP : | |
{ | |
"(" { commentNest = 1; } : NESTED_COMMENT | |
} | |
<INCOMMENT> SKIP : | |
{ | |
<~[ "(", ")" ]> | |
} | |
<NESTED_COMMENT> SKIP: | |
{ | |
"(" { ++commentNest; System.out.println("+++ COMMENT NEST=" + commentNest);} | |
| ")" { --commentNest; System.out.println("+++ COMMENT NEST=" + commentNest); if (commentNest == 0) SwitchTo(INCOMMENT); } | |
} | |
<NESTED_COMMENT> SKIP : | |
{ | |
< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); } | |
} | |
<NESTED_COMMENT> SKIP: | |
{ | |
<~[ "(", ")" ]> | |
} | |
// QUOTED STRINGS | |
SKIP : | |
{ | |
"\"" : INQUOTEDSTRING | |
} | |
<INQUOTEDSTRING> MORE : | |
{ | |
< <QUOTEDPAIR> > { image.deleteCharAt(image.length() - 2); } | |
} | |
<INQUOTEDSTRING> TOKEN : | |
{ | |
< STRING_CONTENT : (~["\"", "\\", "\r"])+ > | |
// Preserve line break within quotes but not trailing white space | |
| < FOLD: "\r\n" ( [" ", "\t"] )* > | |
| < QUOTEDSTRING: "\"" > { matchedToken.image = image.substring(0, image.length() - 1); } : DEFAULT | |
} | |
<DEFAULT> | |
TOKEN : | |
{ | |
< WS: ( [" ", "\t", "\r", "\n"] )+ > | |
} | |
<DEFAULT> | |
TOKEN : | |
{ | |
< CONTENT: (~[" ", "\t", "\r", "\n", "(", "\""])+ > | |
} | |
<*> | |
TOKEN : | |
{ | |
< #QUOTEDPAIR: "\\" <ANY> > | |
| < #ANY: (~[])+ > | |
} |