static void parseAttributeLine()

in storage/src/main/java/com/microsoft/alm/storage/macosx/KeychainSecurityCliStore.java [150:296]


    static void parseAttributeLine(final String line, final Map<String, Object> destination) {
        final String template = "Undefined transition '%1$s' from %2$s.";
        final StringBuilder key = new StringBuilder();
        final StringBuilder type = new StringBuilder();
        final StringBuilder value = new StringBuilder();
        boolean isNullValue = false;
        AttributeParsingState state = AttributeParsingState.Spaces;
        for (final char c : line.toCharArray()) {
            switch (state) {
                case Spaces:
                    switch (c) {
                        case ' ':
                            break;
                        case '0':
                            state = AttributeParsingState.HexKey;
                            key.append(c);
                            break;
                        case '"':
                            state = AttributeParsingState.StringKey;
                            break;
                        default:
                            throw new Error(String.format(template, c, state));
                    }
                    break;
                case HexKey:
                    switch (c) {
                        case ' ':
                            state = AttributeParsingState.BeforeType;
                            break;
                        case 'x':
                        case '0':
                        case '1':
                        case '2':
                        case '3':
                        case '4':
                        case '5':
                        case '6':
                        case '7':
                        case '8':
                        case '9':
                        case 'A':
                        case 'B':
                        case 'C':
                        case 'D':
                        case 'E':
                        case 'F':
                            key.append(c);
                            break;
                        default:
                            throw new Error(String.format(template, c, state));
                    }
                    break;
                case StringKey:
                    switch (c) {
                        case '"':
                            state = AttributeParsingState.BeforeType;
                            break;
                        default:
                            key.append(c);
                            break;
                    }
                    break;
                case BeforeType:
                    switch (c) {
                        case '<':
                            state = AttributeParsingState.Type;
                            break;
                        default:
                            throw new Error(String.format(template, c, state));
                    }
                    break;
                case Type:
                    switch (c) {
                        case '>':
                            state = AttributeParsingState.AfterType;
                            break;
                        default:
                            type.append(c);
                            break;
                    }
                    break;
                case AfterType:
                    switch (c) {
                        case '=':
                            state = AttributeParsingState.BeforeValue;
                            break;
                        default:
                            throw new Error(String.format(template, c, state));
                    }
                    break;
                case BeforeValue:
                    switch (c) {
                        case '<':
                            state = AttributeParsingState.NullValue;
                            isNullValue = true;
                            value.append(c);
                            break;
                        case '0':
                            // TODO: check that type was "timedate"
                            state = AttributeParsingState.TimeDateValue;
                            value.append(c);
                            break;
                        case '"':
                            state = AttributeParsingState.StringValue;
                            break;
                        default:
                            throw new Error(String.format(template, c, state));
                    }
                    break;
                case NullValue:
                    switch (c) {
                        case '>':
                            state = AttributeParsingState.ValueFinished;
                            value.append(c);
                            break;
                        case 'N':
                        case 'U':
                        case 'L':
                            value.append(c);
                            break;
                        default:
                            throw new Error(String.format(template, c, state));
                    }
                    break;
                case StringValue:
                    // double quotes aren't escaped, so everything goes in as-is
                    value.append(c);
                    break;
                case TimeDateValue:
                    // we don't care about timedate for now, so just append as-is
                    value.append(c);
                    break;
                case ValueFinished:
                    throw new Error(String.format(template, c, state));
            }
        }
        if (isNullValue) {
            destination.put(key.toString(), null);
        } else if ("blob".equals(type.toString())) {
            final int lastCharIndex = value.length() - 1;
            value.deleteCharAt(lastCharIndex);
            destination.put(key.toString(), value.toString());
        }
        // TODO: else if ("timedate".equals(type))
        // TODO: else if ("uint32".equals(type))
        // TODO: else if ("sint32".equals(type))
    }