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