1extern crate log;
40#[macro_use]
41extern crate num_derive;
42extern crate num_traits;
43
44use std::collections::HashMap;
45use std::io::{Cursor, Error, ErrorKind, Read};
46
47use byteorder::ReadBytesExt;
48use log::{debug, trace, warn};
49use num_traits::FromPrimitive;
50
51use elements::{JsonBaseValue, JsonValue, Object};
52
53pub mod elements;
54
55#[derive(Debug)]
58pub struct QJSONDocument {
59 pub tag: u32,
61 pub version: u32,
63 pub base: JsonBaseValue,
66}
67
68#[derive(Debug, Eq, PartialEq, FromPrimitive)]
70#[repr(u32)]
71enum QTValueType {
72 Null = 0x0,
74 Bool = 0x1,
76 Double = 0x2,
78 String = 0x3,
80 Array = 0x4,
82 Object = 0x5,
84 Undefined = 0x80,
86}
87
88const QT_JSON_TAG: u32 =
89 (('s' as u32) << 24) | (('j' as u32) << 16) | (('b' as u32) << 8) | ('q' as u32);
90
91pub type Endianess = byteorder::LittleEndian;
92
93impl QJSONDocument {
94 pub fn from_binary(data: Vec<u8>) -> Result<Self, Error> {
96 debug!("[QBJS] Loading data");
97
98 let mut reader = Cursor::new(&data);
99
100 let tag = reader.read_u32::<Endianess>()?;
101 let version = reader.read_u32::<Endianess>()?;
102
103 assert_eq!(tag, QT_JSON_TAG);
104
105 assert_eq!(version, 1);
106
107 debug!("QBJS Version: {}", version);
108
109 let elem = Self::load_element(data[8..].to_vec())?;
110
111 let base = match elem {
112 JsonValue::Object(o) => JsonBaseValue::Object(o),
113 JsonValue::Array(a) => JsonBaseValue::Array(a),
114 _ => {
115 return Err(Error::new(
116 ErrorKind::InvalidData,
117 "The Base must be either an Array or object",
118 ));
119 }
120 };
121
122 let doc = QJSONDocument { tag, version, base };
123
124 debug!("[QBJS] Parsing finished!");
125
126 Ok(doc)
127 }
128
129 fn load_element(data: Vec<u8>) -> Result<JsonValue, Error> {
131 let mut reader = Cursor::new(&data);
132
133 let size = reader.read_u32::<Endianess>()?;
134 let header = reader.read_u32::<Endianess>()?;
135 let offset = reader.read_u32::<Endianess>()?;
136
137 let is_object = (header & 0x1) == 1;
138 let len = header >> 1;
139
140 trace!("Element Size is: {:#0X}", size);
141 trace!("Element Offset is: {:#0X}", offset);
142 trace!("Element is an object: {}", is_object);
143 trace!("Element elements: {}", len);
144
145 let table = data.split_at(offset as usize).1;
146
147 trace!("Table len is {}", table.len() / 4);
149
150 let base = match is_object {
151 true => Self::load_object(&data, table, len, size),
152 false => Self::load_array(&data, table, len, size),
153 };
154
155 trace!("{:?}", base);
156
157 base
158 }
159
160 fn load_object(data: &[u8], offsets: &[u8], len: u32, size: u32) -> Result<JsonValue, Error> {
164 debug!("Loading object ..");
165 trace!("Expected len: {}", len);
166 trace!("Actual len: {}", offsets.len() / 4);
167
168 if offsets.len() / 4 < (len as usize) {
169 return Err(Error::new(
170 ErrorKind::InvalidData,
171 format!(
172 "The object is not the expected size, expected: {}, provided: {}",
173 len,
174 offsets.len() / 4
175 ),
176 ));
177 }
178
179 let mut offsets = Cursor::new(offsets);
180 let mut values = HashMap::new();
181
182 for i in 0..len {
183 trace!("Iterating over entry {}", i);
184
185 let offset = offsets.read_u32::<Endianess>()?;
186 trace!("Entry at offset: {:0X?}", offset);
187
188 let element = data.split_at(offset as usize).1;
189 let mut reader = Cursor::new(element);
190
191 let value_header = reader.read_u32::<Endianess>()?;
192 trace!(" > Value header {:032b}", value_header);
193
194 let value_type_number: u32 = value_header & 0b111;
195 let latin_or_int = ((value_header & 0b1000) >> 3) == 1;
196 let latin_key = ((value_header & 0b10000) >> 4) == 1;
197 let orig_value: u32 = (value_header & 0xFFFFFFE0) >> 5;
198
199 let value_type: Option<QTValueType> = FromPrimitive::from_u32(value_type_number);
200
201 if value_type.is_none() {
202 warn!("Could not parse value at json entry {}\nContinuing. But this might have unacceptable impact", i);
203 debug!("Value type: {:#0X}", value_type_number);
204 debug!("Value value: {:#04X}", orig_value);
205 }
206
207 trace!(" > Value of type: {:?}", value_type);
208 trace!(" > Key is latin: {}", latin_key);
209 let key = Self::read_string(&mut reader, latin_key)?;
210
211 trace!(" > Key is: '{}'", key);
212 trace!(" > Reading value of type: {:?}", value_type);
213
214 let value = Self::decode_value(
215 value_type,
216 orig_value,
217 latin_or_int,
218 latin_key,
219 size as usize,
220 data,
221 )?;
222
223 trace!(" > Value is: {:?}", value);
224
225 values.insert(key, value);
226 }
227
228 let object = Object { size: len, values };
229
230 trace!("Using object {:?}", object);
231
232 Ok(JsonValue::Object(object))
233 }
234
235 fn load_array(data: &[u8], offsets: &[u8], len: u32, size: u32) -> Result<JsonValue, Error> {
236 debug!("Loading array ..");
237 trace!("Expected len: {}", len);
238 trace!("Actual len: {}", offsets.len() / 4);
239
240 if offsets.len() / 4 < (len as usize) {
241 return Err(Error::new(
242 ErrorKind::InvalidData,
243 format!(
244 "The array is not the expected size, expected: {}, provided: {}",
245 len,
246 offsets.len() / 4
247 ),
248 ));
249 }
250
251 let mut offsets = Cursor::new(offsets);
252 let mut values = Vec::new();
253
254 for i in 0..len {
255 trace!("Iterating over entry {}", i);
256
257 let offset = offsets.read_u32::<Endianess>()?;
258 trace!("Entry at offset: 0x{:0X}", offset);
259
260 let value_header = offset;
261 trace!(" > Value header {:032b}b", value_header);
262
263 let value_type_number: u16 = (value_header & 0b111) as u16;
264 let latin_or_int = ((value_header & 0b1000) >> 3) == 1;
265 let latin_key = ((value_header & 0b10000) >> 4) == 1;
266 let orig_value: u32 = (value_header & 0xFFFFFFE0) >> 5;
267
268 let value_type: Option<QTValueType> = FromPrimitive::from_u16(value_type_number);
269
270 if value_type.is_none() {
271 warn!("Could not parse value at json entry {}\nContinuing. But this might have unacceptable impact", i);
272 debug!("Value type: {:#0X}", value_type_number);
273 debug!("Value value: {:#04X}", orig_value);
274 }
275
276 trace!(" > Reading value of type: {:?}", value_type);
277
278 let value = Self::decode_value(
279 value_type,
280 orig_value,
281 latin_or_int,
282 latin_key,
283 size as usize,
284 data,
285 )?;
286
287 trace!(" > Value is: {:?}", value);
288
289 values.push(value);
290 }
291
292 Ok(JsonValue::Array(values))
293 }
294
295 fn decode_value(
301 value_type: Option<QTValueType>,
302 orig_value: u32,
303 latin_or_int: bool,
304 latin_key: bool,
305 size: usize,
306 data: &[u8],
307 ) -> Result<JsonValue, std::io::Error> {
308 let value = match value_type {
309 Some(QTValueType::Double) => {
310 if latin_or_int {
311 JsonValue::Number(orig_value.into())
312 } else {
313 trace!(" > > Value is of type f64");
314 trace!(" > > Value located at offset: {:0X?}", orig_value);
315
316 let value_data = data.split_at(orig_value as usize).1;
317 let mut reader = Cursor::new(value_data);
318 JsonValue::Number(reader.read_f64::<Endianess>()?)
319 }
320 }
321 Some(QTValueType::String) => {
322 trace!(" > > Value located at offset: {:0X?}", orig_value);
323
324 let value_data = data.split_at(orig_value as usize).1;
325 let mut reader = Cursor::new(value_data);
326 JsonValue::String(Self::read_string(&mut reader, latin_key)?)
327 }
328 Some(QTValueType::Object) | Some(QTValueType::Array) => {
329 trace!(" > > Value located at offset: {:0X?}", orig_value);
330
331 trace!(
332 " > > Trimming {} bytes from object",
333 data.len() - size as usize
334 );
335 let value_data = data.split_at(size as usize).0;
336
337 trace!(" > > Trimming {} bytes from object top", orig_value);
338 let encapsulated = value_data.split_at(orig_value as usize).1;
339 Self::load_element(Vec::from(encapsulated))?
340 }
341 Some(QTValueType::Bool) => JsonValue::Bool(orig_value != 0),
342 Some(QTValueType::Null) => JsonValue::Null,
343 _ => JsonValue::Undefined,
344 };
345
346 Ok(value)
347 }
348
349 fn read_string(reader: &mut dyn Read, latin: bool) -> Result<String, Error> {
354 let key_len = reader.read_u16::<Endianess>()?;
355
356 trace!(" --> Reading string, latin:{}, len:{}", latin, key_len);
357 if latin {
359 let mut buffer = Vec::new();
360 for _ in 0..key_len {
361 buffer.push(reader.read_u8()?);
362 }
363
364 Ok(String::from_utf8_lossy(buffer.as_slice()).parse().unwrap())
365 } else {
366 let mut buffer = Vec::new();
368 for _ in 0..key_len {
369 buffer.push(reader.read_u16::<Endianess>()?);
370 }
371 String::from_utf16(buffer.as_slice())
372 .map_err(|_| Error::new(ErrorKind::InvalidData, "Invalid UTF16"))
373 }
374 }
375}
376
377#[cfg(test)]
378mod test {
379 use crate::elements::{JsonBaseValue, JsonValue};
380 use crate::QJSONDocument;
381
382 #[test]
383 fn read_object() {
384 let object_str = b"qbjs\x01\x00\x00\x00$\x00\x00\x00\x03\x00\x00\x00 \
385 \x00\x00\x00\x1B\x03\x00\x00\x04\x00test\x00\x00\x03\x00yes\x00\x00\x00\x0C\x00\x00\x00";
386
387 let parsed = QJSONDocument::from_binary(object_str.to_vec()).unwrap();
388
389 let val = match parsed.base {
390 JsonBaseValue::Object(ref object) => {
391 assert_eq!(object.size, 1);
392
393 object.values.get("test").unwrap()
394 }
395 _ => panic!("Expected object"),
396 };
397
398 match val {
399 JsonValue::String(ref s) => assert_eq!(s, "yes"),
400 _ => panic!("Expected string"),
401 }
402 }
403
404 #[test]
405 fn test_non_latin_number() {
406 let data = b"qbjs\x01\x00\x00\x00\x18\x00\x00\x00\x02\x00\x00\x00\x14\x00\x00\x00\
407 \x33\x33\x33\x33\x33\x33\x24\x40\x82\x01\x00\x00";
408
409 let parsed = QJSONDocument::from_binary(data.to_vec()).unwrap();
410
411 match parsed.base {
412 JsonBaseValue::Array(ref vals) => {
413 assert_eq!(vals.len(), 1);
414 let num = &vals[0];
415 match num {
416 JsonValue::Number(n) => assert_eq!(*n, 10.1),
417 _ => panic!("Expected number"),
418 }
419 }
420 _ => panic!("Expected array"),
421 };
422 }
423
424 #[test]
425 fn test_latin_string() {
426 env_logger::init();
427 let data = b"qbjs\x01\x00\x00\x00\x14\x00\x00\x00\x02\x00\x00\x00\x10\x00\x00\x00\x01\x00\xF6\x00\x8B\x01\x00\x00";
428
429 let parsed = QJSONDocument::from_binary(data.to_vec()).unwrap();
430
431 match parsed.base {
432 JsonBaseValue::Array(ref vals) => {
433 assert_eq!(vals.len(), 1);
434 let num = &vals[0];
435 match num {
436 JsonValue::String(n) => assert_eq!(*n, "รถ"),
437 _ => panic!("Expected string"),
438 }
439 }
440 _ => panic!("Expected array"),
441 };
442 }
443
444 #[test]
445 fn test_bool() {
446 let data = b"qbjs\x01\x00\x00\x00\x10\x00\x00\x00\x02\x00\x00\x00\x0C\x00\x00\x00!\x00\x00
447 \x00";
448
449 let parsed = QJSONDocument::from_binary(data.to_vec()).unwrap();
450
451 match parsed.base {
452 JsonBaseValue::Array(ref vals) => {
453 assert_eq!(vals.len(), 1);
454 let num = &vals[0];
455 match num {
456 JsonValue::Bool(n) => assert_eq!(*n, true),
457 _ => panic!("Expected string"),
458 }
459 }
460 _ => panic!("Expected array"),
461 };
462 }
463
464 #[test]
465 fn test_nested_object() {
466 let data = b"qbjs\x01\x00\x00\x00\x34\x00\x00\x00\x02\x00\x00\x00\x30\x00\x00\x00\x24\x00\
467 \x00\x00\x03\x00\x00\x00\x20\x00\x00\x00\x1B\x03\x00\x00\x04\x00test\x00\x00\x03\
468 \x00yes\x00\x00\x00\x0C\x00\x00\x00\x85\x01\x00\x00";
469
470 let parsed = QJSONDocument::from_binary(data.to_vec()).unwrap();
471
472 match parsed.base {
473 JsonBaseValue::Array(ref vals) => {
474 assert_eq!(vals.len(), 1);
475 let num = &vals[0];
476 let val = match num {
477 JsonValue::Object(n) => {
478 assert_eq!(n.size, 1);
479 n.values.get("test").unwrap()
480 }
481 _ => panic!("Expected string"),
482 };
483
484 match val {
485 JsonValue::String(n) => assert_eq!(*n, "yes"),
486 _ => panic!("Expected string"),
487 }
488 }
489 _ => panic!("Expected array"),
490 };
491 }
492}