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