use of com.github.mangstadt.vinnie.SyntaxStyle in project vinnie by mangstadt.
the class VObjectWriterTest method parameters_multivalued.
@Test
public void parameters_multivalued() throws Exception {
List<VObjectParameters> list = new ArrayList<VObjectParameters>();
VObjectParameters parameters = new VObjectParameters();
parameters.put("SINGLE", "one");
list.add(parameters);
parameters = new VObjectParameters();
parameters.put("MULTIPLE", "one");
parameters.put("MULTIPLE", "two");
list.add(parameters);
parameters = new VObjectParameters();
parameters.put("SINGLE", "one");
parameters.put("MULTIPLE", "one");
parameters.put("MULTIPLE", "two");
list.add(parameters);
SyntaxStyle style = SyntaxStyle.OLD;
{
for (boolean caretEncoding : new boolean[] { false, true }) {
StringWriter sw = new StringWriter();
VObjectWriter writer = new VObjectWriter(sw, style);
writer.setCaretEncodingEnabled(caretEncoding);
for (VObjectParameters p : list) {
writer.writeProperty(null, "PROP", p, "");
}
String actual = sw.toString();
// @formatter:off
String expected = "PROP;SINGLE=one:\r\n" + "PROP;MULTIPLE=one;MULTIPLE=two:\r\n" + "PROP;SINGLE=one;MULTIPLE=one;MULTIPLE=two:\r\n";
// @formatter:on
assertEquals(expected, actual);
}
}
style = SyntaxStyle.NEW;
{
for (boolean caretEncoding : new boolean[] { false, true }) {
StringWriter sw = new StringWriter();
VObjectWriter writer = new VObjectWriter(sw, style);
writer.setCaretEncodingEnabled(caretEncoding);
for (VObjectParameters p : list) {
writer.writeProperty(null, "PROP", p, "");
}
String actual = sw.toString();
// @formatter:off
String expected = "PROP;SINGLE=one:\r\n" + "PROP;MULTIPLE=one,two:\r\n" + "PROP;SINGLE=one;MULTIPLE=one,two:\r\n";
// @formatter:on
assertEquals(expected, actual);
}
}
}
use of com.github.mangstadt.vinnie.SyntaxStyle in project vinnie by mangstadt.
the class VObjectWriterTest method setCaretDecoding.
@Test
public void setCaretDecoding() {
for (SyntaxStyle style : SyntaxStyle.values()) {
StringWriter sw = new StringWriter();
VObjectWriter writer = new VObjectWriter(sw, style);
assertFalse(writer.isCaretEncodingEnabled());
writer.setCaretEncodingEnabled(true);
assertTrue(writer.isCaretEncodingEnabled());
}
}
use of com.github.mangstadt.vinnie.SyntaxStyle in project vinnie by mangstadt.
the class VObjectWriterTest method group_starts_with_whitespace.
@Test
public void group_starts_with_whitespace() throws Exception {
for (SyntaxStyle style : SyntaxStyle.values()) {
StringWriter sw = new StringWriter();
VObjectWriter writer = new VObjectWriter(sw, style);
for (char c : " \t".toCharArray()) {
try {
writer.writeProperty(c + "", "PROP", new VObjectParameters(), "");
fail("IllegalArgumentException expected when group name starts with character " + ch(c) + " and style is " + style.name());
} catch (IllegalArgumentException e) {
// expected
}
String actual = sw.toString();
// @formatter:off
String expected = "";
// @formatter:on
assertEquals(expected, actual);
}
}
}
use of com.github.mangstadt.vinnie.SyntaxStyle in project vinnie by mangstadt.
the class VObjectReader method parseProperty.
/**
* Parses the next property off the input stream.
* @param listener the data listener (for reporting warnings)
* @return the parsed property or null if the property could not be parsed
* @throws IOException if there was a problem reading from the input stream
*/
private VObjectProperty parseProperty(VObjectDataListener listener) throws IOException {
VObjectProperty property = new VObjectProperty();
/*
* The syntax style to assume the data is in.
*/
SyntaxStyle syntax = stack.peekSyntax();
/*
* The name of the parameter we're currently inside of.
*/
String curParamName = null;
/*
* The character that was used to escape the current character (for
* parameter values).
*/
char paramValueEscapeChar = 0;
/*
* Are we currently inside a parameter value that is surrounded with
* double-quotes?
*/
boolean inQuotes = false;
/*
* Are we currently inside the property value?
*/
boolean inValue = false;
/*
* Does the line use quoted-printable encoding, and does it end all of
* its folded lines with a "=" character?
*/
boolean foldedQuotedPrintableLine = false;
/*
* Are we currently inside the whitespace that prepends a folded line?
*/
boolean inFoldedLineWhitespace = false;
/*
* The current character.
*/
char ch = 0;
/*
* The previous character.
*/
char prevChar;
while (true) {
prevChar = ch;
int read = nextChar();
if (read < 0) {
// end of stream
eos = true;
break;
}
ch = (char) read;
if (prevChar == '\r' && ch == '\n') {
/*
* The newline was already processed when the "\r" character was
* encountered, so ignore the accompanying "\n" character.
*/
continue;
}
if (isNewline(ch)) {
foldedQuotedPrintableLine = (inValue && prevChar == '=' && property.getParameters().isQuotedPrintable());
if (foldedQuotedPrintableLine) {
/*
* Remove the "=" character that sometimes appears at the
* end of quoted-printable lines that are followed by a
* folded line.
*/
buffer.chop();
context.unfoldedLine.chop();
}
// keep track of the current line number
lineNumber++;
continue;
}
if (isNewline(prevChar)) {
if (isWhitespace(ch)) {
/*
* This line is a continuation of the previous line (the
* line is folded).
*/
inFoldedLineWhitespace = true;
continue;
}
if (foldedQuotedPrintableLine) {
/*
* The property's parameters indicate that the property
* value is quoted-printable. And the previous line ended
* with an equals sign. This means that folding whitespace
* may not be prepended to folded lines like it should.
*/
} else {
/*
* We're reached the end of the property.
*/
leftOver = ch;
break;
}
}
if (inFoldedLineWhitespace) {
if (isWhitespace(ch) && syntax == SyntaxStyle.OLD) {
/*
* 2.1 allows multiple whitespace characters to be used for
* folding (section 2.1.3).
*/
continue;
}
inFoldedLineWhitespace = false;
}
context.unfoldedLine.append(ch);
if (inValue) {
buffer.append(ch);
continue;
}
// decode escaped parameter value character
if (paramValueEscapeChar != 0) {
char escapeChar = paramValueEscapeChar;
paramValueEscapeChar = 0;
switch(escapeChar) {
case '\\':
switch(ch) {
case '\\':
buffer.append(ch);
continue;
case ';':
/*
* Semicolons can only be escaped in old style parameter
* values. If a new style parameter value has
* semicolons, the value should be surrounded in double
* quotes.
*/
buffer.append(ch);
continue;
}
break;
case '^':
switch(ch) {
case '^':
buffer.append(ch);
continue;
case 'n':
buffer.append(NEWLINE);
continue;
case '\'':
buffer.append('"');
continue;
}
break;
}
/*
* Treat the escape character as a normal character because it's
* not a valid escape sequence.
*/
buffer.append(escapeChar).append(ch);
continue;
}
// check for a parameter value escape character
if (curParamName != null) {
switch(syntax) {
case OLD:
if (ch == '\\') {
paramValueEscapeChar = ch;
continue;
}
break;
case NEW:
if (ch == '^' && caretDecodingEnabled) {
paramValueEscapeChar = ch;
continue;
}
break;
}
}
// set the group
if (ch == '.' && property.getGroup() == null && property.getName() == null) {
property.setGroup(buffer.getAndClear());
continue;
}
if ((ch == ';' || ch == ':') && !inQuotes) {
if (property.getName() == null) {
// set the property name
property.setName(buffer.getAndClear());
} else {
// set a parameter value
String paramValue = buffer.getAndClear();
if (syntax == SyntaxStyle.OLD) {
// old style allows whitespace to surround the "=", so remove it
paramValue = ltrim(paramValue);
}
property.getParameters().put(curParamName, paramValue);
curParamName = null;
}
if (ch == ':') {
// the rest of the line is the property value
inValue = true;
}
continue;
}
if (property.getName() != null) {
// it's a multi-valued parameter
if (ch == ',' && curParamName != null && !inQuotes && syntax != SyntaxStyle.OLD) {
String paramValue = buffer.getAndClear();
property.getParameters().put(curParamName, paramValue);
continue;
}
// set the parameter name
if (ch == '=' && curParamName == null) {
String paramName = buffer.getAndClear().toUpperCase();
if (syntax == SyntaxStyle.OLD) {
// old style allows whitespace to surround the "=", so remove it
paramName = rtrim(paramName);
}
curParamName = paramName;
continue;
}
// entering/leaving a double-quoted parameter value (new style only)
if (ch == '"' && curParamName != null && syntax != SyntaxStyle.OLD) {
inQuotes = !inQuotes;
continue;
}
}
buffer.append(ch);
}
/*
* Line or stream ended before the property value was reached.
*/
if (!inValue) {
return null;
}
property.setValue(buffer.getAndClear());
if (property.getParameters().isQuotedPrintable()) {
decodeQuotedPrintable(property, listener);
}
return property;
}
use of com.github.mangstadt.vinnie.SyntaxStyle in project ez-vcard by mangstadt.
the class VCardParameters method validate.
/**
* <p>
* Checks the parameters for data consistency problems or deviations from
* the specification.
* </p>
* <p>
* These problems will not prevent the vCard from being written to a data
* stream*, but may prevent it from being parsed correctly by the consuming
* application.
* </p>
* <p>
* *With a few exceptions: One thing this method does is check for illegal
* characters. There are certain characters that will break the vCard syntax
* if written (such as a newline character in a parameter name). If one of
* these characters is present, it WILL prevent the vCard from being
* written.
* </p>
* @param version the vCard version to validate against
* @return a list of warnings or an empty list if no problems were found
*/
public List<ValidationWarning> validate(VCardVersion version) {
List<ValidationWarning> warnings = new ArrayList<ValidationWarning>(0);
/*
* Check for invalid characters in names and values.
*/
SyntaxStyle syntax = version.getSyntaxStyle();
for (Map.Entry<String, List<String>> entry : this) {
String name = entry.getKey();
/*
* Don't check LABEL parameter for 2.1 and 3.0 because this
* parameter is converted to a property in those versions.
*/
if (version != VCardVersion.V4_0 && LABEL.equalsIgnoreCase(name)) {
continue;
}
// check the parameter name
if (!VObjectValidator.validateParameterName(name, syntax, true)) {
if (syntax == SyntaxStyle.OLD) {
AllowedCharacters notAllowed = VObjectValidator.allowedCharactersParameterName(syntax, true).flip();
warnings.add(new ValidationWarning(30, name, notAllowed.toString(true)));
} else {
warnings.add(new ValidationWarning(26, name));
}
}
// check the parameter value(s)
List<String> values = entry.getValue();
for (String value : values) {
/*
* Newlines are allowed in LABEL parameters, but are not allowed
* by vobject, so remove them from the value before validating.
*/
if (LABEL.equalsIgnoreCase(name)) {
value = value.replaceAll("\r\n|\r|\n", "");
}
if (!VObjectValidator.validateParameterValue(value, syntax, false, true)) {
AllowedCharacters notAllowed = VObjectValidator.allowedCharactersParameterValue(syntax, false, true).flip();
int code = (syntax == SyntaxStyle.OLD) ? 31 : 25;
warnings.add(new ValidationWarning(code, name, value, notAllowed.toString(true)));
}
}
}
/*
* Check for invalid or unsupported values (e.g. "ENCODING=foo").
*/
{
final int nonStandardValueCode = 3;
final int unsupportedValueCode = 4;
String value = first(CALSCALE);
if (value != null && Calscale.find(value) == null) {
warnings.add(new ValidationWarning(nonStandardValueCode, CALSCALE, value, Calscale.all()));
}
value = first(ENCODING);
if (value != null) {
Encoding encoding = Encoding.find(value);
if (encoding == null) {
warnings.add(new ValidationWarning(nonStandardValueCode, ENCODING, value, Encoding.all()));
} else if (!encoding.isSupportedBy(version)) {
warnings.add(new ValidationWarning(unsupportedValueCode, ENCODING, value));
}
}
value = first(VALUE);
if (value != null) {
VCardDataType dataType = VCardDataType.find(value);
if (dataType == null) {
warnings.add(new ValidationWarning(nonStandardValueCode, VALUE, value, VCardDataType.all()));
} else if (!dataType.isSupportedBy(version)) {
warnings.add(new ValidationWarning(unsupportedValueCode, VALUE, value));
}
}
}
/*
* Check for parameters with malformed values.
*/
{
final int malformedValueCode = 5;
try {
getGeo();
} catch (IllegalStateException e) {
warnings.add(new ValidationWarning(malformedValueCode, GEO, first(GEO)));
}
try {
Integer index = getIndex();
if (index != null && index <= 0) {
warnings.add(new ValidationWarning(28, index));
}
} catch (IllegalStateException e) {
warnings.add(new ValidationWarning(malformedValueCode, INDEX, first(INDEX)));
}
List<String> pids = get(PID);
for (String pid : pids) {
if (!isPidValid(pid)) {
warnings.add(new ValidationWarning(27, pid));
}
}
try {
Integer pref = getPref();
if (pref != null && (pref < 1 || pref > 100)) {
warnings.add(new ValidationWarning(29, pref));
}
} catch (IllegalStateException e) {
warnings.add(new ValidationWarning(malformedValueCode, PREF, first(PREF)));
}
}
/*
* Check that each parameter is supported by the given vCard version.
*/
{
final int paramNotSupportedCode = 6;
for (Map.Entry<String, Set<VCardVersion>> entry : supportedVersions.entrySet()) {
String name = entry.getKey();
String value = first(name);
if (value == null) {
continue;
}
Set<VCardVersion> versions = entry.getValue();
if (!versions.contains(version)) {
warnings.add(new ValidationWarning(paramNotSupportedCode, name));
}
}
}
/*
* Check that the CHARSET parameter has a character set that is
* supported by this JVM.
*/
{
final int invalidCharsetCode = 22;
String charsetStr = getCharset();
if (charsetStr != null) {
try {
Charset.forName(charsetStr);
} catch (IllegalCharsetNameException e) {
warnings.add(new ValidationWarning(invalidCharsetCode, charsetStr));
} catch (UnsupportedCharsetException e) {
warnings.add(new ValidationWarning(invalidCharsetCode, charsetStr));
}
}
}
return warnings;
}
Aggregations