package nu.studer.teamcity.buildscan.agent.servicemessage;

final class ServiceMessage {

    private static final String SERVICE_MESSAGE_START = "##teamcity[";
    private static final String SERVICE_MESSAGE_END = "]";

    private final String name;
    private final String argument;

    private ServiceMessage(String name, String argument) {
        this.name = name;
        this.argument = argument;
    }

    static ServiceMessage of(String name, String argument) {
        return new ServiceMessage(name, argument);
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(SERVICE_MESSAGE_START);
        sb.append(name);
        sb.append(' ');
        sb.append('\'');
        sb.append(escape(argument));
        sb.append('\'');
        sb.append(SERVICE_MESSAGE_END);
        return sb.toString();
    }

    private String escape(String s) {
        StringBuilder sb = new StringBuilder();
        for (char c : s.toCharArray()) {
            sb.append(escape(c));
        }
        return sb.toString();
    }

    private String escape(final char c) {
        switch (c) {
            case '\n':
                return "n";
            case '\r':
                return "r";
            case '|':
                return "|";
            case '\'':
                return "\'";
            case '[':
                return "[";
            case ']':
                return "]";
            default:
                return c < 128 ? Character.toString(c) : String.format("0x%04x", (int) c);
        }
    }

}

package nu.studer.teamcity.buildscan.agent.servicemessage;

final class ServiceMessage {

    private static final String SERVICE_MESSAGE_START = "##teamcity[";
    private static final String SERVICE_MESSAGE_END = "]";

    private final String name;
    private final String argument;

    private ServiceMessage(String name, String argument) {
        this.name = name;
        this.argument = argument;
    }

    static ServiceMessage of(String name, String argument) {
        return new ServiceMessage(name, argument);
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(SERVICE_MESSAGE_START);
        sb.append(name);
        sb.append(' ');
        sb.append('\'');
        sb.append(escape(argument));
        sb.append('\'');
        sb.append(SERVICE_MESSAGE_END);
        return sb.toString();
    }

    private String escape(String s) {
        StringBuilder sb = new StringBuilder();
        for (char c : s.toCharArray()) {
            sb.append(escape(c));
        }
        return sb.toString();
    }

    private String escape(char c) {
        String escapeCharacter = "|";
        switch (c) {
            case '\n':
                return escapeCharacter + "n";
            case '\r':
                return escapeCharacter + "r";
            case '|':
                return escapeCharacter + "|";
            case '\'':
                return escapeCharacter + "\'";
            case '[':
                return escapeCharacter + "[";
            case ']':
                return escapeCharacter + "]";
            default:
                return c < 128 ? Character.toString(c) : escapeCharacter + String.format("0x%04x", (int) c);
        }
    }

}

Fix message escaping to be the same as in the init script
Fix message escaping to be the same as in the init script

This adjustment is done to have the same character escaping as in the PR provided by the TeamCity folks from JetBrains, assuming their encoding code is correct and not the one that was previously used by this plugin.
