• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 crate::message::Message;
23 use crate::reflect::ReflectFieldRef;
24 use crate::reflect::ReflectValueRef;
25 use std;
26 use std::fmt;
27 use std::fmt::Write;
28 
29 mod print;
30 
31 // Used by text format parser and by pure-rust codegen parsed
32 // this it is public but hidden module.
33 // https://github.com/rust-lang/rust/issues/44663
34 #[doc(hidden)]
35 pub mod lexer;
36 
37 use self::print::print_str_to;
38 #[doc(hidden)]
39 pub use self::print::quote_bytes_to;
40 #[doc(hidden)]
41 pub use self::print::quote_escape_bytes;
42 use crate::text_format::print::quote_escape_bytes_to;
43 
44 #[doc(hidden)]
unescape_string(string: &str) -> Vec<u8>45 pub fn unescape_string(string: &str) -> Vec<u8> {
46     fn parse_if_digit(chars: &mut std::str::Chars) -> u8 {
47         let mut copy = chars.clone();
48         let f = match copy.next() {
49             None => return 0,
50             Some(f) => f,
51         };
52         let d = match f {
53             '0'..='9' => (f as u8 - b'0'),
54             _ => return 0,
55         };
56         *chars = copy;
57         d
58     }
59 
60     fn parse_hex_digit(chars: &mut std::str::Chars) -> u8 {
61         match chars.next().unwrap() {
62             c @ '0'..='9' => (c as u8) - b'0',
63             c @ 'a'..='f' => (c as u8) - b'a' + 10,
64             c @ 'A'..='F' => (c as u8) - b'A' + 10,
65             _ => panic!("incorrect hex escape"),
66         }
67     }
68 
69     fn parse_escape_rem(chars: &mut std::str::Chars) -> u8 {
70         let n = chars.next().unwrap();
71         match n {
72             'a' => return b'\x07',
73             'b' => return b'\x08',
74             'f' => return b'\x0c',
75             'n' => return b'\n',
76             'r' => return b'\r',
77             't' => return b'\t',
78             'v' => return b'\x0b',
79             '"' => return b'"',
80             '\'' => return b'\'',
81             '0'..='9' => {
82                 let d1 = n as u8 - b'0';
83                 let d2 = parse_if_digit(chars);
84                 let d3 = parse_if_digit(chars);
85                 return (d1 * 64 + d2 * 8 + d3) as u8;
86             }
87             'x' => {
88                 let d1 = parse_hex_digit(chars);
89                 let d2 = parse_hex_digit(chars);
90                 return d1 * 16 + d2;
91             }
92             c => return c as u8, // TODO: validate ASCII
93         };
94     }
95 
96     let mut chars = string.chars();
97     let mut r = Vec::new();
98 
99     loop {
100         let f = match chars.next() {
101             None => return r,
102             Some(f) => f,
103         };
104 
105         if f == '\\' {
106             r.push(parse_escape_rem(&mut chars));
107         } else {
108             r.push(f as u8); // TODO: escape UTF-8
109         }
110     }
111 }
112 
do_indent(buf: &mut String, pretty: bool, indent: usize)113 fn do_indent(buf: &mut String, pretty: bool, indent: usize) {
114     if pretty && indent > 0 {
115         for _ in 0..indent {
116             buf.push_str("  ");
117         }
118     }
119 }
120 
print_start_field( buf: &mut String, pretty: bool, indent: usize, first: &mut bool, field_name: &str, )121 fn print_start_field(
122     buf: &mut String,
123     pretty: bool,
124     indent: usize,
125     first: &mut bool,
126     field_name: &str,
127 ) {
128     if !*first && !pretty {
129         buf.push_str(" ");
130     }
131     do_indent(buf, pretty, indent);
132     *first = false;
133     buf.push_str(field_name);
134 }
135 
print_end_field(buf: &mut String, pretty: bool)136 fn print_end_field(buf: &mut String, pretty: bool) {
137     if pretty {
138         buf.push_str("\n");
139     }
140 }
141 
print_field( buf: &mut String, pretty: bool, indent: usize, first: &mut bool, field_name: &str, value: ReflectValueRef, )142 fn print_field(
143     buf: &mut String,
144     pretty: bool,
145     indent: usize,
146     first: &mut bool,
147     field_name: &str,
148     value: ReflectValueRef,
149 ) {
150     print_start_field(buf, pretty, indent, first, field_name);
151 
152     match value {
153         ReflectValueRef::Message(m) => {
154             buf.push_str(" {");
155             if pretty {
156                 buf.push_str("\n");
157             }
158             print_to_internal(m, buf, pretty, indent + 1);
159             do_indent(buf, pretty, indent);
160             buf.push_str("}");
161         }
162         ReflectValueRef::Enum(e) => {
163             buf.push_str(": ");
164             buf.push_str(e.name());
165         }
166         ReflectValueRef::String(s) => {
167             buf.push_str(": ");
168             print_str_to(s, buf);
169         }
170         ReflectValueRef::Bytes(b) => {
171             buf.push_str(": ");
172             quote_escape_bytes_to(b, buf);
173         }
174         ReflectValueRef::I32(v) => {
175             write!(buf, ": {}", v).unwrap();
176         }
177         ReflectValueRef::I64(v) => {
178             write!(buf, ": {}", v).unwrap();
179         }
180         ReflectValueRef::U32(v) => {
181             write!(buf, ": {}", v).unwrap();
182         }
183         ReflectValueRef::U64(v) => {
184             write!(buf, ": {}", v).unwrap();
185         }
186         ReflectValueRef::Bool(v) => {
187             write!(buf, ": {}", v).unwrap();
188         }
189         ReflectValueRef::F32(v) => {
190             write!(buf, ": {}", v).unwrap();
191         }
192         ReflectValueRef::F64(v) => {
193             write!(buf, ": {}", v).unwrap();
194         }
195     }
196 
197     print_end_field(buf, pretty);
198 }
199 
print_to_internal(m: &dyn Message, buf: &mut String, pretty: bool, indent: usize)200 fn print_to_internal(m: &dyn Message, buf: &mut String, pretty: bool, indent: usize) {
201     let d = m.descriptor();
202     let mut first = true;
203     for f in d.fields() {
204         match f.get_reflect(m) {
205             ReflectFieldRef::Map(map) => {
206                 for (k, v) in map {
207                     print_start_field(buf, pretty, indent, &mut first, f.name());
208                     buf.push_str(" {");
209                     if pretty {
210                         buf.push_str("\n");
211                     }
212 
213                     let mut entry_first = true;
214 
215                     print_field(buf, pretty, indent + 1, &mut entry_first, "key", k.as_ref());
216                     print_field(
217                         buf,
218                         pretty,
219                         indent + 1,
220                         &mut entry_first,
221                         "value",
222                         v.as_ref(),
223                     );
224                     do_indent(buf, pretty, indent);
225                     buf.push_str("}");
226                     print_end_field(buf, pretty);
227                 }
228             }
229             ReflectFieldRef::Repeated(repeated) => {
230                 // TODO: do not print zeros for v3
231                 for v in repeated {
232                     print_field(buf, pretty, indent, &mut first, f.name(), v.as_ref());
233                 }
234             }
235             ReflectFieldRef::Optional(optional) => {
236                 if let Some(v) = optional {
237                     print_field(buf, pretty, indent, &mut first, f.name(), v);
238                 }
239             }
240         }
241     }
242 
243     // TODO: unknown fields
244 }
245 
246 /// Text-format
print_to(m: &dyn Message, buf: &mut String)247 pub fn print_to(m: &dyn Message, buf: &mut String) {
248     print_to_internal(m, buf, false, 0)
249 }
250 
print_to_string_internal(m: &dyn Message, pretty: bool) -> String251 fn print_to_string_internal(m: &dyn Message, pretty: bool) -> String {
252     let mut r = String::new();
253     print_to_internal(m, &mut r, pretty, 0);
254     r.to_string()
255 }
256 
257 /// Text-format
print_to_string(m: &dyn Message) -> String258 pub fn print_to_string(m: &dyn Message) -> String {
259     print_to_string_internal(m, false)
260 }
261 
262 /// Text-format to `fmt::Formatter`.
fmt(m: &dyn Message, f: &mut fmt::Formatter) -> fmt::Result263 pub fn fmt(m: &dyn Message, f: &mut fmt::Formatter) -> fmt::Result {
264     let pretty = f.alternate();
265     f.write_str(&print_to_string_internal(m, pretty))
266 }
267 
268 #[cfg(test)]
269 mod test {
270 
escape(data: &[u8]) -> String271     fn escape(data: &[u8]) -> String {
272         let mut s = String::with_capacity(data.len() * 4);
273         super::quote_bytes_to(data, &mut s);
274         s
275     }
276 
test_escape_unescape(text: &str, escaped: &str)277     fn test_escape_unescape(text: &str, escaped: &str) {
278         assert_eq!(text.as_bytes(), &super::unescape_string(escaped)[..]);
279         assert_eq!(escaped, &escape(text.as_bytes())[..]);
280     }
281 
282     #[test]
test_print_to_bytes()283     fn test_print_to_bytes() {
284         assert_eq!("ab", escape(b"ab"));
285         assert_eq!("a\\\\023", escape(b"a\\023"));
286         assert_eq!("a\\r\\n\\t \\'\\\"\\\\", escape(b"a\r\n\t '\"\\"));
287         assert_eq!("\\344\\275\\240\\345\\245\\275", escape("你好".as_bytes()));
288     }
289 
290     #[test]
291     fn test_unescape_string() {
292         test_escape_unescape("", "");
293         test_escape_unescape("aa", "aa");
294         test_escape_unescape("\n", "\\n");
295         test_escape_unescape("\r", "\\r");
296         test_escape_unescape("\t", "\\t");
297         test_escape_unescape("你好", "\\344\\275\\240\\345\\245\\275");
298         // hex
299         assert_eq!(b"aaa\x01bbb", &super::unescape_string("aaa\\x01bbb")[..]);
300         assert_eq!(b"aaa\xcdbbb", &super::unescape_string("aaa\\xCDbbb")[..]);
301         assert_eq!(b"aaa\xcdbbb", &super::unescape_string("aaa\\xCDbbb")[..]);
302         // quotes
303         assert_eq!(b"aaa\"bbb", &super::unescape_string("aaa\\\"bbb")[..]);
304         assert_eq!(b"aaa\'bbb", &super::unescape_string("aaa\\\'bbb")[..]);
305     }
306 }
307