Search in sources :

Example 26 with SyntaxStyle

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);
        }
    }
}
Also used : StringWriter(java.io.StringWriter) VObjectParameters(com.github.mangstadt.vinnie.VObjectParameters) ArrayList(java.util.ArrayList) SyntaxStyle(com.github.mangstadt.vinnie.SyntaxStyle) Test(org.junit.Test)

Example 27 with SyntaxStyle

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());
    }
}
Also used : StringWriter(java.io.StringWriter) SyntaxStyle(com.github.mangstadt.vinnie.SyntaxStyle) Test(org.junit.Test)

Example 28 with SyntaxStyle

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);
        }
    }
}
Also used : StringWriter(java.io.StringWriter) SyntaxStyle(com.github.mangstadt.vinnie.SyntaxStyle) VObjectParameters(com.github.mangstadt.vinnie.VObjectParameters) Test(org.junit.Test)

Example 29 with SyntaxStyle

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;
}
Also used : VObjectProperty(com.github.mangstadt.vinnie.VObjectProperty) SyntaxStyle(com.github.mangstadt.vinnie.SyntaxStyle)

Example 30 with SyntaxStyle

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;
}
Also used : EnumSet(java.util.EnumSet) Set(java.util.Set) ArrayList(java.util.ArrayList) VCardVersion(ezvcard.VCardVersion) ValidationWarning(ezvcard.ValidationWarning) SortString(ezvcard.property.SortString) IllegalCharsetNameException(java.nio.charset.IllegalCharsetNameException) AllowedCharacters(com.github.mangstadt.vinnie.validate.AllowedCharacters) UnsupportedCharsetException(java.nio.charset.UnsupportedCharsetException) SyntaxStyle(com.github.mangstadt.vinnie.SyntaxStyle) AbstractList(java.util.AbstractList) ArrayList(java.util.ArrayList) List(java.util.List) HashMap(java.util.HashMap) ClientPidMap(ezvcard.property.ClientPidMap) Map(java.util.Map) VCardDataType(ezvcard.VCardDataType)

Aggregations

SyntaxStyle (com.github.mangstadt.vinnie.SyntaxStyle)50 Test (org.junit.Test)45 InOrder (org.mockito.InOrder)24 StringWriter (java.io.StringWriter)21 VObjectParameters (com.github.mangstadt.vinnie.VObjectParameters)15 VObjectProperty (com.github.mangstadt.vinnie.VObjectProperty)12 IllegalCharsetNameException (java.nio.charset.IllegalCharsetNameException)7 UnsupportedCharsetException (java.nio.charset.UnsupportedCharsetException)7 DecoderException (com.github.mangstadt.vinnie.codec.DecoderException)6 ArrayList (java.util.ArrayList)4 AllowedCharacters (com.github.mangstadt.vinnie.validate.AllowedCharacters)3 ValidationWarning (ezvcard.ValidationWarning)3 HashMap (java.util.HashMap)3 Map (java.util.Map)2 VCardDataType (ezvcard.VCardDataType)1 VCardVersion (ezvcard.VCardVersion)1 ClientPidMap (ezvcard.property.ClientPidMap)1 SortString (ezvcard.property.SortString)1 AbstractList (java.util.AbstractList)1 EnumSet (java.util.EnumSet)1