From 9f60802d37f0abbaf5edc6010e2f27ca990cafc0 Mon Sep 17 00:00:00 2001 From: gered Date: Wed, 19 May 2021 17:53:18 -0400 Subject: [PATCH] add qst file support --- psoutils/Cargo.toml | 2 + psoutils/assets/test/q058-ret-gc.offline.qst | Bin 0 -> 17936 bytes psoutils/assets/test/q058-ret-gc.online.qst | Bin 0 -> 17936 bytes psoutils/assets/test/q118-vr-gc.offline.qst | Bin 0 -> 28416 bytes psoutils/assets/test/q118-vr-gc.online.qst | Bin 0 -> 27368 bytes psoutils/src/quest.rs | 1 + psoutils/src/quest/bin.rs | 2 +- psoutils/src/quest/dat.rs | 2 +- psoutils/src/quest/qst.rs | 586 +++++++++++++++++++ 9 files changed, 591 insertions(+), 2 deletions(-) create mode 100644 psoutils/assets/test/q058-ret-gc.offline.qst create mode 100644 psoutils/assets/test/q058-ret-gc.online.qst create mode 100644 psoutils/assets/test/q118-vr-gc.offline.qst create mode 100644 psoutils/assets/test/q118-vr-gc.online.qst create mode 100644 psoutils/src/quest/qst.rs diff --git a/psoutils/Cargo.toml b/psoutils/Cargo.toml index 2b1ef32..be00411 100644 --- a/psoutils/Cargo.toml +++ b/psoutils/Cargo.toml @@ -11,6 +11,8 @@ byteorder = "1.4.3" thiserror = "1.0.24" encoding_rs = "0.8.28" libc = "0.2.94" +rand = "0.8.3" +itertools = "0.10.0" [dev-dependencies] claim = "0.5.0" diff --git a/psoutils/assets/test/q058-ret-gc.offline.qst b/psoutils/assets/test/q058-ret-gc.offline.qst new file mode 100644 index 0000000000000000000000000000000000000000..d38b51d3fadc7eabe27079874a72d944c626f71d GIT binary patch literal 17936 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

! ziD|qdrW&C_X-++s*J%%;8= zmD`l<+EWKahp?RsnB^9jRNM6LA=SC3K##CIyQ9Q=)qKs?F%iudC=uA@5rN9;D7*0G zeto8X9X)TY*2TXIL??(lYAG3DZ4Ff1A393&*e{bal!vEEok|J&3~*?HBbD8x#}i4D z5gBg7C=(Fo!{iIoCM~Ato>!(gv{47@?0aFz-d+um*6}dAzvvY1;m}oBxP{%;Dc$h< zW+hp%R8(BUUsO$n=$m@7Ay)nWx&ZuN7qT0LWmVhd+}*P2_PBrb``-Pd8-axwqDoHi zJ2^=U6o4=ju6>aLyD=OA_s0hs2DPI*;+32VabhEi@O+^ zD!NXmJ{RpKcXuag{Zj0mi~r!Y-I3nOkU^(+-oV!2<*COxl-Sviekx|=-$31DR>$Om5kLO1xR7kR8ii=b~?L*N&3_8Ig;}Dk$xs7JK{dE%9bca;fkg6k_5*z zH#-DF!@P8^v9`n8!r zC%Q587V$0gAn|%G%Cp8iEvqCT*W}_xQ8e?5BSgo3pZha$I_axhRqL>jkDg(1y$56_ z%XwFhcoNQJ_aq1!7_sWE4Mf-8G7o zbeTmA;x2)`K4N>iV)E4zggxYLz3x#W^g2IAmC$?NKpV&3VYtF44(ZIaojY>rs$H&n z%@bg_YtP1Eu&h-Fq{RBP(%LV3Ck2lBUIwR5fSHnYOur*^5d zWM6=*0HJ%MKpRSCYw_A9VjId!2~k`k-5A08VC^S^)`)DctFoxFu)}uVh-9*PR$2_9 zNbX9viphBQ?aWe@=30nPKsJy6!;%K2nr2D|<3w9}g zuja32=I>{fhJH?qbh4&~;{vWPz+f5M5&=0qS1QBCT3&#>LB8QPkA?K3WYwNy>D&O9 z0~$_Ix;j$hW1??9*uhRgi{GlMYA4yfC42^aEgj*NAgznNW=>{9&{+6WvMi3!09Jn# zbZS`?WZE-=sx1yOA^j)ho(jw;f!mnqkw@dOxbAP$q!6LTJl#-^J)ub{{_=v(eQF}$ zuf_BR1Sq0P5zxObfc)15P4qmL?jl_JGO9O2mdOJI7TToRvmXJ|o(llknvo>o`R^#? zHpK6JT^n*sB)$IK<(jcnU#|Z-${SOzBNPqEY;~O%)RfPA}UY)`ac&A7spP0 zXq!cM!v>EHu2&kN3=e{J?sVf-^Du&|UttpC2qJx$U;5CMiB%>)ZBfAsDr$kaD7mvx z%YQ1&Sy@tLEmwHsH@?}Slp%2dKpSvk zUA?K~rDdys1Bc?t2mxH7i9Jh#N2*mJk2sqg&5{K`0FMW4IZ}V=6j@Hg(rW0@^#Sp2=t1RlA(IcFAKwqU^lJp? zH6FuxB(eDz!ey!~Q3_Pj>g4#}3QPJN#v}4<(qV6v!)?Kpt7Cju-567BF(S?gM=(qZuwXBevbR;JIB{s9vbhMwgtpg38!BwE&imeKtZ(6FSP(A z;#`rxojkzXw{D8ru;#aUcs_%C&}dx9ZN>JE0TVx9V=r#0ueZ*e(TBH+7qYo2(Lg&v zSwTp=`-sYi)HY+>xz7N<<$Tz_eBOux8vCrneaSiZe?$Nj9#N@x7THH&Oqi@1d1OQN z;L0XhqHK?aX)lg}atjJXB*_1+#gu|Y1l|>m@(?P8{;O209LOPny{vixyo?bGM z`qu@}|GJ>_nIi3iMs{Nqa(MH)p4ndOc1Yon6=D(fp~V4v zpjj^A)%S$=H8_g5_Hj`~M5-|t1?Jh`v)AxzDO@}bZ9PHS{%y>!NL!zBffIu%^T55_ z84|po&-?L)XDvZ~j*lT--SpnSqvj9a=qozhxOZv!Go7ASc*{52r7xHfogm{H_O9#P z!pXXX{NLAC>lCx0$C^8{-5|~g%MdL`At4|E7gSa@&0Thb;-z4C^g0dEj}0~2;1{Ej z6{aP1N$5ghWgnpsPp&H!IybSUh3*T8BQsz5cmVHzM1zGWLK|kd;>pxK9#7 z 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 literal 0 HcmV?d00001 diff --git a/psoutils/assets/test/q118-vr-gc.offline.qst b/psoutils/assets/test/q118-vr-gc.offline.qst new file mode 100644 index 0000000000000000000000000000000000000000..3b1f90dc811dc946decb83a7d2ed7007607b2c48 GIT binary patch literal 28416 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 literal 0 HcmV?d00001 diff --git a/psoutils/src/quest.rs b/psoutils/src/quest.rs index 947df61..6728a00 100644 --- a/psoutils/src/quest.rs +++ b/psoutils/src/quest.rs @@ -7,6 +7,7 @@ use crate::quest::dat::{QuestDat, QuestDatError}; pub mod bin; pub mod dat; +pub mod qst; #[derive(Error, Debug)] pub enum QuestError { diff --git a/psoutils/src/quest/bin.rs b/psoutils/src/quest/bin.rs index d7348bc..cf99ed3 100644 --- a/psoutils/src/quest/bin.rs +++ b/psoutils/src/quest/bin.rs @@ -283,7 +283,7 @@ impl QuestBin { } #[cfg(test)] -mod tests { +pub mod tests { use super::*; pub fn validate_quest_58_bin(bin: &QuestBin) { diff --git a/psoutils/src/quest/dat.rs b/psoutils/src/quest/dat.rs index dfcf564..1c36f68 100644 --- a/psoutils/src/quest/dat.rs +++ b/psoutils/src/quest/dat.rs @@ -275,7 +275,7 @@ impl QuestDat { } #[cfg(test)] -mod tests { +pub mod tests { use super::*; pub fn validate_quest_58_dat(dat: &QuestDat) { diff --git a/psoutils/src/quest/qst.rs b/psoutils/src/quest/qst.rs new file mode 100644 index 0000000..5041f8f --- /dev/null +++ b/psoutils/src/quest/qst.rs @@ -0,0 +1,586 @@ +use std::fs::File; +use std::io::{BufReader, Cursor, Write}; +use std::path::Path; + +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use itertools::Itertools; +use rand::random; +use thiserror::Error; + +use crate::bytes::FixedLengthByteArrays; +use crate::encryption::{Crypter, PCCrypter}; +use crate::packets::quest::*; +use crate::packets::{PacketError, PacketHeader}; +use crate::quest::bin::{QuestBin, QuestBinError}; +use crate::quest::dat::{QuestDat, QuestDatError}; +use crate::text::LanguageError; + +#[derive(Error, Debug)] +pub enum QuestQstError { + #[error("I/O error while processing quest qst")] + IoError(#[from] std::io::Error), + + #[error("String encoding error during processing of quest qst string data")] + StringEncodingError(#[from] LanguageError), + + #[error("Error reading quest qst data packet")] + DataPacketError(#[from] PacketError), + + #[error("Bad quest qst data format: {0}")] + DataFormatError(String), + + #[error("Error processing quest bin")] + QuestBinError(#[from] QuestBinError), + + #[error("Error processing quest dat")] + QuestDatError(#[from] QuestDatError), +} + +pub struct QuestQst { + bin_header: QuestHeaderPacket, + dat_header: QuestHeaderPacket, + bin_chunks: Box<[QuestDataPacket]>, + dat_chunks: Box<[QuestDataPacket]>, +} + +fn encrypt_quest_data( + quest_data: &mut [u8], + decompressed_size: usize, +) -> Result, QuestQstError> { + let crypt_key = random::(); + + // yes, PC encryption is used even for gamecube qst files + let mut crypter = PCCrypter::new(crypt_key); + crypter.crypt(quest_data); + + let mut result = Vec::::with_capacity(8 + quest_data.len()); + result.write_u32::(decompressed_size as u32)?; + result.write_u32::(crypt_key)?; + result.write_all(quest_data)?; + Ok(result.into_boxed_slice()) +} + +fn decrypt_quest_data(quest_data: &mut [u8]) -> Result<&[u8], QuestQstError> { + let mut prefix = &quest_data[0..8]; + let _decompressed_size = prefix.read_u32::()?; + let crypt_key = prefix.read_u32::()?; + + // yes, PC encryption is used even for gamecube qst files + let mut crypter = PCCrypter::new(crypt_key); + let mut result = &mut quest_data[8..]; + crypter.crypt(&mut result); + Ok(result) +} + +fn create_quest_data_chunks( + quest_data: &[u8], + filename: &str, + is_online_quest: bool, +) -> Result, QuestQstError> { + let mut chunks = Vec::::new(); + for (index, chunk) in quest_data.chunks(QUEST_DATA_PACKET_DATA_SIZE).enumerate() { + let mut chunk = QuestDataPacket::new(&filename, chunk, is_online_quest)?; + chunk.header.flags = index as u8; + chunks.push(chunk); + } + Ok(chunks.into_boxed_slice()) +} + +fn extract_quest_chunk_data( + chunks: &[QuestDataPacket], + is_online_quest: bool, +) -> Result, QuestQstError> { + // TODO: rewrite this function, it is kinda sloppy ... + + let mut data = Vec::::new(); + for chunk in chunks.iter() { + data.write_all(&chunk.data[0..(chunk.size as usize)])?; + } + + let actual_data = if is_online_quest { + data + } else { + decrypt_quest_data(&mut data)?.into() + }; + + Ok(actual_data) +} + +impl QuestQst { + pub fn from_bindat(bin: &QuestBin, dat: &QuestDat) -> Result { + let is_online = !bin.header.is_download; // "download quest" = "offline quest" (because it is played from a memory card ...) + let quest_name = &bin.header.name; + let quest_number = bin.header.quest_number_u16(); // i hate the quest .bin quest_number u8/u16 confusion amongst PSO tools ... + let bin_filename = format!("quest{}.bin", quest_number); + let dat_filename = format!("quest{}.dat", quest_number); + + let mut bin_bytes = bin.to_compressed_bytes()?; + let mut dat_bytes = dat.to_compressed_bytes()?; + if !is_online { + // offline quests are encrypted with some extra bits added before the encrypted data + bin_bytes = encrypt_quest_data(bin_bytes.as_mut(), bin.calculate_size())?; + dat_bytes = encrypt_quest_data(dat_bytes.as_mut(), dat.calculate_size())?; + } + + let bin_header = QuestHeaderPacket::new( + quest_name, + bin.header.language, + &bin_filename, + bin_bytes.len(), + is_online, + )?; + + let dat_header = QuestHeaderPacket::new( + quest_name, + bin.header.language, + &dat_filename, + dat_bytes.len(), + is_online, + )?; + + let bin_chunks = create_quest_data_chunks(bin_bytes.as_ref(), &bin_filename, is_online)?; + let dat_chunks = create_quest_data_chunks(dat_bytes.as_ref(), &dat_filename, is_online)?; + + Ok(QuestQst { + bin_header, + dat_header, + bin_chunks, + dat_chunks, + }) + } + + pub fn from_file(path: &Path) -> Result { + let file = File::open(path)?; + let mut reader = BufReader::new(file); + Ok(Self::from_bytes(&mut reader)?) + } + + pub fn from_bytes(reader: &mut T) -> Result { + let mut bin_header: Option = None; + let mut dat_header: Option = None; + let mut bin_chunks = Vec::::new(); + let mut dat_chunks = Vec::::new(); + let mut bin_data_counter: usize = 0; + let mut dat_data_counter: usize = 0; + + // loop, continuing to read packets until we have ALL of the following: + // - a bin header + // - a dat header + // - bin data chunks that contain the exact number of bytes specified by the bin header + // - dat data chunks that contain the exact number of bytes specified by the dat header + // + // the way this reading works should allow for the maximum amount of flexibility of the qst + // file layout. though, most (all?) things that create qst files will follow this ordering: + // - bin and dat header (either bin+dat or dat+bin) + // - interleaved bin and dat chunks + // + // however, i have observed that fuzziqer servers (newserv, khyller) generally sends out + // quest packets un-interleaved. that is, these servers send out bin header + bin data, and + // then dat header + dat data (actually, i think the ordering might be dat first ...? meh) + // + // thus, i decided that even if there is only a very small chance that someone out there + // saved a qst file in such a "non-standard" format, that we could easily account for any + // of those variations here + while (bin_header.is_none() + || (bin_header.is_some() + && bin_data_counter < bin_header.as_ref().unwrap().size as usize)) + || (dat_header.is_none() + || (dat_header.is_some() + && dat_data_counter < dat_header.as_ref().unwrap().size as usize)) + { + // what type of packet is this? + let packet_header = PacketHeader::from_bytes(reader)?; + match packet_header.id { + PACKET_ID_QUEST_HEADER_ONLINE | PACKET_ID_QUEST_HEADER_OFFLINE => { + // there can only be one bin and dat header per qst file + if bin_header.is_some() && dat_header.is_some() { + return Err(QuestQstError::DataFormatError(String::from( + "Encountered more than two header packets", + ))); + } + + let header = QuestHeaderPacket::from_header_and_bytes(packet_header, reader)?; + + // the header packet must include a filename, as this is used to determine + // whether it is for a .bin or .dat file + if header.filename.as_unpadded_slice().len() == 0 { + return Err(QuestQstError::DataFormatError(String::from( + "Encountered header packet with blank filename", + ))); + } + + match header.file_type() { + QuestPacketFileType::Bin => { + if bin_header.is_some() { + return Err(QuestQstError::DataFormatError(String::from( + "Encountered duplicate bin file header packet", + ))); + } else { + bin_header = Some(header); + } + } + QuestPacketFileType::Dat => { + if dat_header.is_some() { + return Err(QuestQstError::DataFormatError(String::from( + "Encountered duplicate dat file header packet", + ))); + } else { + dat_header = Some(header); + } + } + QuestPacketFileType::Unknown => { + return Err(QuestQstError::DataFormatError(String::from( + "Unable to determine file type from filename in header packet", + ))); + } + } + } + PACKET_ID_QUEST_DATA_ONLINE | PACKET_ID_QUEST_DATA_OFFLINE => { + // data chunk packets must come after its associated header packet + // (e.g. .bin data chunks must follow the .bin header, same for .dat ...) + if bin_header.is_none() && dat_header.is_none() { + return Err(QuestQstError::DataFormatError(String::from( + "Encountered data chunk packet before any header packets", + ))); + } + + let chunk = QuestDataPacket::from_header_and_bytes(packet_header, reader)?; + + // the data chunk packet must include a filename, as this is used to determine + // whether it is for a .bin or .dat file + if chunk.filename.as_unpadded_slice().len() == 0 { + return Err(QuestQstError::DataFormatError(String::from( + "Encountered data chunk packet with blank filename", + ))); + } + + // small sanity check, technically would not be a problem, but there shouldn't + // be any "blank" data chunk packets + if chunk.size == 0 { + return Err(QuestQstError::DataFormatError(String::from( + "Encountered data chunk packet with zero-length data", + ))); + } + + match chunk.file_type() { + QuestPacketFileType::Bin => { + if bin_header.is_none() { + return Err(QuestQstError::DataFormatError(String::from("Encountered data chunk packet for bin file before its header packet"))); + } else { + bin_data_counter += chunk.size as usize; + bin_chunks.push(chunk); + } + } + QuestPacketFileType::Dat => { + if dat_header.is_none() { + return Err(QuestQstError::DataFormatError(String::from("Encountered data chunk packet for dat file before its header packet"))); + } else { + dat_data_counter += chunk.size as usize; + dat_chunks.push(chunk); + } + } + QuestPacketFileType::Unknown => { + return Err(QuestQstError::DataFormatError(String::from( + "Unable to determine file type from filename in data chunk packet", + ))) + } + } + } + other_id => { + return Err(QuestQstError::DataFormatError(format!( + "Unexpected packet id found in quest qst data: {}", + other_id + ))) + } + } + } + + let bin_header = bin_header.unwrap(); + let dat_header = dat_header.unwrap(); + + // validate that the file bin/dat data chunk byte counts matched what was specified in the + // bin/dat headers + + if bin_data_counter as u32 != bin_header.size { + let size = bin_header.size; + return Err(QuestQstError::DataFormatError(format!( + "Read {} bytes of bin data, but the bin header specified {} bytes would be present", + bin_data_counter, size + ))); + } + if dat_data_counter as u32 != dat_header.size { + let size = dat_header.size; + return Err(QuestQstError::DataFormatError(format!( + "Read {} bytes of dat data, but the dat header specified {} bytes would be present", + dat_data_counter, size + ))); + } + + // validate that all packets encountered (header and data chunk) were of the same category + // the entire qst file should have only contained packet IDs: + // - PACKET_ID_QUEST_HEADER_ONLINE and PACKET_ID_QUEST_DATA_ONLINE, or + // - PACKET_ID_QUEST_HEADER_OFFLINE and PACKET_ID_QUEST_DATA_OFFLINE + + if bin_header.header.id != dat_header.header.id { + return Err(QuestQstError::DataFormatError(String::from( + "Packet header ID mismatch between bin and dat headers", + ))); + } + let expected_chunk_packets_id = if bin_header.header.id == PACKET_ID_QUEST_HEADER_ONLINE { + PACKET_ID_QUEST_DATA_ONLINE + } else { + PACKET_ID_QUEST_DATA_OFFLINE + }; + + if bin_chunks + .iter() + .filter(|chunk| chunk.header.id != expected_chunk_packets_id) + .count() + != 0 + { + return Err(QuestQstError::DataFormatError(format!( + "One or more bin data chunk packets were not of the expected type: {}", + expected_chunk_packets_id + ))); + } + if dat_chunks + .iter() + .filter(|chunk| chunk.header.id != expected_chunk_packets_id) + .count() + != 0 + { + return Err(QuestQstError::DataFormatError(format!( + "One or more dat data chunk packets were not of the expected type: {}", + expected_chunk_packets_id + ))); + } + + Ok(QuestQst { + bin_header, + dat_header, + bin_chunks: bin_chunks.into_boxed_slice(), + dat_chunks: dat_chunks.into_boxed_slice(), + }) + } + + pub fn write_bytes(&self, writer: &mut T) -> Result<(), QuestQstError> { + self.bin_header.write_bytes(writer)?; + self.dat_header.write_bytes(writer)?; + for chunk in self.bin_chunks.iter().interleave(self.dat_chunks.iter()) { + chunk.write_bytes(writer)?; + } + Ok(()) + } + + pub fn to_bytes(&self) -> Result, QuestQstError> { + let mut buffer = Cursor::new(Vec::::new()); + self.write_bytes(&mut buffer)?; + Ok(buffer.into_inner().into_boxed_slice()) + } + + pub fn is_online(&self) -> bool { + // assumes that a QuestQst could never be created with bin/dat headers containing + // different packet IDs ... + self.bin_header.header.id == PACKET_ID_QUEST_HEADER_ONLINE + } + + pub fn extract_bin_bytes(&self) -> Result, QuestQstError> { + Ok(extract_quest_chunk_data(&self.bin_chunks, self.is_online())?.into_boxed_slice()) + } + + pub fn extract_bin(&self) -> Result { + let data = self.extract_bin_bytes()?; + Ok(QuestBin::from_compressed_bytes(data.as_ref())?) + } + + pub fn extract_dat_bytes(&self) -> Result, QuestQstError> { + Ok(extract_quest_chunk_data(&self.dat_chunks, self.is_online())?.into_boxed_slice()) + } + + pub fn extract_dat(&self) -> Result { + let data = self.extract_dat_bytes()?; + Ok(QuestDat::from_compressed_bytes(data.as_ref())?) + } +} + +#[cfg(test)] +mod tests { + use crate::quest::bin::tests::{validate_quest_118_bin, validate_quest_58_bin}; + use crate::quest::dat::tests::{validate_quest_118_dat, validate_quest_58_dat}; + + use super::*; + + fn get_num_chunks_for_size(size: usize) -> usize { + ((size as f32) / (QUEST_DATA_PACKET_DATA_SIZE as f32)).ceil() as usize + } + + fn validate_quest_58_qst( + qst: &QuestQst, + bin_size: usize, + dat_size: usize, + is_online: bool, + ) -> Result<(), QuestQstError> { + let (expected_header_id, expected_chunk_id) = if is_online { + (PACKET_ID_QUEST_HEADER_ONLINE, PACKET_ID_QUEST_DATA_ONLINE) + } else { + (PACKET_ID_QUEST_HEADER_OFFLINE, PACKET_ID_QUEST_DATA_OFFLINE) + }; + + assert_eq!(qst.is_online(), is_online); + + assert_eq!(qst.bin_header.header.id, expected_header_id); + assert_eq!(qst.bin_header.name_str()?, "Lost HEAT SWORD"); + assert_eq!(qst.bin_header.filename_str()?, "quest58.bin"); + assert_eq!(qst.bin_header.file_type(), QuestPacketFileType::Bin); + let size = qst.bin_header.size as usize; + assert_eq!(size, bin_size); + + let num_chunks = get_num_chunks_for_size(bin_size); + assert_eq!(qst.bin_chunks.len(), num_chunks); + for chunk in qst.bin_chunks.iter() { + assert_eq!(chunk.header.id, expected_chunk_id); + assert_eq!(chunk.filename_str()?, "quest58.bin"); + assert_eq!(chunk.file_type(), QuestPacketFileType::Bin); + assert!(chunk.data().len() > 0); + } + + assert_eq!(qst.dat_header.header.id, expected_header_id); + assert_eq!(qst.dat_header.name_str()?, "Lost HEAT SWORD"); + assert_eq!(qst.dat_header.filename_str()?, "quest58.dat"); + assert_eq!(qst.dat_header.file_type(), QuestPacketFileType::Dat); + let size = qst.dat_header.size as usize; + assert_eq!(size, dat_size); + + let num_chunks = get_num_chunks_for_size(dat_size); + assert_eq!(qst.dat_chunks.len(), num_chunks); + for chunk in qst.dat_chunks.iter() { + assert_eq!(chunk.header.id, expected_chunk_id); + assert_eq!(chunk.filename_str()?, "quest58.dat"); + assert_eq!(chunk.file_type(), QuestPacketFileType::Dat); + assert!(chunk.data().len() > 0); + } + + let mut bin = qst.extract_bin()?; + if !is_online { + assert_eq!(true, bin.header.is_download); + bin.header.is_download = false; + } + validate_quest_58_bin(&bin); + + let dat = qst.extract_dat()?; + validate_quest_58_dat(&dat); + + Ok(()) + } + + fn validate_quest_118_qst( + qst: &QuestQst, + bin_size: usize, + dat_size: usize, + is_online: bool, + ) -> Result<(), QuestQstError> { + let (expected_header_id, expected_chunk_id) = if is_online { + (PACKET_ID_QUEST_HEADER_ONLINE, PACKET_ID_QUEST_DATA_ONLINE) + } else { + (PACKET_ID_QUEST_HEADER_OFFLINE, PACKET_ID_QUEST_DATA_OFFLINE) + }; + + assert_eq!(qst.is_online(), is_online); + + assert_eq!(qst.bin_header.header.id, expected_header_id); + assert_eq!(qst.bin_header.name_str()?, "Towards the Future"); + assert_eq!(qst.bin_header.filename_str()?, "quest118.bin"); + assert_eq!(qst.bin_header.file_type(), QuestPacketFileType::Bin); + let size = qst.bin_header.size as usize; + assert_eq!(size, bin_size); + + let num_chunks = get_num_chunks_for_size(bin_size); + assert_eq!(qst.bin_chunks.len(), num_chunks); + for chunk in qst.bin_chunks.iter() { + assert_eq!(chunk.header.id, expected_chunk_id); + assert_eq!(chunk.filename_str()?, "quest118.bin"); + assert_eq!(chunk.file_type(), QuestPacketFileType::Bin); + assert!(chunk.data().len() > 0); + } + + assert_eq!(qst.dat_header.header.id, expected_header_id); + assert_eq!(qst.dat_header.name_str()?, "Towards the Future"); + assert_eq!(qst.dat_header.filename_str()?, "quest118.dat"); + assert_eq!(qst.dat_header.file_type(), QuestPacketFileType::Dat); + let size = qst.dat_header.size as usize; + assert_eq!(size, dat_size); + + let num_chunks = get_num_chunks_for_size(dat_size); + assert_eq!(qst.dat_chunks.len(), num_chunks); + for chunk in qst.dat_chunks.iter() { + assert_eq!(chunk.header.id, expected_chunk_id); + assert_eq!(chunk.filename_str()?, "quest118.dat"); + assert_eq!(chunk.file_type(), QuestPacketFileType::Dat); + assert!(chunk.data().len() > 0); + } + + let mut bin = qst.extract_bin()?; + if !is_online { + assert_eq!(true, bin.header.is_download); + bin.header.is_download = false; + } + validate_quest_118_bin(&bin); + + let dat = qst.extract_dat()?; + validate_quest_118_dat(&dat); + + Ok(()) + } + + #[test] + pub fn read_quest_58_qst_from_file() -> Result<(), QuestQstError> { + let qst = QuestQst::from_file(Path::new("assets/test/q058-ret-gc.online.qst"))?; + validate_quest_58_qst(&qst, 1438, 15097, true)?; + + let qst = QuestQst::from_file(Path::new("assets/test/q058-ret-gc.offline.qst"))?; + validate_quest_58_qst(&qst, 1571, 15105, false)?; + + Ok(()) + } + + #[test] + pub fn read_quest_118_qst_from_file() -> Result<(), QuestQstError> { + let qst = QuestQst::from_file(Path::new("assets/test/q118-vr-gc.online.qst"))?; + validate_quest_118_qst(&qst, 14208, 11802, true)?; + + let qst = QuestQst::from_file(Path::new("assets/test/q118-vr-gc.offline.qst"))?; + validate_quest_118_qst(&qst, 14801, 11810, false)?; + + Ok(()) + } + + #[test] + pub fn create_qst_from_quest_58_bindat_files() -> Result<(), QuestQstError> { + let mut bin = QuestBin::from_compressed_file(Path::new("assets/test/q058-ret-gc.bin"))?; + let dat = QuestDat::from_compressed_file(Path::new("assets/test/q058-ret-gc.dat"))?; + + let qst = QuestQst::from_bindat(&bin, &dat)?; + validate_quest_58_qst(&qst, 1565, 15507, true)?; + + bin.header.is_download = true; + let qst = QuestQst::from_bindat(&bin, &dat)?; + validate_quest_58_qst(&qst, 1573, 15515, false)?; + + Ok(()) + } + + #[test] + pub fn create_qst_from_quest_118_bindat_files() -> Result<(), QuestQstError> { + let mut bin = QuestBin::from_compressed_file(Path::new("assets/test/q118-vr-gc.bin"))?; + let dat = QuestDat::from_compressed_file(Path::new("assets/test/q118-vr-gc.dat"))?; + + let qst = QuestQst::from_bindat(&bin, &dat)?; + validate_quest_118_qst(&qst, 14794, 12277, true)?; + + bin.header.is_download = true; + let qst = QuestQst::from_bindat(&bin, &dat)?; + validate_quest_118_qst(&qst, 14803, 12285, false)?; + + Ok(()) + } +}