• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jasonish / suricata / 22785952221

06 Mar 2026 11:16PM UTC coverage: 67.722% (-11.5%) from 79.244%
22785952221

push

github

jasonish
github-ci: add schema ordering check for yaml schema

158908 of 234646 relevant lines covered (67.72%)

6673126.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.31
/rust/src/jsonbuilder.rs
1
/* Copyright (C) 2020-2024 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17

18
//! Module for building JSON documents.
19

20
#![allow(clippy::missing_safety_doc)]
21

22
use base64::{engine::general_purpose::STANDARD, Engine};
23
use num_traits::Unsigned;
24
use std::cmp::max;
25
use std::collections::TryReserveError;
26
use std::ffi::CStr;
27
use std::os::raw::c_char;
28
use std::str::Utf8Error;
29

30
const INIT_SIZE: usize = 4096;
31

32
#[derive(Debug, PartialEq, Eq)]
33
pub enum JsonError {
34
    InvalidState,
35
    Utf8Error(Utf8Error),
36
    Memory,
37
}
38

39
impl std::error::Error for JsonError {}
40

41
impl std::fmt::Display for JsonError {
42
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
×
43
        match self {
×
44
            JsonError::InvalidState => write!(f, "invalid state"),
×
45
            JsonError::Utf8Error(ref e) => e.fmt(f),
×
46
            JsonError::Memory => write!(f, "memory error"),
×
47
        }
48
    }
×
49
}
50

51
impl From<TryReserveError> for JsonError {
52
    fn from(_: TryReserveError) -> Self {
×
53
        JsonError::Memory
×
54
    }
×
55
}
56

57
impl From<Utf8Error> for JsonError {
58
    fn from(e: Utf8Error) -> Self {
×
59
        JsonError::Utf8Error(e)
×
60
    }
×
61
}
62

63
#[derive(Clone, Debug)]
64
enum Type {
65
    Object,
66
    Array,
67
}
68

69
#[derive(Debug, Clone, Copy, PartialEq)]
70
#[repr(C)]
71
enum State {
72
    None = 0,
73
    ObjectFirst,
74
    ObjectNth,
75
    ArrayFirst,
76
    ArrayNth,
77
}
78

79
impl State {
80
    fn from_u64(v: u64) -> Result<State, JsonError> {
17,766✔
81
        let s = match v {
17,766✔
82
            0 => State::None,
×
83
            1 => State::ObjectFirst,
×
84
            2 => State::ObjectNth,
17,766✔
85
            3 => State::ArrayFirst,
×
86
            4 => State::ArrayNth,
×
87
            _ => {
88
                return Err(JsonError::InvalidState);
×
89
            }
90
        };
91
        Ok(s)
17,766✔
92
    }
17,766✔
93
}
94

95
/// A "mark" or saved state for a JsonBuilder object.
96
///
97
/// The name is full, and the types are u64 as this object is used
98
/// directly in C as well.
99
#[repr(C)]
100
pub struct JsonBuilderMark {
101
    position: u64,
102
    state_index: u64,
103
    state: u64,
104
}
105

106
#[derive(Debug, Clone)]
107
pub struct JsonBuilder {
108
    buf: String,
109
    state: Vec<State>,
110
    init_type: Type,
111
}
112

113
impl JsonBuilder {
114
    /// Returns a new JsonBuilder in object state.
115
    pub fn try_new_object() -> Result<Self, JsonError> {
2,224,864✔
116
        Self::try_new_object_with_capacity(INIT_SIZE)
2,224,864✔
117
    }
2,224,864✔
118

119
    pub fn try_new_object_with_capacity(capacity: usize) -> Result<Self, JsonError> {
2,224,864✔
120
        let mut buf = String::new();
2,224,864✔
121
        buf.try_reserve(capacity)?;
2,224,864✔
122
        buf.push('{');
2,224,864✔
123
        let mut state = Vec::new();
2,224,864✔
124
        state.try_reserve(32)?;
2,224,864✔
125
        state.extend_from_slice(&[State::None, State::ObjectFirst]);
2,224,864✔
126
        Ok(Self {
2,224,864✔
127
            buf,
2,224,864✔
128
            state,
2,224,864✔
129
            init_type: Type::Object,
2,224,864✔
130
        })
2,224,864✔
131
    }
2,224,864✔
132

133
    /// Returns a new JsonBuilder in array state.
134
    pub fn try_new_array() -> Result<Self, JsonError> {
40,334✔
135
        Self::try_new_array_with_capacity(INIT_SIZE)
40,334✔
136
    }
40,334✔
137

138
    pub fn try_new_array_with_capacity(capacity: usize) -> Result<Self, JsonError> {
40,334✔
139
        let mut buf = String::new();
40,334✔
140
        buf.try_reserve(capacity)?;
40,334✔
141
        buf.push('[');
40,334✔
142
        let mut state = Vec::new();
40,334✔
143
        state.try_reserve(32)?;
40,334✔
144
        state.extend_from_slice(&[State::None, State::ArrayFirst]);
40,334✔
145
        Ok(Self {
40,334✔
146
            buf,
40,334✔
147
            state,
40,334✔
148
            init_type: Type::Array,
40,334✔
149
        })
40,334✔
150
    }
40,334✔
151

152
    /// A wrapper around String::push that pre-allocates data return
153
    /// an error if unable to.
154
    pub fn push(&mut self, ch: char) -> Result<&mut Self, JsonError> {
144,402,984✔
155
        if self.buf.capacity() == self.buf.len() {
144,402,984✔
156
            self.buf.try_reserve(INIT_SIZE)?;
9,977✔
157
        }
144,393,007✔
158
        self.buf.push(ch);
144,402,984✔
159
        Ok(self)
144,402,984✔
160
    }
144,402,984✔
161

162
    /// A wrapper around String::push_str that pre-allocates data
163
    /// return an error if unable to.
164
    pub fn push_str(&mut self, s: &str) -> Result<&mut Self, JsonError> {
149,478,799✔
165
        if self.buf.capacity() < self.buf.len() + s.len() {
149,478,799✔
166
            self.buf.try_reserve(max(INIT_SIZE, s.len()))?;
1,727✔
167
        }
149,477,072✔
168
        self.buf.push_str(s);
149,478,799✔
169
        Ok(self)
149,478,799✔
170
    }
149,478,799✔
171

172
    // Reset the builder to its initial state, without losing
173
    // the current capacity.
174
    pub fn reset(&mut self) {
×
175
        self.buf.truncate(0);
×
176
        self.state.clear();
×
177
        match self.init_type {
×
178
            Type::Array => {
×
179
                self.buf.push('[');
×
180
                self.state
×
181
                    .extend_from_slice(&[State::None, State::ArrayFirst]);
×
182
            }
×
183
            Type::Object => {
×
184
                self.buf.push('{');
×
185
                self.state
×
186
                    .extend_from_slice(&[State::None, State::ObjectFirst]);
×
187
            }
×
188
        }
189
    }
×
190

191
    // Closes the currently open datatype (object or array).
192
    pub fn close(&mut self) -> Result<&mut Self, JsonError> {
7,084,436✔
193
        match self.current_state() {
7,084,436✔
194
            State::ObjectFirst | State::ObjectNth => {
195
                self.push('}')?;
6,423,019✔
196
                self.pop_state();
6,423,019✔
197
                Ok(self)
6,423,019✔
198
            }
199
            State::ArrayFirst | State::ArrayNth => {
200
                self.push(']')?;
661,417✔
201
                self.pop_state();
661,417✔
202
                Ok(self)
661,417✔
203
            }
204
            State::None => {
205
                debug_validate_fail!("invalid state");
206
                Err(JsonError::InvalidState)
×
207
            }
208
        }
209
    }
7,084,436✔
210

211
    // Return the current state of the JsonBuilder.
212
    fn current_state(&self) -> State {
58,626,366✔
213
        if self.state.is_empty() {
58,626,366✔
214
            State::None
×
215
        } else {
216
            self.state[self.state.len() - 1]
58,626,366✔
217
        }
218
    }
58,626,366✔
219

220
    /// Move to a new state.
221
    fn push_state(&mut self, state: State) -> Result<(), JsonError> {
4,837,384✔
222
        if self.state.len() == self.state.capacity() {
4,837,384✔
223
            self.state.try_reserve(32)?;
×
224
        }
4,837,384✔
225
        self.state.push(state);
4,837,384✔
226
        Ok(())
4,837,384✔
227
    }
4,837,384✔
228

229
    /// Go back to the previous state.
230
    fn pop_state(&mut self) {
7,084,436✔
231
        self.state.pop();
7,084,436✔
232
    }
7,084,436✔
233

234
    /// Change the current state.
235
    fn set_state(&mut self, state: State) {
7,871,225✔
236
        let n = self.state.len() - 1;
7,871,225✔
237
        self.state[n] = state;
7,871,225✔
238
    }
7,871,225✔
239

240
    pub fn get_mark(&self) -> JsonBuilderMark {
111,606✔
241
        JsonBuilderMark {
111,606✔
242
            position: self.buf.len() as u64,
111,606✔
243
            state: self.current_state() as u64,
111,606✔
244
            state_index: self.state.len() as u64,
111,606✔
245
        }
111,606✔
246
    }
111,606✔
247

248
    pub fn restore_mark(&mut self, mark: &JsonBuilderMark) -> Result<(), JsonError> {
17,766✔
249
        let state = State::from_u64(mark.state)?;
17,766✔
250
        if mark.position < (self.buf.len() as u64) && mark.state_index < (self.state.len() as u64) {
17,766✔
251
            self.buf.truncate(mark.position as usize);
17,163✔
252
            self.state.truncate(mark.state_index as usize);
17,163✔
253
            self.state[(mark.state_index as usize) - 1] = state;
17,163✔
254
        }
17,163✔
255
        Ok(())
17,766✔
256
    }
17,766✔
257

258
    /// Open an object under the given key.
259
    ///
260
    /// For example:
261
    ///     Before: {
262
    ///     After:  {"key": {
263
    pub fn open_object(&mut self, key: &str) -> Result<&mut Self, JsonError> {
3,869,207✔
264
        match self.current_state() {
3,869,207✔
265
            State::ObjectFirst => {
266
                self.push('"')?;
14,854✔
267
                self.set_state(State::ObjectNth);
14,854✔
268
            }
269
            State::ObjectNth => {
270
                self.push_str(",\"")?;
3,854,353✔
271
            }
272
            _ => {
273
                debug_validate_fail!("invalid state");
274
                return Err(JsonError::InvalidState);
×
275
            }
276
        }
277
        self.push_str(key)?;
3,869,207✔
278
        self.push_str("\":{")?;
3,869,207✔
279
        self.push_state(State::ObjectFirst)?;
3,869,207✔
280
        Ok(self)
3,869,207✔
281
    }
3,869,207✔
282

283
    /// Start an object.
284
    ///
285
    /// Like open_object but does not create the object under a key. An
286
    /// error will be returned if starting an object does not make
287
    /// sense for the current state.
288
    pub fn start_object(&mut self) -> Result<&mut Self, JsonError> {
338,690✔
289
        match self.current_state() {
338,690✔
290
            State::ArrayFirst => {}
98,257✔
291
            State::ArrayNth => {
292
                self.push(',')?;
240,433✔
293
            }
294
            _ => {
295
                debug_validate_fail!("invalid state");
296
                return Err(JsonError::InvalidState);
×
297
            }
298
        }
299
        self.push('{')?;
338,690✔
300
        self.set_state(State::ArrayNth);
338,690✔
301
        self.push_state(State::ObjectFirst)?;
338,690✔
302
        Ok(self)
338,690✔
303
    }
338,690✔
304

305
    /// Open an array under the given key.
306
    ///
307
    /// For example:
308
    ///     Before: {
309
    ///     After:  {"key": [
310
    pub fn open_array(&mut self, key: &str) -> Result<&mut Self, JsonError> {
629,487✔
311
        match self.current_state() {
629,487✔
312
            State::ObjectFirst => {}
65,593✔
313
            State::ObjectNth => {
314
                self.push(',')?;
563,894✔
315
            }
316
            _ => {
317
                debug_validate_fail!("invalid state");
318
                return Err(JsonError::InvalidState);
×
319
            }
320
        }
321
        self.push('"')?;
629,487✔
322
        self.push_str(key)?;
629,487✔
323
        self.push_str("\":[")?;
629,487✔
324
        self.set_state(State::ObjectNth);
629,487✔
325
        self.push_state(State::ArrayFirst)?;
629,487✔
326
        Ok(self)
629,487✔
327
    }
629,487✔
328

329
    /// Add a string to an array.
330
    pub fn append_string(&mut self, val: &str) -> Result<&mut Self, JsonError> {
511,570✔
331
        match self.current_state() {
511,570✔
332
            State::ArrayFirst => {
333
                self.encode_string(val)?;
379,988✔
334
                self.set_state(State::ArrayNth);
379,988✔
335
                Ok(self)
379,988✔
336
            }
337
            State::ArrayNth => {
338
                self.push(',')?;
131,582✔
339
                self.encode_string(val)?;
131,582✔
340
                Ok(self)
131,582✔
341
            }
342
            _ => {
343
                debug_validate_fail!("invalid state");
344
                Err(JsonError::InvalidState)
×
345
            }
346
        }
347
    }
511,570✔
348

349
    pub fn append_string_from_bytes(&mut self, val: &[u8]) -> Result<&mut Self, JsonError> {
56,367✔
350
        match std::str::from_utf8(val) {
56,367✔
351
            Ok(s) => self.append_string(s),
56,350✔
352
            Err(_) => self.append_string(&try_string_from_bytes(val)?),
17✔
353
        }
354
    }
56,367✔
355

356
    /// Add a string to an array.
357
    pub fn append_base64(&mut self, val: &[u8]) -> Result<&mut Self, JsonError> {
3✔
358
        match self.current_state() {
3✔
359
            State::ArrayFirst => {
360
                self.push('"')?;
2✔
361
                self.encode_base64(val)?;
2✔
362
                self.push('"')?;
2✔
363
                self.set_state(State::ArrayNth);
2✔
364
                Ok(self)
2✔
365
            }
366
            State::ArrayNth => {
367
                self.push(',')?;
1✔
368
                self.push('"')?;
1✔
369
                self.encode_base64(val)?;
1✔
370
                self.push('"')?;
1✔
371
                Ok(self)
1✔
372
            }
373
            _ => {
374
                debug_validate_fail!("invalid state");
375
                Err(JsonError::InvalidState)
×
376
            }
377
        }
378
    }
3✔
379

380
    /// Add a byte array to a JSON array encoded as hex.
381
    pub fn append_hex(&mut self, val: &[u8]) -> Result<&mut Self, JsonError> {
×
382
        match self.current_state() {
×
383
            State::ArrayFirst => {
384
                self.push('"')?;
×
385
                for i in 0..val.len() {
×
386
                    self.push(HEX[(val[i] >> 4) as usize] as char)?;
×
387
                    self.push(HEX[(val[i] & 0xf) as usize] as char)?;
×
388
                }
389
                self.push('"')?;
×
390
                self.set_state(State::ArrayNth);
×
391
                Ok(self)
×
392
            }
393
            State::ArrayNth => {
394
                self.push(',')?;
×
395
                self.push('"')?;
×
396
                for i in 0..val.len() {
×
397
                    self.push(HEX[(val[i] >> 4) as usize] as char)?;
×
398
                    self.push(HEX[(val[i] & 0xf) as usize] as char)?;
×
399
                }
400
                self.push('"')?;
×
401
                Ok(self)
×
402
            }
403
            _ => {
404
                debug_validate_fail!("invalid state");
405
                Err(JsonError::InvalidState)
×
406
            }
407
        }
408
    }
×
409

410
    /// Add an unsigned integer to an array.
411
    pub fn append_uint(&mut self, val: u64) -> Result<&mut Self, JsonError> {
98,843✔
412
        match self.current_state() {
98,843✔
413
            State::ArrayFirst => {
98,445✔
414
                self.set_state(State::ArrayNth);
98,445✔
415
            }
98,445✔
416
            State::ArrayNth => {
417
                self.push(',')?;
398✔
418
            }
419
            _ => {
420
                debug_validate_fail!("invalid state");
421
                return Err(JsonError::InvalidState);
×
422
            }
423
        }
424
        self.push_str(&val.to_string())
98,843✔
425
    }
98,843✔
426

427
    pub fn append_float(&mut self, val: f64) -> Result<&mut Self, JsonError> {
×
428
        match self.current_state() {
×
429
            State::ArrayFirst => {
×
430
                self.set_state(State::ArrayNth);
×
431
            }
×
432
            State::ArrayNth => {
433
                self.push(',')?;
×
434
            }
435
            _ => {
436
                debug_validate_fail!("invalid state");
437
                return Err(JsonError::InvalidState);
×
438
            }
439
        }
440
        self.push_float(val)?;
×
441
        Ok(self)
×
442
    }
×
443

444
    pub fn set_object(&mut self, key: &str, js: &JsonBuilder) -> Result<&mut Self, JsonError> {
79,603✔
445
        match self.current_state() {
79,603✔
446
            State::ObjectNth => {
447
                self.push(',')?;
51,398✔
448
            }
449
            State::ObjectFirst => {
28,205✔
450
                self.set_state(State::ObjectNth);
28,205✔
451
            }
28,205✔
452
            _ => {
453
                debug_validate_fail!("invalid state");
454
                return Err(JsonError::InvalidState);
×
455
            }
456
        }
457
        self.push('"')?;
79,603✔
458
        self.push_str(key)?;
79,603✔
459
        self.push_str("\":")?;
79,603✔
460
        self.push_str(&js.buf)?;
79,603✔
461
        Ok(self)
79,603✔
462
    }
79,603✔
463

464
    /// Append an object onto this array.
465
    ///
466
    /// '[' -> '[{...}'
467
    /// '[{...}' -> '[{...},{...}'
468
    pub fn append_object(&mut self, js: &JsonBuilder) -> Result<&mut Self, JsonError> {
228,141✔
469
        match self.current_state() {
228,141✔
470
            State::ArrayFirst => {
81,784✔
471
                self.set_state(State::ArrayNth);
81,784✔
472
            }
81,784✔
473
            State::ArrayNth => {
474
                self.push(',')?;
146,357✔
475
            }
476
            _ => {
477
                debug_validate_fail!("invalid state");
478
                return Err(JsonError::InvalidState);
×
479
            }
480
        }
481
        self.push_str(&js.buf)?;
228,141✔
482
        Ok(self)
228,141✔
483
    }
228,141✔
484

485
    /// Set a key and string value type on an object.
486
    #[inline(always)]
487
    pub fn set_string(&mut self, key: &str, val: &str) -> Result<&mut Self, JsonError> {
23,012,971✔
488
        match self.current_state() {
23,012,971✔
489
            State::ObjectNth => {
490
                self.push(',')?;
19,187,587✔
491
            }
492
            State::ObjectFirst => {
3,825,384✔
493
                self.set_state(State::ObjectNth);
3,825,384✔
494
            }
3,825,384✔
495
            _ => {
496
                debug_validate_fail!("invalid state");
497
                return Err(JsonError::InvalidState);
×
498
            }
499
        }
500
        self.push('"')?;
23,012,971✔
501
        self.push_str(key)?;
23,012,971✔
502
        self.push_str("\":")?;
23,012,971✔
503
        self.encode_string(val)?;
23,012,971✔
504
        Ok(self)
23,012,971✔
505
    }
23,012,971✔
506

507
    /// Set a key and a string value on an object, with a limited size
508
    pub fn set_string_limited(
707✔
509
        &mut self, key: &str, val: &str, limit: usize,
707✔
510
    ) -> Result<&mut Self, JsonError> {
707✔
511
        if val.len() > limit {
707✔
512
            // Gracefully handle splitting UTF-8 strings at arbitrary locations.
513
            // Strings in Rust are UTF-8; and a UTF-8 code point is max 4 bytes.
514
            // Hence we will find a suitable boundary within 4 bytes of any byte
515
            // position, in any direction with sufficiently long strings left.
516
            // This is an approach similar to Rust's (currently nightly unstable
517
            // only) "floor_char_boundary" str method:
518
            // https://doc.rust-lang.org/std/primitive.str.html#method.floor_char_boundary
519
            for i in 0..=std::cmp::min(limit, 4) {
2✔
520
                // We first try the requested boundary. In the expected
521
                // ("happy") case the limit is at a code point boundary so the
522
                // slice will succeed immediately. If not, we successively try
523
                // earlier positions in the string until we find a suitable
524
                // position.
525
                if let Some(valtrunc) = val.get(0..limit - i) {
2✔
526
                    let additional_bytes = val.len() - limit;
2✔
527
                    let outstr = format!(
2✔
528
                        "{valtrunc}[truncated {additional_bytes} additional byte{}]",
2✔
529
                        if additional_bytes != 1 { "s" } else { "" }
2✔
530
                    );
531
                    self.set_string(key, &outstr)?;
2✔
532
                    break;
2✔
533
                }
×
534
            }
535
        } else {
536
            self.set_string(key, val)?;
705✔
537
        }
538
        Ok(self)
707✔
539
    }
707✔
540

541
    pub fn set_formatted(&mut self, formatted: &str) -> Result<&mut Self, JsonError> {
769,011✔
542
        match self.current_state() {
769,011✔
543
            State::ObjectNth => {
544
                self.push(',')?;
230,225✔
545
            }
546
            State::ObjectFirst => {
538,786✔
547
                self.set_state(State::ObjectNth);
538,786✔
548
            }
538,786✔
549
            _ => {
550
                debug_validate_fail!("invalid state");
551
                return Err(JsonError::InvalidState);
×
552
            }
553
        }
554
        self.push_str(formatted)?;
769,011✔
555
        Ok(self)
769,011✔
556
    }
769,011✔
557

558
    /// Set a key and a string value (from bytes) on an object.
559
    pub fn set_string_from_bytes(&mut self, key: &str, val: &[u8]) -> Result<&mut Self, JsonError> {
548,455✔
560
        match std::str::from_utf8(val) {
548,455✔
561
            Ok(s) => self.set_string(key, s),
546,551✔
562
            Err(_) => self.set_string(key, &try_string_from_bytes(val)?),
1,904✔
563
        }
564
    }
548,455✔
565

566
    /// Set a key with a string value taking only ascii-printable bytes.
567
    /// Non-printable characters are replaced by a dot `.`, except
568
    /// CR and LF which are escaped the regular json way \r and \n
569
    pub fn set_print_ascii(&mut self, key: &str, val: &[u8]) -> Result<&mut Self, JsonError> {
82,868✔
570
        match self.current_state() {
82,868✔
571
            State::ObjectNth => {
572
                self.push(',')?;
82,693✔
573
            }
574
            State::ObjectFirst => {
175✔
575
                self.set_state(State::ObjectNth);
175✔
576
            }
175✔
577
            _ => {
578
                debug_validate_fail!("invalid state");
579
                return Err(JsonError::InvalidState);
×
580
            }
581
        }
582
        self.push('"')?;
82,868✔
583
        self.push_str(key)?;
82,868✔
584
        self.push_str("\":\"")?;
82,868✔
585
        for &x in val.iter() {
49,565,313✔
586
            match x {
49,565,313✔
587
                b'\r' => {
588
                    self.push_str("\\r")?;
215,738✔
589
                }
590
                b'\n'=> {
591
                    self.push_str("\\n")?;
358,247✔
592
                }
593
                b'"'=> {
594
                    self.push_str("\\\"")?;
223,502✔
595
                }
596
                b'\\'=> {
597
                    self.push_str("\\\\")?;
56,875✔
598
                }
599
                _ => {
600
                    if !x.is_ascii() || x.is_ascii_control()  {
48,710,951✔
601
                        self.push('.')?;
32,678,080✔
602
                    } else {
603
                        self.push(x as char)?;
16,032,871✔
604
                    }
605
                }
606
            }
607
        }
608
        self.push('"')?;
82,868✔
609
        Ok(self)
82,868✔
610
    }
82,868✔
611

612
    /// Set a key and a string value (from bytes) on an object, with a limited size
613
    pub fn set_string_from_bytes_limited(
1,107✔
614
        &mut self, key: &str, val: &[u8], limit: usize,
1,107✔
615
    ) -> Result<&mut Self, JsonError> {
1,107✔
616
        let mut valtrunc = Vec::new();
1,107✔
617
        let val = if val.len() > limit {
1,107✔
618
            let additional_bytes = val.len() - limit;
39✔
619
            valtrunc.extend_from_slice(&val[..limit]);
39✔
620
            valtrunc.extend_from_slice(
39✔
621
                format!(
39✔
622
                    "[truncated {additional_bytes} additional byte{}]",
39✔
623
                    if additional_bytes != 1 { "s" } else { "" }
39✔
624
                )
625
                .as_bytes(),
39✔
626
            );
39✔
627
            &valtrunc
39✔
628
        } else {
629
            val
1,068✔
630
        };
631
        match std::str::from_utf8(val) {
1,107✔
632
            Ok(s) => self.set_string(key, s),
1,054✔
633
            Err(_) => self.set_string(key, &try_string_from_bytes(val)?),
53✔
634
        }
635
    }
1,107✔
636

637
    /// Set a key and a string field as the base64 encoded string of the value.
638
    pub fn set_base64(&mut self, key: &str, val: &[u8]) -> Result<&mut Self, JsonError> {
510,854✔
639
        match self.current_state() {
510,854✔
640
            State::ObjectNth => {
641
                self.push(',')?;
510,854✔
642
            }
643
            State::ObjectFirst => {
×
644
                self.set_state(State::ObjectNth);
×
645
            }
×
646
            _ => {
647
                debug_validate_fail!("invalid state");
648
                return Err(JsonError::InvalidState);
×
649
            }
650
        }
651
        self.push('"')?;
510,854✔
652
        self.push_str(key)?;
510,854✔
653
        self.push_str("\":\"")?;
510,854✔
654
        self.encode_base64(val)?;
510,854✔
655
        self.push('"')?;
510,854✔
656

657
        Ok(self)
510,854✔
658
    }
510,854✔
659

660
    /// Set a key and a string field as the hex encoded string of the value.
661
    pub fn set_hex(&mut self, key: &str, val: &[u8]) -> Result<&mut Self, JsonError> {
21,335✔
662
        match self.current_state() {
21,335✔
663
            State::ObjectNth => {
664
                self.push(',')?;
21,275✔
665
            }
666
            State::ObjectFirst => {
60✔
667
                self.set_state(State::ObjectNth);
60✔
668
            }
60✔
669
            _ => {
670
                debug_validate_fail!("invalid state");
671
                return Err(JsonError::InvalidState);
×
672
            }
673
        }
674
        self.push('"')?;
21,335✔
675
        self.push_str(key)?;
21,335✔
676
        self.push_str("\":\"")?;
21,335✔
677
        for i in 0..val.len() {
757,529✔
678
            self.push(HEX[(val[i] >> 4) as usize] as char)?;
757,529✔
679
            self.push(HEX[(val[i] & 0xf) as usize] as char)?;
757,529✔
680
        }
681
        self.push('"')?;
21,335✔
682

683
        Ok(self)
21,335✔
684
    }
21,335✔
685

686
    /// Set a key and an unsigned integer type on an object.
687
    pub fn set_uint<T>(&mut self, key: &str, val: T) -> Result<&mut Self, JsonError>
21,061,548✔
688
    where
21,061,548✔
689
        T: Unsigned + Into<u64>,
21,061,548✔
690
    {
21,061,548✔
691
        let val: u64 = val.into();
21,061,548✔
692
        match self.current_state() {
21,061,548✔
693
            State::ObjectNth => {
694
                self.push(',')?;
19,178,932✔
695
            }
696
            State::ObjectFirst => {
1,882,616✔
697
                self.set_state(State::ObjectNth);
1,882,616✔
698
            }
1,882,616✔
699
            _ => {
700
                debug_validate_fail!("invalid state");
701
                return Err(JsonError::InvalidState);
×
702
            }
703
        }
704
        self.push('"')?;
21,061,548✔
705
        self.push_str(key)?;
21,061,548✔
706
        self.push_str("\":")?;
21,061,548✔
707
        self.push_str(&val.to_string())?;
21,061,548✔
708
        Ok(self)
21,061,548✔
709
    }
21,061,548✔
710

711
    /// Set a key and a signed integer type on an object.
712
    pub fn set_int(&mut self, key: &str, val: i64) -> Result<&mut Self, JsonError> {
40,105✔
713
        match self.current_state() {
40,105✔
714
            State::ObjectNth => {
715
                self.push(',')?;
108✔
716
            }
717
            State::ObjectFirst => {
39,997✔
718
                self.set_state(State::ObjectNth);
39,997✔
719
            }
39,997✔
720
            _ => {
721
                debug_validate_fail!("invalid state");
722
                return Err(JsonError::InvalidState);
×
723
            }
724
        }
725
        self.push('"')?;
40,105✔
726
        self.push_str(key)?;
40,105✔
727
        self.push_str("\":")?;
40,105✔
728
        self.push_str(&val.to_string())?;
40,105✔
729
        Ok(self)
40,105✔
730
    }
40,105✔
731

732
    pub fn set_float(&mut self, key: &str, val: f64) -> Result<&mut Self, JsonError> {
160✔
733
        match self.current_state() {
160✔
734
            State::ObjectNth => {
735
                self.push(',')?;
136✔
736
            }
737
            State::ObjectFirst => {
24✔
738
                self.set_state(State::ObjectNth);
24✔
739
            }
24✔
740
            _ => {
741
                debug_validate_fail!("invalid state");
742
                return Err(JsonError::InvalidState);
×
743
            }
744
        }
745
        self.push('"')?;
160✔
746
        self.push_str(key)?;
160✔
747
        self.push_str("\":")?;
160✔
748
        self.push_float(val)?;
160✔
749
        Ok(self)
160✔
750
    }
160✔
751

752
    pub fn set_bool(&mut self, key: &str, val: bool) -> Result<&mut Self, JsonError> {
175,928✔
753
        match self.current_state() {
175,928✔
754
            State::ObjectNth => {
755
                self.push(',')?;
163,200✔
756
            }
757
            State::ObjectFirst => {
12,728✔
758
                self.set_state(State::ObjectNth);
12,728✔
759
            }
12,728✔
760
            _ => {
761
                debug_validate_fail!("invalid state");
762
                return Err(JsonError::InvalidState);
×
763
            }
764
        }
765
        self.push('"')?;
175,928✔
766
        self.push_str(key)?;
175,928✔
767
        if val {
175,928✔
768
            self.push_str("\":true")?;
83,269✔
769
        } else {
770
            self.push_str("\":false")?;
92,659✔
771
        }
772
        Ok(self)
175,928✔
773
    }
175,928✔
774

775
    pub fn capacity(&self) -> usize {
×
776
        self.buf.capacity()
×
777
    }
×
778

779
    fn push_float(&mut self, val: f64) -> Result<(), JsonError> {
160✔
780
        if val.is_nan() || val.is_infinite() {
160✔
781
            self.push_str("null")?;
×
782
        } else {
783
            self.push_str(&val.to_string())?;
160✔
784
        }
785
        Ok(())
160✔
786
    }
160✔
787

788
    /// Encode a string into the buffer, escaping as needed.
789
    ///
790
    /// The string is encoded into an intermediate vector as its faster
791
    /// than building onto the buffer.
792
    ///
793
    /// TODO: Revisit this, would be nice to build directly onto the
794
    ///    existing buffer.
795
    #[inline(always)]
796
    fn encode_string(&mut self, val: &str) -> Result<(), JsonError> {
23,524,541✔
797
        let mut buf = Vec::new();
23,524,541✔
798

23,524,541✔
799
        // Start by allocating a reasonable size buffer, it will be
23,524,541✔
800
        // grown if needed.
23,524,541✔
801
        buf.try_reserve(val.len() * 2 + 2)?;
23,524,541✔
802
        buf.resize(val.len() * 2 + 2, 0);
23,524,541✔
803

23,524,541✔
804
        let mut offset = 0;
23,524,541✔
805
        let bytes = val.as_bytes();
23,524,541✔
806
        buf[offset] = b'"';
23,524,541✔
807
        offset += 1;
23,524,541✔
808
        for &x in bytes.iter() {
373,659,455✔
809
            if offset + 7 >= buf.capacity() {
373,659,455✔
810
                // We could be smarter, but just double the buffer size.
811
                buf.try_reserve(buf.capacity())?;
3,974,319✔
812
                buf.resize(buf.capacity(), 0);
3,974,319✔
813
            }
369,685,136✔
814
            let escape = ESCAPED[x as usize];
373,659,455✔
815
            if escape == 0 {
373,659,455✔
816
                buf[offset] = x;
373,341,998✔
817
                offset += 1;
373,341,998✔
818
            } else if escape == b'u' {
373,341,998✔
819
                buf[offset] = b'\\';
93,301✔
820
                offset += 1;
93,301✔
821
                buf[offset] = b'u';
93,301✔
822
                offset += 1;
93,301✔
823
                buf[offset] = b'0';
93,301✔
824
                offset += 1;
93,301✔
825
                buf[offset] = b'0';
93,301✔
826
                offset += 1;
93,301✔
827
                buf[offset] = HEX[((x >> 4) & 0xf) as usize];
93,301✔
828
                offset += 1;
93,301✔
829
                buf[offset] = HEX[(x & 0xf) as usize];
93,301✔
830
                offset += 1;
93,301✔
831
            } else {
224,156✔
832
                buf[offset] = b'\\';
224,156✔
833
                offset += 1;
224,156✔
834
                buf[offset] = escape;
224,156✔
835
                offset += 1;
224,156✔
836
            }
224,156✔
837
        }
838
        buf[offset] = b'"';
23,524,541✔
839
        offset += 1;
23,524,541✔
840
        match std::str::from_utf8(&buf[0..offset]) {
23,524,541✔
841
            Ok(s) => {
23,524,541✔
842
                self.push_str(s)?;
23,524,541✔
843
            }
844
            Err(err) => {
×
845
                let error = format!(
×
846
                    "\"UTF8-ERROR: what=[escaped string] error={} output={:02x?} input={:02x?}\"",
×
847
                    err,
×
848
                    &buf[0..offset],
×
849
                    val.as_bytes(),
×
850
                );
×
851
                self.push_str(&error)?;
×
852
            }
853
        }
854
        Ok(())
23,524,541✔
855
    }
23,524,541✔
856

857
    fn encode_base64(&mut self, val: &[u8]) -> Result<&mut Self, JsonError> {
510,857✔
858
        let encoded_len = 4 * val.len().div_ceil(3);
510,857✔
859
        if self.buf.capacity() < self.buf.len() + encoded_len {
510,857✔
860
            self.buf.try_reserve(encoded_len)?;
11,506✔
861
        }
499,351✔
862
        STANDARD.encode_string(val, &mut self.buf);
510,857✔
863
        Ok(self)
510,857✔
864
    }
510,857✔
865
}
866

867
/// A Suricata specific function to create a string from bytes when UTF-8 decoding fails.
868
///
869
/// For bytes over 0x0f, we encode as hex like "\xf2".
870
fn try_string_from_bytes(input: &[u8]) -> Result<String, JsonError> {
1,974✔
871
    let mut out = String::new();
1,974✔
872

1,974✔
873
    // Allocate enough data to handle the worst case scenario of every
1,974✔
874
    // byte needing to be presented as a byte.
1,974✔
875
    out.try_reserve(input.len() * 4)?;
1,974✔
876

877
    for b in input.iter() {
127,760✔
878
        if *b < 128 {
127,760✔
879
            out.push(*b as char);
97,005✔
880
        } else {
97,005✔
881
            out.push_str(&format!("\\x{:02x}", *b));
30,755✔
882
        }
30,755✔
883
    }
884
    return Ok(out);
1,974✔
885
}
1,974✔
886

887
#[no_mangle]
888
pub extern "C" fn SCJbNewObject() -> *mut JsonBuilder {
1,995,941✔
889
    match JsonBuilder::try_new_object() {
1,995,941✔
890
        Ok(js) => {
1,995,941✔
891
            let boxed = Box::new(js);
1,995,941✔
892
            Box::into_raw(boxed)
1,995,941✔
893
        }
894
        Err(_) => std::ptr::null_mut(),
×
895
    }
896
}
1,995,941✔
897

898
#[no_mangle]
899
pub extern "C" fn SCJbNewArray() -> *mut JsonBuilder {
24,668✔
900
    match JsonBuilder::try_new_array() {
24,668✔
901
        Ok(js) => {
24,668✔
902
            let boxed = Box::new(js);
24,668✔
903
            Box::into_raw(boxed)
24,668✔
904
        }
905
        Err(_) => std::ptr::null_mut(),
×
906
    }
907
}
24,668✔
908

909
#[no_mangle]
910
pub extern "C" fn SCJbClone(js: &mut JsonBuilder) -> *mut JsonBuilder {
×
911
    let clone = Box::new(js.clone());
×
912
    Box::into_raw(clone)
×
913
}
×
914

915
#[no_mangle]
916
pub unsafe extern "C" fn SCJbFree(js: &mut JsonBuilder) {
2,020,609✔
917
    let _ = Box::from_raw(js);
2,020,609✔
918
}
2,020,609✔
919

920
#[no_mangle]
921
pub extern "C" fn SCJbCapacity(jb: &mut JsonBuilder) -> usize {
×
922
    jb.capacity()
×
923
}
×
924

925
#[no_mangle]
926
pub extern "C" fn SCJbReset(jb: &mut JsonBuilder) {
×
927
    jb.reset();
×
928
}
×
929

930
#[no_mangle]
931
pub unsafe extern "C" fn SCJbOpenObject(js: &mut JsonBuilder, key: *const c_char) -> bool {
3,642,837✔
932
    if let Ok(s) = CStr::from_ptr(key).to_str() {
3,642,837✔
933
        js.open_object(s).is_ok()
3,642,837✔
934
    } else {
935
        false
×
936
    }
937
}
3,642,837✔
938

939
#[no_mangle]
940
pub unsafe extern "C" fn SCJbStartObject(js: &mut JsonBuilder) -> bool {
144,452✔
941
    js.start_object().is_ok()
144,452✔
942
}
144,452✔
943

944
#[no_mangle]
945
pub unsafe extern "C" fn SCJbOpenArray(js: &mut JsonBuilder, key: *const c_char) -> bool {
466,662✔
946
    if let Ok(s) = CStr::from_ptr(key).to_str() {
466,662✔
947
        js.open_array(s).is_ok()
466,662✔
948
    } else {
949
        false
×
950
    }
951
}
466,662✔
952

953
#[no_mangle]
954
pub unsafe extern "C" fn SCJbSetString(
20,787,844✔
955
    js: &mut JsonBuilder, key: *const c_char, val: *const c_char,
20,787,844✔
956
) -> bool {
20,787,844✔
957
    if val.is_null() {
20,787,844✔
958
        return false;
64,848✔
959
    }
20,722,996✔
960
    if let Ok(key) = CStr::from_ptr(key).to_str() {
20,722,996✔
961
        if let Ok(val) = CStr::from_ptr(val).to_str() {
20,722,996✔
962
            return js.set_string(key, val).is_ok();
20,722,558✔
963
        }
438✔
964
    }
×
965
    return false;
438✔
966
}
20,787,844✔
967

968
#[no_mangle]
969
pub unsafe extern "C" fn SCJbSetStringFromBytes(
216,434✔
970
    js: &mut JsonBuilder, key: *const c_char, bytes: *const u8, len: u32,
216,434✔
971
) -> bool {
216,434✔
972
    if bytes.is_null() || len == 0 {
216,434✔
973
        return false;
5,688✔
974
    }
210,746✔
975
    if let Ok(key) = CStr::from_ptr(key).to_str() {
210,746✔
976
        let val = std::slice::from_raw_parts(bytes, len as usize);
210,746✔
977
        return js.set_string_from_bytes(key, val).is_ok();
210,746✔
978
    }
×
979
    return false;
×
980
}
216,434✔
981

982
#[no_mangle]
983
pub unsafe extern "C" fn SCJbSetPrintAsciiString(
113,166✔
984
    js: &mut JsonBuilder, key: *const c_char, bytes: *const u8, len: u32,
113,166✔
985
) -> bool {
113,166✔
986
    if bytes.is_null() || len == 0 {
113,166✔
987
        return false;
30,298✔
988
    }
82,868✔
989
    if let Ok(key) = CStr::from_ptr(key).to_str() {
82,868✔
990
        let val = std::slice::from_raw_parts(bytes, len as usize);
82,868✔
991
        return js.set_print_ascii(key, val).is_ok();
82,868✔
992
    }
×
993
    return false;
×
994
}
113,166✔
995

996
#[no_mangle]
997
pub unsafe extern "C" fn SCJbSetBase64(
648,690✔
998
    js: &mut JsonBuilder, key: *const c_char, bytes: *const u8, len: u32,
648,690✔
999
) -> bool {
648,690✔
1000
    if bytes.is_null() || len == 0 {
648,690✔
1001
        return false;
137,836✔
1002
    }
510,854✔
1003
    if let Ok(key) = CStr::from_ptr(key).to_str() {
510,854✔
1004
        let val = std::slice::from_raw_parts(bytes, len as usize);
510,854✔
1005
        return js.set_base64(key, val).is_ok();
510,854✔
1006
    }
×
1007
    return false;
×
1008
}
648,690✔
1009

1010
#[no_mangle]
1011
pub unsafe extern "C" fn SCJbSetHex(
16,591✔
1012
    js: &mut JsonBuilder, key: *const c_char, bytes: *const u8, len: u32,
16,591✔
1013
) -> bool {
16,591✔
1014
    if bytes.is_null() || len == 0 {
16,591✔
1015
        return false;
×
1016
    }
16,591✔
1017
    if let Ok(key) = CStr::from_ptr(key).to_str() {
16,591✔
1018
        let val = std::slice::from_raw_parts(bytes, len as usize);
16,591✔
1019
        return js.set_hex(key, val).is_ok();
16,591✔
1020
    }
×
1021
    return false;
×
1022
}
16,591✔
1023

1024
#[no_mangle]
1025
pub unsafe extern "C" fn SCJbSetFormatted(js: &mut JsonBuilder, formatted: *const c_char) -> bool {
769,011✔
1026
    if let Ok(formatted) = CStr::from_ptr(formatted).to_str() {
769,011✔
1027
        return js.set_formatted(formatted).is_ok();
769,011✔
1028
    }
×
1029
    return false;
×
1030
}
769,011✔
1031

1032
#[no_mangle]
1033
pub unsafe extern "C" fn SCJbAppendObject(jb: &mut JsonBuilder, obj: &JsonBuilder) -> bool {
496✔
1034
    jb.append_object(obj).is_ok()
496✔
1035
}
496✔
1036

1037
#[no_mangle]
1038
pub unsafe extern "C" fn SCJbSetObject(
62,659✔
1039
    js: &mut JsonBuilder, key: *const c_char, val: &mut JsonBuilder,
62,659✔
1040
) -> bool {
62,659✔
1041
    if let Ok(key) = CStr::from_ptr(key).to_str() {
62,659✔
1042
        return js.set_object(key, val).is_ok();
62,659✔
1043
    }
×
1044
    return false;
×
1045
}
62,659✔
1046

1047
#[no_mangle]
1048
pub unsafe extern "C" fn SCJbAppendString(js: &mut JsonBuilder, val: *const c_char) -> bool {
409,327✔
1049
    if val.is_null() {
409,327✔
1050
        return false;
×
1051
    }
409,327✔
1052
    if let Ok(val) = CStr::from_ptr(val).to_str() {
409,327✔
1053
        return js.append_string(val).is_ok();
409,325✔
1054
    }
2✔
1055
    return false;
2✔
1056
}
409,327✔
1057

1058
#[no_mangle]
1059
pub unsafe extern "C" fn SCJbAppendStringFromBytes(
32,928✔
1060
    js: &mut JsonBuilder, bytes: *const u8, len: u32,
32,928✔
1061
) -> bool {
32,928✔
1062
    if bytes.is_null() || len == 0 {
32,928✔
1063
        return false;
×
1064
    }
32,928✔
1065
    let val = std::slice::from_raw_parts(bytes, len as usize);
32,928✔
1066
    return js.append_string_from_bytes(val).is_ok();
32,928✔
1067
}
32,928✔
1068

1069
#[no_mangle]
1070
pub unsafe extern "C" fn SCJbAppendBase64(
3✔
1071
    js: &mut JsonBuilder, bytes: *const u8, len: u32,
3✔
1072
) -> bool {
3✔
1073
    if bytes.is_null() || len == 0 {
3✔
1074
        return false;
×
1075
    }
3✔
1076
    let val = std::slice::from_raw_parts(bytes, len as usize);
3✔
1077
    return js.append_base64(val).is_ok();
3✔
1078
}
3✔
1079

1080
#[no_mangle]
1081
pub unsafe extern "C" fn SCJbAppendUint(js: &mut JsonBuilder, val: u64) -> bool {
98,682✔
1082
    return js.append_uint(val).is_ok();
98,682✔
1083
}
98,682✔
1084

1085
#[no_mangle]
1086
pub unsafe extern "C" fn SCJbAppendFloat(js: &mut JsonBuilder, val: f64) -> bool {
×
1087
    return js.append_float(val).is_ok();
×
1088
}
×
1089

1090
#[no_mangle]
1091
pub unsafe extern "C" fn SCJbSetUint(js: &mut JsonBuilder, key: *const c_char, val: u64) -> bool {
19,809,532✔
1092
    if let Ok(key) = CStr::from_ptr(key).to_str() {
19,809,532✔
1093
        return js.set_uint(key, val).is_ok();
19,809,532✔
1094
    }
×
1095
    return false;
×
1096
}
19,809,532✔
1097

1098
#[no_mangle]
1099
pub unsafe extern "C" fn SCJbSetInt(js: &mut JsonBuilder, key: *const c_char, val: i64) -> bool {
563✔
1100
    if let Ok(key) = CStr::from_ptr(key).to_str() {
563✔
1101
        return js.set_int(key, val).is_ok();
563✔
1102
    }
×
1103
    return false;
×
1104
}
563✔
1105

1106
#[no_mangle]
1107
pub unsafe extern "C" fn SCJbSetFloat(js: &mut JsonBuilder, key: *const c_char, val: f64) -> bool {
160✔
1108
    if let Ok(key) = CStr::from_ptr(key).to_str() {
160✔
1109
        return js.set_float(key, val).is_ok();
160✔
1110
    }
×
1111
    return false;
×
1112
}
160✔
1113

1114
#[no_mangle]
1115
pub unsafe extern "C" fn SCJbSetBool(js: &mut JsonBuilder, key: *const c_char, val: bool) -> bool {
100,837✔
1116
    if let Ok(key) = CStr::from_ptr(key).to_str() {
100,837✔
1117
        return js.set_bool(key, val).is_ok();
100,837✔
1118
    }
×
1119
    return false;
×
1120
}
100,837✔
1121

1122
#[no_mangle]
1123
pub unsafe extern "C" fn SCJbClose(js: &mut JsonBuilder) -> bool {
6,269,193✔
1124
    js.close().is_ok()
6,269,193✔
1125
}
6,269,193✔
1126

1127
#[no_mangle]
1128
pub unsafe extern "C" fn SCJbLen(js: &JsonBuilder) -> usize {
1,959,081✔
1129
    js.buf.len()
1,959,081✔
1130
}
1,959,081✔
1131

1132
#[no_mangle]
1133
pub unsafe extern "C" fn SCJbPtr(js: &mut JsonBuilder) -> *const u8 {
1,956,871✔
1134
    js.buf.as_ptr()
1,956,871✔
1135
}
1,956,871✔
1136

1137
#[no_mangle]
1138
pub unsafe extern "C" fn SCJbGetMark(js: &mut JsonBuilder, mark: &mut JsonBuilderMark) {
82,850✔
1139
    let m = js.get_mark();
82,850✔
1140
    mark.position = m.position;
82,850✔
1141
    mark.state_index = m.state_index;
82,850✔
1142
    mark.state = m.state;
82,850✔
1143
}
82,850✔
1144

1145
#[no_mangle]
1146
pub unsafe extern "C" fn SCJbRestoreMark(js: &mut JsonBuilder, mark: &mut JsonBuilderMark) -> bool {
4,989✔
1147
    js.restore_mark(mark).is_ok()
4,989✔
1148
}
4,989✔
1149

1150
#[cfg(test)]
1151
mod test {
1152
    use super::*;
1153

1154
    #[test]
1155
    fn test_try_reserve() {
1156
        // Just a sanity check that try_reserve works as I expect.
1157
        let mut buf = String::new();
1158
        assert_eq!(buf.len(), 0);
1159
        assert_eq!(buf.capacity(), 0);
1160

1161
        buf.try_reserve(1).unwrap();
1162
        assert_eq!(buf.len(), 0);
1163
        assert!(buf.capacity() >= 1);
1164
    }
1165

1166
    #[test]
1167
    fn test_set_bool() {
1168
        let mut jb = JsonBuilder::try_new_object().unwrap();
1169
        jb.set_bool("first", true).unwrap();
1170
        assert_eq!(jb.buf, r#"{"first":true"#);
1171
        jb.set_bool("second", false).unwrap();
1172
        assert_eq!(jb.buf, r#"{"first":true,"second":false"#);
1173

1174
        let mut jb = JsonBuilder::try_new_object().unwrap();
1175
        jb.set_bool("first", false).unwrap();
1176
        assert_eq!(jb.buf, r#"{"first":false"#);
1177
        jb.set_bool("second", true).unwrap();
1178
        assert_eq!(jb.buf, r#"{"first":false,"second":true"#);
1179
    }
1180

1181
    #[test]
1182
    fn test_object_in_object() -> Result<(), JsonError> {
1183
        let mut js = JsonBuilder::try_new_object().unwrap();
1184

1185
        js.open_object("object")?;
1186
        assert_eq!(js.current_state(), State::ObjectFirst);
1187
        assert_eq!(js.buf, r#"{"object":{"#);
1188

1189
        js.set_string("one", "one")?;
1190
        assert_eq!(js.current_state(), State::ObjectNth);
1191
        assert_eq!(js.buf, r#"{"object":{"one":"one""#);
1192

1193
        js.close()?;
1194
        assert_eq!(js.current_state(), State::ObjectNth);
1195
        assert_eq!(js.buf, r#"{"object":{"one":"one"}"#);
1196

1197
        js.close()?;
1198
        assert_eq!(js.current_state(), State::None);
1199
        assert_eq!(js.buf, r#"{"object":{"one":"one"}}"#);
1200

1201
        Ok(())
1202
    }
1203

1204
    #[test]
1205
    fn test_empty_array_in_object() -> Result<(), JsonError> {
1206
        let mut js = JsonBuilder::try_new_object().unwrap();
1207

1208
        js.open_array("array")?;
1209
        assert_eq!(js.current_state(), State::ArrayFirst);
1210

1211
        js.close()?;
1212
        assert_eq!(js.current_state(), State::ObjectNth);
1213
        assert_eq!(js.buf, r#"{"array":[]"#);
1214

1215
        js.close()?;
1216
        assert_eq!(js.buf, r#"{"array":[]}"#);
1217

1218
        Ok(())
1219
    }
1220

1221
    #[test]
1222
    #[cfg(not(feature = "debug-validate"))]
1223
    fn test_array_in_object() -> Result<(), JsonError> {
1224
        let mut js = JsonBuilder::try_new_object().unwrap();
1225

1226
        // Attempt to add an item, should fail.
1227
        assert_eq!(
1228
            js.append_string("will fail").err().unwrap(),
1229
            JsonError::InvalidState
1230
        );
1231

1232
        js.open_array("array")?;
1233
        assert_eq!(js.current_state(), State::ArrayFirst);
1234

1235
        js.append_string("one")?;
1236
        assert_eq!(js.current_state(), State::ArrayNth);
1237
        assert_eq!(js.buf, r#"{"array":["one""#);
1238

1239
        js.append_string("two")?;
1240
        assert_eq!(js.current_state(), State::ArrayNth);
1241
        assert_eq!(js.buf, r#"{"array":["one","two""#);
1242

1243
        js.append_uint(3)?;
1244
        assert_eq!(js.current_state(), State::ArrayNth);
1245
        assert_eq!(js.buf, r#"{"array":["one","two",3"#);
1246

1247
        js.close()?;
1248
        assert_eq!(js.current_state(), State::ObjectNth);
1249
        assert_eq!(js.buf, r#"{"array":["one","two",3]"#);
1250

1251
        js.close()?;
1252
        assert_eq!(js.current_state(), State::None);
1253
        assert_eq!(js.buf, r#"{"array":["one","two",3]}"#);
1254

1255
        Ok(())
1256
    }
1257

1258
    #[test]
1259
    fn basic_test() -> Result<(), JsonError> {
1260
        let mut js = JsonBuilder::try_new_object().unwrap();
1261
        assert_eq!(js.current_state(), State::ObjectFirst);
1262
        assert_eq!(js.buf, "{");
1263

1264
        js.set_string("one", "one")?;
1265
        assert_eq!(js.current_state(), State::ObjectNth);
1266
        assert_eq!(js.buf, r#"{"one":"one""#);
1267

1268
        js.set_string("two", "two")?;
1269
        assert_eq!(js.current_state(), State::ObjectNth);
1270
        assert_eq!(js.buf, r#"{"one":"one","two":"two""#);
1271

1272
        js.set_uint("three", 3u8)?;
1273

1274
        js.close()?;
1275
        assert_eq!(js.current_state(), State::None);
1276
        assert_eq!(js.buf, r#"{"one":"one","two":"two","three":3}"#);
1277

1278
        Ok(())
1279
    }
1280

1281
    #[test]
1282
    fn test_combine() -> Result<(), JsonError> {
1283
        let mut main = JsonBuilder::try_new_object().unwrap();
1284
        let mut obj = JsonBuilder::try_new_object().unwrap();
1285
        obj.close()?;
1286

1287
        let mut array = JsonBuilder::try_new_array().unwrap();
1288
        array.append_string("one")?;
1289
        array.append_uint(2)?;
1290
        array.close()?;
1291
        main.set_object("object", &obj)?;
1292
        main.set_object("array", &array)?;
1293
        main.close()?;
1294

1295
        assert_eq!(main.buf, r#"{"object":{},"array":["one",2]}"#);
1296

1297
        Ok(())
1298
    }
1299

1300
    #[test]
1301
    fn test_objects_in_array() -> Result<(), JsonError> {
1302
        let mut js = JsonBuilder::try_new_array()?;
1303
        assert_eq!(js.buf, r#"["#);
1304

1305
        js.start_object()?;
1306
        assert_eq!(js.buf, r#"[{"#);
1307

1308
        js.set_string("uid", "0")?;
1309
        assert_eq!(js.buf, r#"[{"uid":"0""#);
1310

1311
        js.close()?;
1312
        assert_eq!(js.buf, r#"[{"uid":"0"}"#);
1313

1314
        js.start_object()?;
1315
        assert_eq!(js.buf, r#"[{"uid":"0"},{"#);
1316

1317
        js.set_string("username", "root")?;
1318
        assert_eq!(js.buf, r#"[{"uid":"0"},{"username":"root""#);
1319

1320
        js.close()?;
1321
        assert_eq!(js.buf, r#"[{"uid":"0"},{"username":"root"}"#);
1322

1323
        js.close()?;
1324
        assert_eq!(js.buf, r#"[{"uid":"0"},{"username":"root"}]"#);
1325

1326
        Ok(())
1327
    }
1328

1329
    #[test]
1330
    fn test_grow() -> Result<(), JsonError> {
1331
        let mut jb = JsonBuilder::try_new_object_with_capacity(1).unwrap();
1332

1333
        // For efficiency reasons, more capacity may be allocated than
1334
        // requested.
1335
        assert!(jb.capacity() > 0);
1336
        let capacity = jb.capacity();
1337

1338
        let mut value = String::new();
1339
        for i in 0..capacity {
1340
            value.push_str((i % 10).to_string().as_str());
1341
        }
1342
        jb.set_string("foo", &value)?;
1343
        assert!(jb.capacity() > capacity);
1344
        Ok(())
1345
    }
1346

1347
    #[test]
1348
    fn test_reset() -> Result<(), JsonError> {
1349
        let mut jb = JsonBuilder::try_new_object().unwrap();
1350
        assert_eq!(jb.buf, "{");
1351
        jb.set_string("foo", "bar")?;
1352
        let cap = jb.capacity();
1353
        jb.reset();
1354
        assert_eq!(jb.buf, "{");
1355
        assert_eq!(jb.capacity(), cap);
1356
        Ok(())
1357
    }
1358

1359
    #[test]
1360
    fn test_append_string_from_bytes() -> Result<(), JsonError> {
1361
        let mut jb = JsonBuilder::try_new_array().unwrap();
1362
        let s = &[0x41, 0x41, 0x41, 0x00];
1363
        jb.append_string_from_bytes(s)?;
1364
        assert_eq!(jb.buf, r#"["AAA\u0000""#);
1365

1366
        let s = &[0x00, 0x01, 0x02, 0x03];
1367
        let mut jb = JsonBuilder::try_new_array().unwrap();
1368
        jb.append_string_from_bytes(s)?;
1369
        assert_eq!(jb.buf, r#"["\u0000\u0001\u0002\u0003""#);
1370

1371
        Ok(())
1372
    }
1373

1374
    #[test]
1375
    fn test_set_string_from_bytes() {
1376
        let mut jb = JsonBuilder::try_new_object().unwrap();
1377
        jb.set_string_from_bytes("first", &[]).unwrap();
1378
        assert_eq!(jb.buf, r#"{"first":"""#);
1379
        jb.set_string_from_bytes("second", &[]).unwrap();
1380
        assert_eq!(jb.buf, r#"{"first":"","second":"""#);
1381
    }
1382

1383
    #[test]
1384
    fn test_append_string_from_bytes_grow() -> Result<(), JsonError> {
1385
        let s = &[0x00, 0x01, 0x02, 0x03];
1386
        let mut jb = JsonBuilder::try_new_array().unwrap();
1387
        jb.append_string_from_bytes(s)?;
1388

1389
        for i in 1..1000 {
1390
            let mut s = Vec::new();
1391
            s.resize(i, 0x41);
1392
            let mut jb = JsonBuilder::try_new_array().unwrap();
1393
            jb.append_string_from_bytes(&s)?;
1394
        }
1395

1396
        Ok(())
1397
    }
1398

1399
    #[test]
1400
    fn test_set_string_limited() {
1401
        let mut jb = JsonBuilder::try_new_object().unwrap();
1402
        jb.set_string_limited("val", "foobar", 10).unwrap();
1403
        assert_eq!(jb.buf, r#"{"val":"foobar""#);
1404
        jb.reset();
1405
        jb.set_string_limited("val", "foobar", 2).unwrap();
1406
        assert_eq!(jb.buf, r#"{"val":"fo[truncated 4 additional bytes]""#);
1407
        jb.reset();
1408
        jb.set_string_limited("val", "foobar", 0).unwrap();
1409
        assert_eq!(jb.buf, r#"{"val":"[truncated 6 additional bytes]""#);
1410
        jb.reset();
1411
        let unicode_str = "Hello, 世界! 👋😊";
1412
        // invalid unicode boundary, naive access should panic
1413
        let result = std::panic::catch_unwind(|| _ = unicode_str[..9]);
1414
        assert!(result.is_err());
1415
        // our code should just skip the incomplete character
1416
        jb.set_string_limited("val", unicode_str, 9).unwrap();
1417
        assert_eq!(jb.buf, r#"{"val":"Hello, [truncated 14 additional bytes]""#);
1418
        jb.reset();
1419
        // valid unicode boundary, naive access should not panic
1420
        let result = std::panic::catch_unwind(|| _ = unicode_str[..10]);
1421
        assert!(result.is_ok());
1422
        jb.set_string_limited("val", unicode_str, 10).unwrap();
1423
        assert_eq!(
1424
            jb.buf,
1425
            r#"{"val":"Hello, 世[truncated 13 additional bytes]""#
1426
        );
1427
        jb.reset();
1428
        let unicode_str2 = "世";
1429
        // this character has three UTF-8 bytes
1430
        assert_eq!(
1431
            unicode_str2,
1432
            std::str::from_utf8(&[0xE4, 0xB8, 0x96]).unwrap()
1433
        );
1434
        let result = std::panic::catch_unwind(|| _ = unicode_str2[..1]);
1435
        assert!(result.is_err());
1436
        jb.set_string_limited("val", unicode_str2, 1).unwrap();
1437
        assert_eq!(jb.buf, r#"{"val":"[truncated 2 additional bytes]""#);
1438
        jb.reset();
1439
        jb.set_string_limited("val", unicode_str2, 2).unwrap();
1440
        assert_eq!(jb.buf, r#"{"val":"[truncated 1 additional byte]""#);
1441
        jb.reset();
1442
        // with limit 3 or more we should include it in the log
1443
        jb.set_string_limited("val", unicode_str2, 3).unwrap();
1444
        assert_eq!(jb.buf, r#"{"val":"世""#);
1445
        jb.reset();
1446
        jb.set_string_limited("val", unicode_str2, 4).unwrap();
1447
        assert_eq!(jb.buf, r#"{"val":"世""#);
1448
        jb.reset();
1449
        jb.set_string_limited("val", unicode_str2, 0).unwrap();
1450
        assert_eq!(jb.buf, r#"{"val":"[truncated 3 additional bytes]""#);
1451
        let unicode_str3 = "🏴󠁧󠁢󠁷󠁬󠁳󠁿";
1452
        // this character consists of multiple code points
1453
        jb.reset();
1454
        jb.set_string_limited("val", unicode_str3, 7).unwrap();
1455
        assert_eq!(jb.buf, r#"{"val":"🏴[truncated 21 additional bytes]""#);
1456
        jb.reset();
1457
        jb.set_string_limited("val", unicode_str3, 2).unwrap();
1458
        assert_eq!(jb.buf, r#"{"val":"[truncated 26 additional bytes]""#);
1459
    }
1460

1461
    #[test]
1462
    fn test_set_string_from_bytes_limited() {
1463
        let mut jb = JsonBuilder::try_new_object().unwrap();
1464
        jb.set_string_from_bytes_limited("first", b"foobar", 10)
1465
            .unwrap();
1466
        assert_eq!(jb.buf, r#"{"first":"foobar""#);
1467
        jb.set_string_from_bytes_limited("second", b"foobar", 2)
1468
            .unwrap();
1469
        assert_eq!(
1470
            jb.buf,
1471
            r#"{"first":"foobar","second":"fo[truncated 4 additional bytes]""#
1472
        );
1473
        jb.set_string_from_bytes_limited("third", b"foobar", 0)
1474
            .unwrap();
1475
        assert_eq!(
1476
            jb.buf,
1477
            r#"{"first":"foobar","second":"fo[truncated 4 additional bytes]","third":"[truncated 6 additional bytes]""#
1478
        );
1479
    }
1480

1481
    #[test]
1482
    fn test_invalid_utf8() {
1483
        let mut jb = JsonBuilder::try_new_object().unwrap();
1484
        jb.set_string_from_bytes("invalid", &[0xf0, 0xf1, 0xf2])
1485
            .unwrap();
1486
        assert_eq!(jb.buf, r#"{"invalid":"\\xf0\\xf1\\xf2""#);
1487

1488
        let mut jb = JsonBuilder::try_new_array().unwrap();
1489
        jb.append_string_from_bytes(&[0xf0, 0xf1, 0xf2]).unwrap();
1490
        assert_eq!(jb.buf, r#"["\\xf0\\xf1\\xf2""#);
1491
    }
1492

1493
    #[test]
1494
    fn test_marks() {
1495
        let mut jb = JsonBuilder::try_new_object().unwrap();
1496
        jb.set_string("foo", "bar").unwrap();
1497
        assert_eq!(jb.buf, r#"{"foo":"bar""#);
1498
        assert_eq!(jb.current_state(), State::ObjectNth);
1499
        assert_eq!(jb.state.len(), 2);
1500
        let mark = jb.get_mark();
1501

1502
        // Mutate such that states are transitioned.
1503
        jb.open_array("bar").unwrap();
1504
        jb.start_object().unwrap();
1505
        assert_eq!(jb.buf, r#"{"foo":"bar","bar":[{"#);
1506
        assert_eq!(jb.current_state(), State::ObjectFirst);
1507
        assert_eq!(jb.state.len(), 4);
1508

1509
        // Restore to mark.
1510
        jb.restore_mark(&mark).unwrap();
1511
        assert_eq!(jb.buf, r#"{"foo":"bar""#);
1512
        assert_eq!(jb.current_state(), State::ObjectNth);
1513
        assert_eq!(jb.state.len(), 2);
1514
    }
1515

1516
    #[test]
1517
    fn test_set_formatted() {
1518
        let mut jb = JsonBuilder::try_new_object().unwrap();
1519
        jb.set_formatted("\"foo\":\"bar\"").unwrap();
1520
        assert_eq!(jb.buf, r#"{"foo":"bar""#);
1521
        jb.set_formatted("\"bar\":\"foo\"").unwrap();
1522
        assert_eq!(jb.buf, r#"{"foo":"bar","bar":"foo""#);
1523
        jb.close().unwrap();
1524
        assert_eq!(jb.buf, r#"{"foo":"bar","bar":"foo"}"#);
1525
    }
1526

1527
    #[test]
1528
    fn test_set_float() {
1529
        let mut jb = JsonBuilder::try_new_object().unwrap();
1530
        jb.set_float("one", 1.1).unwrap();
1531
        jb.set_float("two", 2.2).unwrap();
1532
        jb.close().unwrap();
1533
        assert_eq!(jb.buf, r#"{"one":1.1,"two":2.2}"#);
1534
    }
1535

1536
    #[test]
1537
    fn test_append_float() {
1538
        let mut jb = JsonBuilder::try_new_array().unwrap();
1539
        jb.append_float(1.1).unwrap();
1540
        jb.append_float(2.2).unwrap();
1541
        jb.close().unwrap();
1542
        assert_eq!(jb.buf, r#"[1.1,2.2]"#);
1543
    }
1544

1545
    #[test]
1546
    fn test_set_nan() {
1547
        let mut jb = JsonBuilder::try_new_object().unwrap();
1548
        jb.set_float("nan", f64::NAN).unwrap();
1549
        jb.close().unwrap();
1550
        assert_eq!(jb.buf, r#"{"nan":null}"#);
1551
    }
1552

1553
    #[test]
1554
    fn test_append_nan() {
1555
        let mut jb = JsonBuilder::try_new_array().unwrap();
1556
        jb.append_float(f64::NAN).unwrap();
1557
        jb.close().unwrap();
1558
        assert_eq!(jb.buf, r#"[null]"#);
1559
    }
1560

1561
    #[test]
1562
    fn test_set_inf() {
1563
        let mut jb = JsonBuilder::try_new_object().unwrap();
1564
        jb.set_float("inf", f64::INFINITY).unwrap();
1565
        jb.close().unwrap();
1566
        assert_eq!(jb.buf, r#"{"inf":null}"#);
1567

1568
        let mut jb = JsonBuilder::try_new_object().unwrap();
1569
        jb.set_float("inf", f64::NEG_INFINITY).unwrap();
1570
        jb.close().unwrap();
1571
        assert_eq!(jb.buf, r#"{"inf":null}"#);
1572
    }
1573

1574
    #[test]
1575
    fn test_append_inf() {
1576
        let mut jb = JsonBuilder::try_new_array().unwrap();
1577
        jb.append_float(f64::INFINITY).unwrap();
1578
        jb.close().unwrap();
1579
        assert_eq!(jb.buf, r#"[null]"#);
1580

1581
        let mut jb = JsonBuilder::try_new_array().unwrap();
1582
        jb.append_float(f64::NEG_INFINITY).unwrap();
1583
        jb.close().unwrap();
1584
        assert_eq!(jb.buf, r#"[null]"#);
1585
    }
1586
}
1587

1588
// Escape table as seen in serde-json (MIT/Apache license)
1589

1590
const QU: u8 = b'"';
1591
const BS: u8 = b'\\';
1592
const BB: u8 = b'b';
1593
const TT: u8 = b't';
1594
const NN: u8 = b'n';
1595
const FF: u8 = b'f';
1596
const RR: u8 = b'r';
1597
const UU: u8 = b'u';
1598
const __: u8 = 0;
1599

1600
// Look up table for characters that need escaping in a product string
1601
static ESCAPED: [u8; 256] = [
1602
    // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
1603
    UU, UU, UU, UU, UU, UU, UU, UU, BB, TT, NN, UU, FF, RR, UU, UU, // 0
1604
    UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, // 1
1605
    __, __, QU, __, __, __, __, __, __, __, __, __, __, __, __, __, // 2
1606
    __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 3
1607
    __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 4
1608
    __, __, __, __, __, __, __, __, __, __, __, __, BS, __, __, __, // 5
1609
    __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 6
1610
    __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7
1611
    __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8
1612
    __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9
1613
    __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // A
1614
    __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // B
1615
    __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // C
1616
    __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // D
1617
    __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // E
1618
    __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F
1619
];
1620

1621
pub static HEX: [u8; 16] = [
1622
    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd', b'e', b'f',
1623
];
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc