1 //! Protobuf "text format" implementation.
2 //!
3 //! Text format message look like this:
4 //!
5 //! ```text,ignore
6 //! size: 17
7 //! color: "red"
8 //! children {
9 //!     size: 18
10 //!     color: "blue"
11 //! }
12 //! children {
13 //!     size: 19
14 //!     color: "green"
15 //! }
16 //! ```
17 //!
18 //! This format is not specified, but it is implemented by all official
19 //! protobuf implementations, including `protoc` command which can decode
20 //! and encode messages using text format.
21 
22 use core::Message;
23 use reflect::ReflectFieldRef;
24 use reflect::ReflectValueRef;
25 use std;
26 use std::fmt;
27 use std::fmt::Write;
28 
quote_bytes_to(bytes: &[u8], buf: &mut String)29 fn quote_bytes_to(bytes: &[u8], buf: &mut String) {
30     for &c in bytes {
31         match c {
32             b'\n' => buf.push_str(r"\n"),
33             b'\r' => buf.push_str(r"\r"),
34             b'\t' => buf.push_str(r"\t"),
35             b'"' => buf.push_str("\\\""),
36             b'\\' => buf.push_str(r"\\"),
37             b'\x20'..=b'\x7e' => buf.push(c as char),
38             _ => {
39                 buf.push('\\');
40                 buf.push((b'0' + (c >> 6)) as char);
41                 buf.push((b'0' + ((c >> 3) & 7)) as char);
42                 buf.push((b'0' + (c & 7)) as char);
43             }
44         }
45     }
46 }
47 
quote_escape_bytes_to(bytes: &[u8], buf: &mut String)48 fn quote_escape_bytes_to(bytes: &[u8], buf: &mut String) {
49     buf.push('"');
50     quote_bytes_to(bytes, buf);
51     buf.push('"');
52 }
53 
54 #[doc(hidden)]
quote_escape_bytes(bytes: &[u8]) -> String55 pub fn quote_escape_bytes(bytes: &[u8]) -> String {
56     let mut r = String::new();
57     quote_escape_bytes_to(bytes, &mut r);
58     r
59 }
60 
61 #[doc(hidden)]
unescape_string(string: &str) -> Vec<u8>62 pub fn unescape_string(string: &str) -> Vec<u8> {
63     fn parse_if_digit(chars: &mut std::str::Chars) -> u8 {
64         let mut copy = chars.clone();
65         let f = match copy.next() {
66             None => return 0,
67             Some(f) => f,
68         };
69         let d = match f {
70             '0'..='9' => (f as u8 - b'0'),
71             _ => return 0,
72         };
73         *chars = copy;
74         d
75     }
76 
77     fn parse_hex_digit(chars: &mut std::str::Chars) -> u8 {
78         match chars.next().unwrap() {
79             c @ '0'..='9' => (c as u8) - b'0',
80             c @ 'a'..='f' => (c as u8) - b'a' + 10,
81             c @ 'A'..='F' => (c as u8) - b'A' + 10,
82             _ => panic!("incorrect hex escape"),
83         }
84     }
85 
86     fn parse_escape_rem(chars: &mut std::str::Chars) -> u8 {
87         let n = chars.next().unwrap();
88         match n {
89             'a' => return b'\x07',
90             'b' => return b'\x08',
91             'f' => return b'\x0c',
92             'n' => return b'\n',
93             'r' => return b'\r',
94             't' => return b'\t',
95             'v' => return b'\x0b',
96             '"' => return b'"',
97             '\'' => return b'\'',
98             '0'..='9' => {
99                 let d1 = n as u8 - b'0';
100                 let d2 = parse_if_digit(chars);
101                 let d3 = parse_if_digit(chars);
102                 return (d1 * 64 + d2 * 8 + d3) as u8;
103             }
104             'x' => {
105                 let d1 = parse_hex_digit(chars);
106                 let d2 = parse_hex_digit(chars);
107                 return d1 * 16 + d2;
108             }
109             c => return c as u8, // TODO: validate ASCII
110         };
111     }
112 
113     let mut chars = string.chars();
114     let mut r = Vec::new();
115 
116     loop {
117         let f = match chars.next() {
118             None => return r,
119             Some(f) => f,
120         };
121 
122         if f == '\\' {
123             r.push(parse_escape_rem(&mut chars));
124         } else {
125             r.push(f as u8); // TODO: escape UTF-8
126         }
127     }
128 }
129 
print_str_to(s: &str, buf: &mut String)130 fn print_str_to(s: &str, buf: &mut String) {
131     // TODO: keep printable Unicode
132     quote_escape_bytes_to(s.as_bytes(), buf);
133 }
134 
do_indent(buf: &mut String, pretty: bool, indent: usize)135 fn do_indent(buf: &mut String, pretty: bool, indent: usize) {
136     if pretty && indent > 0 {
137         for _ in 0..indent {
138             buf.push_str("  ");
139         }
140     }
141 }
142 
print_start_field( buf: &mut String, pretty: bool, indent: usize, first: &mut bool, field_name: &str, )143 fn print_start_field(
144     buf: &mut String,
145     pretty: bool,
146     indent: usize,
147     first: &mut bool,
148     field_name: &str,
149 ) {
150     if !*first && !pretty {
151         buf.push_str(" ");
152     }
153     do_indent(buf, pretty, indent);
154     *first = false;
155     buf.push_str(field_name);
156 }
157 
print_end_field(buf: &mut String, pretty: bool)158 fn print_end_field(buf: &mut String, pretty: bool) {
159     if pretty {
160         buf.push_str("\n");
161     }
162 }
163 
print_field( buf: &mut String, pretty: bool, indent: usize, first: &mut bool, field_name: &str, value: ReflectValueRef, )164 fn print_field(
165     buf: &mut String,
166     pretty: bool,
167     indent: usize,
168     first: &mut bool,
169     field_name: &str,
170     value: ReflectValueRef,
171 ) {
172     print_start_field(buf, pretty, indent, first, field_name);
173 
174     match value {
175         ReflectValueRef::Message(m) => {
176             buf.push_str(" {");
177             if pretty {
178                 buf.push_str("\n");
179             }
180             print_to_internal(m, buf, pretty, indent + 1);
181             do_indent(buf, pretty, indent);
182             buf.push_str("}");
183         }
184         ReflectValueRef::Enum(e) => {
185             buf.push_str(": ");
186             buf.push_str(e.name());
187         }
188         ReflectValueRef::String(s) => {
189             buf.push_str(": ");
190             print_str_to(s, buf);
191         }
192         ReflectValueRef::Bytes(b) => {
193             buf.push_str(": ");
194             quote_escape_bytes_to(b, buf);
195         }
196         ReflectValueRef::I32(v) => {
197             write!(buf, ": {}", v).unwrap();
198         }
199         ReflectValueRef::I64(v) => {
200             write!(buf, ": {}", v).unwrap();
201         }
202         ReflectValueRef::U32(v) => {
203             write!(buf, ": {}", v).unwrap();
204         }
205         ReflectValueRef::U64(v) => {
206             write!(buf, ": {}", v).unwrap();
207         }
208         ReflectValueRef::Bool(v) => {
209             write!(buf, ": {}", v).unwrap();
210         }
211         ReflectValueRef::F32(v) => {
212             write!(buf, ": {}", v).unwrap();
213         }
214         ReflectValueRef::F64(v) => {
215             write!(buf, ": {}", v).unwrap();
216         }
217     }
218 
219     print_end_field(buf, pretty);
220 }
221 
print_to_internal(m: &Message, buf: &mut String, pretty: bool, indent: usize)222 fn print_to_internal(m: &Message, buf: &mut String, pretty: bool, indent: usize) {
223     let d = m.descriptor();
224     let mut first = true;
225     for f in d.fields() {
226         match f.get_reflect(m) {
227             ReflectFieldRef::Map(map) => {
228                 for (k, v) in map {
229                     print_start_field(buf, pretty, indent, &mut first, f.name());
230                     buf.push_str(" {");
231                     if pretty {
232                         buf.push_str("\n");
233                     }
234 
235                     let mut entry_first = true;
236 
237                     print_field(buf, pretty, indent + 1, &mut entry_first, "key", k.as_ref());
238                     print_field(
239                         buf,
240                         pretty,
241                         indent + 1,
242                         &mut entry_first,
243                         "value",
244                         v.as_ref(),
245                     );
246                     do_indent(buf, pretty, indent);
247                     buf.push_str("}");
248                     print_end_field(buf, pretty);
249                 }
250             }
251             ReflectFieldRef::Repeated(repeated) => {
252                 // TODO: do not print zeros for v3
253                 for v in repeated {
254                     print_field(buf, pretty, indent, &mut first, f.name(), v.as_ref());
255                 }
256             }
257             ReflectFieldRef::Optional(optional) => {
258                 if let Some(v) = optional {
259                     print_field(buf, pretty, indent, &mut first, f.name(), v);
260                 }
261             }
262         }
263     }
264 
265     // TODO: unknown fields
266 }
267 
268 /// Text-format
print_to(m: &Message, buf: &mut String)269 pub fn print_to(m: &Message, buf: &mut String) {
270     print_to_internal(m, buf, false, 0)
271 }
272 
print_to_string_internal(m: &Message, pretty: bool) -> String273 fn print_to_string_internal(m: &Message, pretty: bool) -> String {
274     let mut r = String::new();
275     print_to_internal(m, &mut r, pretty, 0);
276     r.to_string()
277 }
278 
279 /// Text-format
print_to_string(m: &Message) -> String280 pub fn print_to_string(m: &Message) -> String {
281     print_to_string_internal(m, false)
282 }
283 
284 /// Text-format to `fmt::Formatter`.
fmt(m: &Message, f: &mut fmt::Formatter) -> fmt::Result285 pub fn fmt(m: &Message, f: &mut fmt::Formatter) -> fmt::Result {
286     let pretty = f.alternate();
287     f.write_str(&print_to_string_internal(m, pretty))
288 }
289 
290 #[cfg(test)]
291 mod test {
292 
escape(data: &[u8]) -> String293     fn escape(data: &[u8]) -> String {
294         let mut s = String::with_capacity(data.len() * 4);
295         super::quote_bytes_to(data, &mut s);
296         s
297     }
298 
test_escape_unescape(text: &str, escaped: &str)299     fn test_escape_unescape(text: &str, escaped: &str) {
300         assert_eq!(text.as_bytes(), &super::unescape_string(escaped)[..]);
301         assert_eq!(escaped, &escape(text.as_bytes())[..]);
302     }
303 
304     #[test]
test_print_to_bytes()305     fn test_print_to_bytes() {
306         assert_eq!("ab", escape(b"ab"));
307         assert_eq!("a\\\\023", escape(b"a\\023"));
308         assert_eq!("a\\r\\n\\t '\\\"\\\\", escape(b"a\r\n\t '\"\\"));
309         assert_eq!("\\344\\275\\240\\345\\245\\275", escape("你好".as_bytes()));
310     }
311 
312     #[test]
313     fn test_unescape_string() {
314         test_escape_unescape("", "");
315         test_escape_unescape("aa", "aa");
316         test_escape_unescape("\n", "\\n");
317         test_escape_unescape("\r", "\\r");
318         test_escape_unescape("\t", "\\t");
319         test_escape_unescape("你好", "\\344\\275\\240\\345\\245\\275");
320         // hex
321         assert_eq!(b"aaa\x01bbb", &super::unescape_string("aaa\\x01bbb")[..]);
322         assert_eq!(b"aaa\xcdbbb", &super::unescape_string("aaa\\xCDbbb")[..]);
323         assert_eq!(b"aaa\xcdbbb", &super::unescape_string("aaa\\xCDbbb")[..]);
324         // quotes
325         assert_eq!(b"aaa\"bbb", &super::unescape_string("aaa\\\"bbb")[..]);
326         assert_eq!(b"aaa\'bbb", &super::unescape_string("aaa\\\'bbb")[..]);
327     }
328 }
329