• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 package com.google.protobuf;
9 
10 /**
11  * Provide text format escaping of proto instances. These ASCII characters are escaped:
12  *
13  * ASCII #7   (bell) --> \a
14  * ASCII #8   (backspace) --> \b
15  * ASCII #9   (horizontal tab) --> \t
16  * ASCII #10  (linefeed) --> \n
17  * ASCII #11  (vertical tab) --> \v
18  * ASCII #13  (carriage return) --> \r
19  * ASCII #12  (formfeed) --> \f
20  * ASCII #34  (apostrophe) --> \'
21  * ASCII #39  (straight double quote) --> \"
22  * ASCII #92  (backslash) --> \\
23  *
24  * Other printable ASCII characters between 32 and 127 inclusive are output as is, unescaped.
25  * Other ASCII characters less than 32 and all Unicode characters 128 or greater are
26  * first encoded as UTF-8, then each byte is escaped individually as a 3-digit octal escape.
27  */
28 final class TextFormatEscaper {
TextFormatEscaper()29   private TextFormatEscaper() {}
30 
31   private interface ByteSequence {
size()32     int size();
33 
byteAt(int offset)34     byte byteAt(int offset);
35   }
36 
37   /**
38    * Backslash escapes bytes in the format used in protocol buffer text format.
39    */
escapeBytes(ByteSequence input)40   static String escapeBytes(ByteSequence input) {
41     final StringBuilder builder = new StringBuilder(input.size());
42     for (int i = 0; i < input.size(); i++) {
43       byte b = input.byteAt(i);
44       switch (b) {
45         case 0x07:
46           builder.append("\\a");
47           break;
48         case '\b':
49           builder.append("\\b");
50           break;
51         case '\f':
52           builder.append("\\f");
53           break;
54         case '\n':
55           builder.append("\\n");
56           break;
57         case '\r':
58           builder.append("\\r");
59           break;
60         case '\t':
61           builder.append("\\t");
62           break;
63         case 0x0b:
64           builder.append("\\v");
65           break;
66         case '\\':
67           builder.append("\\\\");
68           break;
69         case '\'':
70           builder.append("\\\'");
71           break;
72         case '"':
73           builder.append("\\\"");
74           break;
75         default:
76           // Only ASCII characters between 0x20 (space) and 0x7e (tilde) are
77           // printable.  Other byte values must be escaped.
78           if (b >= 0x20 && b <= 0x7e) {
79             builder.append((char) b);
80           } else {
81             builder.append('\\');
82             builder.append((char) ('0' + ((b >>> 6) & 3)));
83             builder.append((char) ('0' + ((b >>> 3) & 7)));
84             builder.append((char) ('0' + (b & 7)));
85           }
86           break;
87       }
88     }
89     return builder.toString();
90   }
91 
92   /**
93    * Backslash escapes bytes in the format used in protocol buffer text format.
94    */
escapeBytes(final ByteString input)95   static String escapeBytes(final ByteString input) {
96     return escapeBytes(
97         new ByteSequence() {
98           @Override
99           public int size() {
100             return input.size();
101           }
102 
103           @Override
104           public byte byteAt(int offset) {
105             return input.byteAt(offset);
106           }
107         });
108   }
109 
110   /** Like {@link #escapeBytes(ByteString)}, but used for byte array. */
111   static String escapeBytes(final byte[] input) {
112     return escapeBytes(
113         new ByteSequence() {
114           @Override
115           public int size() {
116             return input.length;
117           }
118 
119           @Override
120           public byte byteAt(int offset) {
121             return input[offset];
122           }
123         });
124   }
125 
126   /**
127    * Like {@link #escapeBytes(ByteString)}, but escapes a text string.
128    */
129   static String escapeText(String input) {
130     return escapeBytes(ByteString.copyFromUtf8(input));
131   }
132 
133   /** Escape double quotes and backslashes in a String for unicode output of a message. */
134   static String escapeDoubleQuotesAndBackslashes(String input) {
135     return input.replace("\\", "\\\\").replace("\"", "\\\"");
136   }
137 }
138