new drone, convert some macros to functions #32
							
								
								
									
										31
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								.drone.yml
									
									
									
									
									
								
							| @ -3,8 +3,23 @@ kind: pipeline | |||||||
| type: docker | type: docker | ||||||
| name: test libpso | name: test libpso | ||||||
| 
 | 
 | ||||||
|  | concurrency: | ||||||
|  |     limit: 1 | ||||||
|  | 
 | ||||||
|  | environment: | ||||||
|  |   CARGO_INCREMENTAL: false | ||||||
|  | 
 | ||||||
| steps: | steps: | ||||||
| - name: cargo build | - name: clean cache | ||||||
|  |   image: rustlang/rust:nightly | ||||||
|  |   volumes: | ||||||
|  |   - name: cache | ||||||
|  |     path: /usr/local/cargo | ||||||
|  |   - name: target-cache | ||||||
|  |     path: /drone/src/target | ||||||
|  |   commands: | ||||||
|  |   - cargo prune | ||||||
|  | - name: build | ||||||
|   image: rustlang/rust:nightly |   image: rustlang/rust:nightly | ||||||
|   volumes: |   volumes: | ||||||
|   - name: cache |   - name: cache | ||||||
| @ -13,7 +28,7 @@ steps: | |||||||
|     path: /drone/src/target |     path: /drone/src/target | ||||||
|   commands: |   commands: | ||||||
|   - cargo build |   - cargo build | ||||||
| - name: cargo test | - name: clippy! | ||||||
|   image: rustlang/rust:nightly |   image: rustlang/rust:nightly | ||||||
|   volumes: |   volumes: | ||||||
|   - name: cache |   - name: cache | ||||||
| @ -21,7 +36,16 @@ steps: | |||||||
|   - name: target-cache |   - name: target-cache | ||||||
|     path: /drone/src/target |     path: /drone/src/target | ||||||
|   commands: |   commands: | ||||||
|   - cargo test |   - cargo clippy -- --deny warnings | ||||||
|  | - name: test | ||||||
|  |   image: rustlang/rust:nightly | ||||||
|  |   volumes: | ||||||
|  |   - name: cache | ||||||
|  |     path: /usr/local/cargo | ||||||
|  |   - name: target-cache | ||||||
|  |     path: /drone/src/target | ||||||
|  |   commands: | ||||||
|  |   - cargo test --jobs 1 | ||||||
| 
 | 
 | ||||||
| volumes: | volumes: | ||||||
| - name: cache | - name: cache | ||||||
| @ -30,4 +54,3 @@ volumes: | |||||||
| - name: target-cache | - name: target-cache | ||||||
|   host: |   host: | ||||||
|     path: /home/drone/cargo-cache |     path: /home/drone/cargo-cache | ||||||
| 
 |  | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| [package] | [package] | ||||||
| name = "libpso" | name = "libpso" | ||||||
| version = "0.1.0" | version = "0.0.1" | ||||||
| authors = ["Jake Probst <jake.probst@gmail.com>"] | authors = ["Jake Probst <jake.probst@gmail.com>"] | ||||||
| edition = "2018" | edition = "2018" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| [package] | [package] | ||||||
| name = "psopacket" | name = "psopacket" | ||||||
| version = "1.0.0" | version = "0.0.1" | ||||||
| authors = ["Jake Probst <jake.probst@gmail.com>"] | authors = ["Jake Probst <jake.probst@gmail.com>"] | ||||||
| edition = "2018" | edition = "2018" | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -149,14 +149,14 @@ fn generate_psopacket_impl(pkt_cmd: u16, name: syn::Ident, attrs: &Vec<AttrType> | |||||||
|             fn from_bytes(data: &[u8]) -> Result<#name, PacketParseError> { |             fn from_bytes(data: &[u8]) -> Result<#name, PacketParseError> { | ||||||
|                 let mut cur = std::io::Cursor::new(data); |                 let mut cur = std::io::Cursor::new(data); | ||||||
|                 let mut b: [u8; 2] = [0; 2]; |                 let mut b: [u8; 2] = [0; 2]; | ||||||
|                 cur.read(&mut b).unwrap(); |                 cur.read_exact(&mut b).unwrap(); | ||||||
|                 let len = u16::from_le_bytes(b); |                 let len = u16::from_le_bytes(b); | ||||||
|                 cur.read(&mut b).unwrap(); |                 cur.read_exact(&mut b).unwrap(); | ||||||
|                 let cmd = u16::from_le_bytes(b); |                 let cmd = u16::from_le_bytes(b); | ||||||
|                 let mut f: [u8; 4] = [0; 4]; |                 let mut f: [u8; 4] = [0; 4]; | ||||||
| 
 | 
 | ||||||
|                 let flag = if #include_flag { |                 let flag = if #include_flag { | ||||||
|                     cur.read(&mut f).unwrap(); |                     cur.read_exact(&mut f).unwrap(); | ||||||
|                     u32::from_le_bytes(f) |                     u32::from_le_bytes(f) | ||||||
|                 } |                 } | ||||||
|                 else { 0 }; |                 else { 0 }; | ||||||
| @ -542,9 +542,9 @@ fn generate_psomessage_impl(msg_cmd: u8, name: syn::Ident, attrs: &Vec<AttrType> | |||||||
|             const CMD: u8 = #msg_cmd; |             const CMD: u8 = #msg_cmd; | ||||||
|             fn from_bytes<R: std::io::Read + std::io::Seek >(mut cur: &mut R) -> Result<#name, PacketParseError> { |             fn from_bytes<R: std::io::Read + std::io::Seek >(mut cur: &mut R) -> Result<#name, PacketParseError> { | ||||||
|                 let mut buf1 = [0u8; 1]; |                 let mut buf1 = [0u8; 1]; | ||||||
|                 cur.read(&mut buf1).unwrap(); |                 cur.read_exact(&mut buf1).unwrap(); | ||||||
|                 let cmd = buf1[0]; |                 let cmd = buf1[0]; | ||||||
|                 cur.read(&mut buf1).unwrap(); |                 cur.read_exact(&mut buf1).unwrap(); | ||||||
|                 let size = buf1[0]; |                 let size = buf1[0]; | ||||||
| 
 | 
 | ||||||
|                 let mut subbuf = vec![0u8; size as usize * 4 - 2]; |                 let mut subbuf = vec![0u8; size as usize * 4 - 2]; | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | #![allow(clippy::module_inception)] | ||||||
| pub mod settings; | pub mod settings; | ||||||
| pub mod character; | pub mod character; | ||||||
| pub mod guildcard; | pub mod guildcard; | ||||||
|  | |||||||
| @ -48,7 +48,7 @@ impl PSOBBCipher { | |||||||
|         for k in cipher.p_array.iter_mut() { |         for k in cipher.p_array.iter_mut() { | ||||||
|             let mut pt = *k as u16; |             let mut pt = *k as u16; | ||||||
|             pt = ((pt & 0x00FF) << 8) + ((pt & 0xFF00) >> 8); |             pt = ((pt & 0x00FF) << 8) + ((pt & 0xFF00) >> 8); | ||||||
|             *k = ((((*k >> 16) ^ pt as u32) << 16)) + pt as u32; |             *k = (((*k >> 16) ^ pt as u32) << 16) + pt as u32; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         for i in 0..18 { |         for i in 0..18 { | ||||||
| @ -85,7 +85,7 @@ impl PSOBBCipher { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl PSOCipher for PSOBBCipher { | impl PSOCipher for PSOBBCipher { | ||||||
|     fn encrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError> { |     fn encrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError> { | ||||||
|         let mut real_data = data.chunks(4).map(|k| { |         let mut real_data = data.chunks(4).map(|k| { | ||||||
|             u32::from_le_bytes([k[0], k[1], k[2], k[3]]) |             u32::from_le_bytes([k[0], k[1], k[2], k[3]]) | ||||||
|         }).collect::<Vec<_>>(); |         }).collect::<Vec<_>>(); | ||||||
| @ -106,9 +106,7 @@ impl PSOCipher for PSOBBCipher { | |||||||
|             l ^= self.p_array[4]; |             l ^= self.p_array[4]; | ||||||
|             r ^= self.p_array[5]; |             r ^= self.p_array[5]; | ||||||
| 
 | 
 | ||||||
|             let tmp = l; |             std::mem::swap(&mut l, &mut r); | ||||||
|             l = r; |  | ||||||
|             r = tmp; |  | ||||||
| 
 | 
 | ||||||
|             result.extend_from_slice(&l.to_le_bytes()); |             result.extend_from_slice(&l.to_le_bytes()); | ||||||
|             result.extend_from_slice(&r.to_le_bytes()); |             result.extend_from_slice(&r.to_le_bytes()); | ||||||
| @ -117,7 +115,7 @@ impl PSOCipher for PSOBBCipher { | |||||||
|         Ok(result) |         Ok(result) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn decrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError> { |     fn decrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError> { | ||||||
|         if data.len() % 8 != 0 { |         if data.len() % 8 != 0 { | ||||||
|             return Err(CipherError::InvalidSize); |             return Err(CipherError::InvalidSize); | ||||||
|         } |         } | ||||||
| @ -139,9 +137,8 @@ impl PSOCipher for PSOBBCipher { | |||||||
|             l ^= self.p_array[1]; |             l ^= self.p_array[1]; | ||||||
|             r ^= self.p_array[0]; |             r ^= self.p_array[0]; | ||||||
| 
 | 
 | ||||||
|             let tmp = l; | 
 | ||||||
|             l = r; |             std::mem::swap(&mut l, &mut r); | ||||||
|             r = tmp; |  | ||||||
| 
 | 
 | ||||||
|             result.extend_from_slice(&l.to_le_bytes()); |             result.extend_from_slice(&l.to_le_bytes()); | ||||||
|             result.extend_from_slice(&r.to_le_bytes()); |             result.extend_from_slice(&r.to_le_bytes()); | ||||||
|  | |||||||
| @ -10,8 +10,8 @@ pub enum CipherError { | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| pub trait PSOCipher { | pub trait PSOCipher { | ||||||
|     fn encrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError>; |     fn encrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError>; | ||||||
|     fn decrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError>; |     fn decrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError>; | ||||||
|     fn header_size(&self) -> usize; |     fn header_size(&self) -> usize; | ||||||
|     fn block_size(&self) -> usize { |     fn block_size(&self) -> usize { | ||||||
|         self.header_size() |         self.header_size() | ||||||
| @ -24,12 +24,12 @@ pub struct NullCipher { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl PSOCipher for NullCipher { | impl PSOCipher for NullCipher { | ||||||
|     fn encrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError> { |     fn encrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError> { | ||||||
|         Ok(data.clone()) |         Ok(data.to_vec()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn decrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError> { |     fn decrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError> { | ||||||
|         Ok(data.clone()) |         Ok(data.to_vec()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn header_size(&self) -> usize { |     fn header_size(&self) -> usize { | ||||||
|  | |||||||
| @ -31,15 +31,15 @@ impl PSOPCCipher { | |||||||
|             eax = edi; |             eax = edi; | ||||||
|             var1 = eax / W(55); |             var1 = eax / W(55); | ||||||
|             edx = eax - (var1 * W(55)); |             edx = eax - (var1 * W(55)); | ||||||
|             ebx = ebx - esi; |             ebx -= esi; | ||||||
|             edi = edi + W(0x15); |             edi += W(0x15); | ||||||
|             stream[edx.0 as usize] = esi.0; |             stream[edx.0 as usize] = esi.0; | ||||||
|             esi = ebx; |             esi = ebx; | ||||||
|             ebx = W(stream[edx.0 as usize]); |             ebx = W(stream[edx.0 as usize]); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let mut cipher = PSOPCCipher { |         let mut cipher = PSOPCCipher { | ||||||
|             stream: stream, |             stream, | ||||||
|             offset: 1, |             offset: 1, | ||||||
|         }; |         }; | ||||||
|         
 |         
 | ||||||
| @ -63,7 +63,7 @@ impl PSOPCCipher { | |||||||
|         while edx > W(0) { |         while edx > W(0) { | ||||||
|             esi = W(self.stream[eax.0 as usize + 0x1F]); |             esi = W(self.stream[eax.0 as usize + 0x1F]); | ||||||
|             ebp = W(self.stream[eax.0 as usize]); |             ebp = W(self.stream[eax.0 as usize]); | ||||||
|             ebp = ebp - esi; |             ebp -= esi; | ||||||
|             self.stream[eax.0 as usize] = ebp.0; |             self.stream[eax.0 as usize] = ebp.0; | ||||||
|             eax += W(1); |             eax += W(1); | ||||||
|             edx -= W(1); |             edx -= W(1); | ||||||
| @ -74,7 +74,7 @@ impl PSOPCCipher { | |||||||
|         while edx > W(0) { |         while edx > W(0) { | ||||||
|             esi = W(self.stream[eax.0 as usize - 0x18]); |             esi = W(self.stream[eax.0 as usize - 0x18]); | ||||||
|             ebp = W(self.stream[eax.0 as usize]); |             ebp = W(self.stream[eax.0 as usize]); | ||||||
|             ebp = ebp - esi; |             ebp -= esi; | ||||||
|             self.stream[eax.0 as usize] = ebp.0; |             self.stream[eax.0 as usize] = ebp.0; | ||||||
|             eax += W(1); |             eax += W(1); | ||||||
|             edx -= W(1); |             edx -= W(1); | ||||||
| @ -94,7 +94,7 @@ impl PSOPCCipher { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl PSOCipher for PSOPCCipher { | impl PSOCipher for PSOPCCipher { | ||||||
|     fn encrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError> { |     fn encrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError> { | ||||||
|         let mut result = Vec::new(); |         let mut result = Vec::new(); | ||||||
|         if data.len() % 4 != 0 { |         if data.len() % 4 != 0 { | ||||||
|             return Err(CipherError::InvalidSize) |             return Err(CipherError::InvalidSize) | ||||||
| @ -108,7 +108,7 @@ impl PSOCipher for PSOPCCipher { | |||||||
|         Ok(result) |         Ok(result) | ||||||
|     } |     } | ||||||
|     
 |     
 | ||||||
|     fn decrypt(&mut self, data: &Vec<u8>) -> Result<Vec<u8>, CipherError> { |     fn decrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, CipherError> { | ||||||
|         self.encrypt(data) |         self.encrypt(data) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ pub mod crypto; | |||||||
| pub mod packet; | pub mod packet; | ||||||
| pub mod character; | pub mod character; | ||||||
| pub mod util; | pub mod util; | ||||||
| pub mod item; | //pub mod item;
 | ||||||
| 
 | 
 | ||||||
| use std::io::{Read, Seek}; | use std::io::{Read, Seek}; | ||||||
| #[derive(Debug, PartialEq)] | #[derive(Debug, PartialEq)] | ||||||
| @ -119,7 +119,7 @@ impl PSOPacketData for ConsumingBlob { | |||||||
|         let mut blob: Vec<u8> = Vec::new(); |         let mut blob: Vec<u8> = Vec::new(); | ||||||
|         cursor.read_to_end(&mut blob).map_err(|_| PacketParseError::ReadError)?; |         cursor.read_to_end(&mut blob).map_err(|_| PacketParseError::ReadError)?; | ||||||
|         Ok(ConsumingBlob { |         Ok(ConsumingBlob { | ||||||
|             blob: blob, |             blob, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|     fn as_bytes(&self) -> Vec<u8> { |     fn as_bytes(&self) -> Vec<u8> { | ||||||
|  | |||||||
| @ -1,7 +1,8 @@ | |||||||
| use chrono::{DateTime, Utc}; | use chrono::{DateTime, Utc}; | ||||||
| 
 | 
 | ||||||
| use psopacket::{pso_packet, PSOPacketData}; | use psopacket::{pso_packet, PSOPacketData}; | ||||||
| use crate::{PSOPacket, PacketParseError, PSOPacketData, utf8_to_utf16_array}; | use crate::{PSOPacket, PacketParseError, PSOPacketData}; | ||||||
|  | use crate::util::utf8_to_utf16_array; | ||||||
| 
 | 
 | ||||||
| use crate::character::character::SelectScreenCharacter; | use crate::character::character::SelectScreenCharacter; | ||||||
| 
 | 
 | ||||||
| @ -23,9 +24,9 @@ impl LoginWelcome { | |||||||
|         let mut copyright = [0u8; 0x60]; |         let mut copyright = [0u8; 0x60]; | ||||||
|         copyright[..0x4B].clone_from_slice(b"Phantasy Star Online Blue Burst Game Server. Copyright 1999-2004 SONICTEAM."); |         copyright[..0x4B].clone_from_slice(b"Phantasy Star Online Blue Burst Game Server. Copyright 1999-2004 SONICTEAM."); | ||||||
|         LoginWelcome { |         LoginWelcome { | ||||||
|             copyright: copyright, |             copyright, | ||||||
|             server_key: server_key, |             server_key, | ||||||
|             client_key: client_key, |             client_key, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -75,8 +76,8 @@ pub struct Session { | |||||||
|     pub character_slot: u8, // 1..=4
 |     pub character_slot: u8, // 1..=4
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Session { | impl Default for Session { | ||||||
|     pub fn new() -> Session { |     fn default() -> Session { | ||||||
|         Session { |         Session { | ||||||
|             version: [0; 30], |             version: [0; 30], | ||||||
|             session_id: 0, |             session_id: 0, | ||||||
| @ -179,12 +180,12 @@ pub struct LoginResponse { | |||||||
| impl LoginResponse { | impl LoginResponse { | ||||||
|     pub fn by_status(status: AccountStatus, session: Session) -> LoginResponse { |     pub fn by_status(status: AccountStatus, session: Session) -> LoginResponse { | ||||||
|         LoginResponse { |         LoginResponse { | ||||||
|             status: status, |             status, | ||||||
|             tag: 0x00010000, |             tag: 0x00010000, | ||||||
|             //tag: 0x00000100,
 |             //tag: 0x00000100,
 | ||||||
|             guildcard: 0, |             guildcard: 0, | ||||||
|             team_id: 0, |             team_id: 0, | ||||||
|             session: session, |             session, | ||||||
|             caps: 0x00000102, |             caps: 0x00000102, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -193,9 +194,9 @@ impl LoginResponse { | |||||||
|             status: AccountStatus::Ok, |             status: AccountStatus::Ok, | ||||||
|             tag: 0x00010000, |             tag: 0x00010000, | ||||||
|             //tag: 0x00000100,
 |             //tag: 0x00000100,
 | ||||||
|             guildcard: guildcard, |             guildcard, | ||||||
|             team_id: team_id, |             team_id, | ||||||
|             session: session, |             session, | ||||||
|             caps: 0x00000102, |             caps: 0x00000102, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -228,10 +229,10 @@ impl SendKeyAndTeamSettings { | |||||||
|     pub fn new(keyboard_config: [u8; 0x16C], gamepad_config: [u8; 0x38], guildcard: u32, team_id: u32) -> SendKeyAndTeamSettings { |     pub fn new(keyboard_config: [u8; 0x16C], gamepad_config: [u8; 0x38], guildcard: u32, team_id: u32) -> SendKeyAndTeamSettings { | ||||||
|         SendKeyAndTeamSettings { |         SendKeyAndTeamSettings { | ||||||
|             unknown: [0; 0x114], |             unknown: [0; 0x114], | ||||||
|             keyboard_config: keyboard_config, |             keyboard_config, | ||||||
|             gamepad_config: gamepad_config, |             gamepad_config, | ||||||
|             guildcard: guildcard, |             guildcard, | ||||||
|             team_id: team_id, |             team_id, | ||||||
|             //team_info: [0; 2],
 |             //team_info: [0; 2],
 | ||||||
|             team_info: [0; 8], |             team_info: [0; 8], | ||||||
|             team_priv: 0, |             team_priv: 0, | ||||||
| @ -254,8 +255,8 @@ pub struct RedirectClient { | |||||||
| impl RedirectClient { | impl RedirectClient { | ||||||
|     pub fn new(ip: u32, port: u16) -> RedirectClient { |     pub fn new(ip: u32, port: u16) -> RedirectClient { | ||||||
|         RedirectClient { |         RedirectClient { | ||||||
|             ip: ip, |             ip, | ||||||
|             port: port, |             port, | ||||||
|             padding: 0, |             padding: 0, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -275,7 +276,7 @@ pub struct ChecksumAck { | |||||||
| impl ChecksumAck { | impl ChecksumAck { | ||||||
|     pub fn new(ack: u32) -> ChecksumAck { |     pub fn new(ack: u32) -> ChecksumAck { | ||||||
|         ChecksumAck { |         ChecksumAck { | ||||||
|             ack: ack, |             ack, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -314,7 +315,7 @@ impl GuildcardDataHeader { | |||||||
|         GuildcardDataHeader { |         GuildcardDataHeader { | ||||||
|             one: 1, |             one: 1, | ||||||
|             len: len as u32, |             len: len as u32, | ||||||
|             checksum: checksum |             checksum, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -330,7 +331,6 @@ pub struct GuildcardDataChunk { | |||||||
|     _unknown: u32, |     _unknown: u32, | ||||||
|     chunk: u32, |     chunk: u32, | ||||||
|     pub buffer: [u8; GUILD_CARD_CHUNK_SIZE], |     pub buffer: [u8; GUILD_CARD_CHUNK_SIZE], | ||||||
| 
 |  | ||||||
|     len: usize, |     len: usize, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -338,9 +338,9 @@ impl GuildcardDataChunk { | |||||||
|     pub fn new(chunk: u32, buffer: [u8; GUILD_CARD_CHUNK_SIZE], len: usize) -> GuildcardDataChunk { |     pub fn new(chunk: u32, buffer: [u8; GUILD_CARD_CHUNK_SIZE], len: usize) -> GuildcardDataChunk { | ||||||
|         GuildcardDataChunk { |         GuildcardDataChunk { | ||||||
|             _unknown: 0, |             _unknown: 0, | ||||||
|             chunk: chunk as u32, |             chunk, | ||||||
|             buffer: buffer, |             buffer, | ||||||
|             len: len, |             len, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -371,12 +371,12 @@ impl PSOPacket for GuildcardDataChunk { | |||||||
| 
 | 
 | ||||||
| impl std::fmt::Debug for GuildcardDataChunk { | impl std::fmt::Debug for GuildcardDataChunk { | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||||
|         write!(f, "packet GuildcardDataChunk {{\n").unwrap(); |         writeln!(f, "packet GuildcardDataChunk {{").unwrap(); | ||||||
|         write!(f, "    flag: {:?}\n", 0).unwrap(); |         writeln!(f, "    flag: {:?}", 0).unwrap(); | ||||||
|         write!(f, "    _unknown: {:#X?}\n", self._unknown).unwrap(); |         writeln!(f, "    _unknown: {:#X?}", self._unknown).unwrap(); | ||||||
|         write!(f, "    chunk: {:#X?}\n", self.chunk).unwrap(); |         writeln!(f, "    chunk: {:#X?}", self.chunk).unwrap(); | ||||||
|         write!(f, "    buffer: [0..{:#X}]\n", self.len).unwrap(); |         writeln!(f, "    buffer: [0..{:#X}]", self.len).unwrap(); | ||||||
|         write!(f, "}}") |         writeln!(f, "}}") | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -428,9 +428,9 @@ impl PSOPacket for ParamDataHeader { | |||||||
| 
 | 
 | ||||||
| impl std::fmt::Debug for ParamDataHeader { | impl std::fmt::Debug for ParamDataHeader { | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||||
|         write!(f, "packet ParamDataHeader{{\n").unwrap(); |         writeln!(f, "packet ParamDataHeader{{").unwrap(); | ||||||
|         write!(f, "    files: [..]\n").unwrap(); |         writeln!(f, "    files: [..]").unwrap(); | ||||||
|         write!(f, "}}") |         writeln!(f, "}}") | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -492,9 +492,9 @@ impl ShipList { | |||||||
|                 menu: ships.get(0).map(|s| s.menu).unwrap_or(0), |                 menu: ships.get(0).map(|s| s.menu).unwrap_or(0), | ||||||
|                 item: 0, |                 item: 0, | ||||||
|                 flags: 0, |                 flags: 0, | ||||||
|                 name: utf8_to_utf16_array!("Ship", 0x11), |                 name: utf8_to_utf16_array("Ship"), | ||||||
|             }, |             }, | ||||||
|             ships: ships, |             ships, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -517,7 +517,7 @@ mod tests { | |||||||
|             tag: 0, |             tag: 0, | ||||||
|             guildcard: 0, |             guildcard: 0, | ||||||
|             team_id: 0, |             team_id: 0, | ||||||
|             session: Session::new(), |             session: Session::default(), | ||||||
|             caps: 0, |             caps: 0, | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
| @ -560,7 +560,7 @@ mod tests { | |||||||
|     #[test] |     #[test] | ||||||
|     fn test_session_size() { |     fn test_session_size() { | ||||||
|         use super::PSOPacketData; |         use super::PSOPacketData; | ||||||
|         let session = super::Session::new(); |         let session = super::Session::default(); | ||||||
|         assert!(session.as_bytes().len() == 40); |         assert!(session.as_bytes().len() == 40); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -764,21 +764,21 @@ impl PSOPacketData for TradeRequestCommand { | |||||||
|                      0, 0, |                      0, 0, | ||||||
|                      0, 0, 0, 0] |                      0, 0, 0, 0] | ||||||
|                     .into_iter() |                     .into_iter() | ||||||
|                     .chain(meseta.to_le_bytes().to_vec().into_iter()) |                     .chain(meseta.to_le_bytes().iter().copied()) | ||||||
|                     .collect() |                     .collect() | ||||||
|             }, |             }, | ||||||
|             TradeRequestCommand::AddItem(item_id, amount) => { |             TradeRequestCommand::AddItem(item_id, amount) => { | ||||||
|                 vec![1u8, 0, 0, 0] |                 vec![1u8, 0, 0, 0] | ||||||
|                     .into_iter() |                     .into_iter() | ||||||
|                     .chain(item_id.to_le_bytes().to_vec().into_iter()) |                     .chain(item_id.to_le_bytes().iter().copied()) | ||||||
|                     .chain(amount.to_le_bytes().to_vec().into_iter()) |                     .chain(amount.to_le_bytes().iter().copied()) | ||||||
|                     .collect() |                     .collect() | ||||||
|             }, |             }, | ||||||
|             TradeRequestCommand::RemoveItem(item_id, amount) => { |             TradeRequestCommand::RemoveItem(item_id, amount) => { | ||||||
|                 vec![2u8, 0, 0, 0] |                 vec![2u8, 0, 0, 0] | ||||||
|                     .into_iter() |                     .into_iter() | ||||||
|                     .chain(item_id.to_le_bytes().to_vec().into_iter()) |                     .chain(item_id.to_le_bytes().iter().copied()) | ||||||
|                     .chain(amount.to_le_bytes().to_vec().into_iter()) |                     .chain(amount.to_le_bytes().iter().copied()) | ||||||
|                     .collect() |                     .collect() | ||||||
|             }, |             }, | ||||||
|             TradeRequestCommand::Confirm => { |             TradeRequestCommand::Confirm => { | ||||||
| @ -1178,7 +1178,7 @@ pub enum GameMessage { | |||||||
|     PlayerTelepipe(PlayerTelepipe), |     PlayerTelepipe(PlayerTelepipe), | ||||||
|     NpcSpawn(NpcSpawn), |     NpcSpawn(NpcSpawn), | ||||||
|     ActivateBossWarp(ActivateBossWarp), |     ActivateBossWarp(ActivateBossWarp), | ||||||
|     PlayerJoiningGame(PlayerJoiningGame), |     PlayerJoiningGame(Box<PlayerJoiningGame>), | ||||||
|     PlayerJoiningGame2(PlayerJoiningGame2), |     PlayerJoiningGame2(PlayerJoiningGame2), | ||||||
|     BurstDone(BurstDone), |     BurstDone(BurstDone), | ||||||
|     WordSelect(WordSelect), |     WordSelect(WordSelect), | ||||||
| @ -1346,7 +1346,7 @@ impl PSOPacketData for GameMessage { | |||||||
|             PlayerTelepipe::CMD => Ok(GameMessage::PlayerTelepipe(PlayerTelepipe::from_bytes(&mut cur)?)), |             PlayerTelepipe::CMD => Ok(GameMessage::PlayerTelepipe(PlayerTelepipe::from_bytes(&mut cur)?)), | ||||||
|             NpcSpawn::CMD => Ok(GameMessage::NpcSpawn(NpcSpawn::from_bytes(&mut cur)?)), |             NpcSpawn::CMD => Ok(GameMessage::NpcSpawn(NpcSpawn::from_bytes(&mut cur)?)), | ||||||
|             ActivateBossWarp::CMD => Ok(GameMessage::ActivateBossWarp(ActivateBossWarp::from_bytes(&mut cur)?)), |             ActivateBossWarp::CMD => Ok(GameMessage::ActivateBossWarp(ActivateBossWarp::from_bytes(&mut cur)?)), | ||||||
|             PlayerJoiningGame::CMD => Ok(GameMessage::PlayerJoiningGame(PlayerJoiningGame::from_bytes(&mut cur)?)), |             PlayerJoiningGame::CMD => Ok(GameMessage::PlayerJoiningGame(Box::new(PlayerJoiningGame::from_bytes(&mut cur)?))), | ||||||
|             PlayerJoiningGame2::CMD => Ok(GameMessage::PlayerJoiningGame2(PlayerJoiningGame2::from_bytes(&mut cur)?)), |             PlayerJoiningGame2::CMD => Ok(GameMessage::PlayerJoiningGame2(PlayerJoiningGame2::from_bytes(&mut cur)?)), | ||||||
|             BurstDone::CMD => Ok(GameMessage::BurstDone(BurstDone::from_bytes(&mut cur)?)), |             BurstDone::CMD => Ok(GameMessage::BurstDone(BurstDone::from_bytes(&mut cur)?)), | ||||||
|             WordSelect::CMD => Ok(GameMessage::WordSelect(WordSelect::from_bytes(&mut cur)?)), |             WordSelect::CMD => Ok(GameMessage::WordSelect(WordSelect::from_bytes(&mut cur)?)), | ||||||
| @ -1427,7 +1427,7 @@ impl PSOPacketData for GameMessage { | |||||||
|             _ => Err(PacketParseError::UnknownMessage(byte[0], |             _ => Err(PacketParseError::UnknownMessage(byte[0], | ||||||
|                                                       { |                                                       { | ||||||
|                                                           let mut b = vec![0; len[0] as usize * 4]; |                                                           let mut b = vec![0; len[0] as usize * 4]; | ||||||
|                                                           cur.read(&mut b).unwrap(); |                                                           cur.read_exact(&mut b).unwrap(); | ||||||
|                                                           b.to_vec() |                                                           b.to_vec() | ||||||
|                                                       } |                                                       } | ||||||
|             )), |             )), | ||||||
|  | |||||||
| @ -19,10 +19,10 @@ pub struct PatchWelcome { | |||||||
| impl PatchWelcome { | impl PatchWelcome { | ||||||
|     pub fn new(server_key: u32, client_key: u32) -> PatchWelcome { |     pub fn new(server_key: u32, client_key: u32) -> PatchWelcome { | ||||||
|         PatchWelcome { |         PatchWelcome { | ||||||
|             copyright: b"Patch Server. Copyright SonicTeam, LTD. 2001".clone(), |             copyright: *b"Patch Server. Copyright SonicTeam, LTD. 2001", | ||||||
|             padding: [0; 20], |             padding: [0; 20], | ||||||
|             server_key: server_key, |             server_key, | ||||||
|             client_key: client_key, |             client_key, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -58,8 +58,8 @@ impl StartFileSend { | |||||||
|             *dst = *src |             *dst = *src | ||||||
|         } |         } | ||||||
|         StartFileSend { |         StartFileSend { | ||||||
|             id: id, |             id, | ||||||
|             size: size, |             size, | ||||||
|             filename: f, |             filename: f, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -106,31 +106,22 @@ impl PSOPacket for FileSend { | |||||||
| 
 | 
 | ||||||
| impl std::fmt::Debug for FileSend { | impl std::fmt::Debug for FileSend { | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||||||
|         write!(f, "packet FileSend {{\n").unwrap(); |         writeln!(f, "packet FileSend {{").unwrap(); | ||||||
|         write!(f, "    chunk_num: {:?}\n", self.chunk_num).unwrap(); |         writeln!(f, "    chunk_num: {:?}", self.chunk_num).unwrap(); | ||||||
|         write!(f, "    checksum: {:X?}\n", self.checksum).unwrap(); |         writeln!(f, "    checksum: {:X?}", self.checksum).unwrap(); | ||||||
|         write!(f, "    chunk_size: {:X?}\n", self.chunk_size).unwrap(); |         writeln!(f, "    chunk_size: {:X?}", self.chunk_size).unwrap(); | ||||||
|         write!(f, "    buffer: [...a large array ...]\n").unwrap(); |         writeln!(f, "    buffer: [...a large array ...]").unwrap(); | ||||||
|         write!(f, "}}") |         writeln!(f, "}}") | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | #[derive(Default)] | ||||||
| #[pso_packet(0x08, no_flag)] | #[pso_packet(0x08, no_flag)] | ||||||
| pub struct EndFileSend { | pub struct EndFileSend { | ||||||
|     padding: u32, |     padding: u32, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl EndFileSend { |  | ||||||
|     pub fn new() -> EndFileSend { |  | ||||||
|         EndFileSend { |  | ||||||
|             padding: 0, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| #[pso_packet(0x0B, no_flag)] | #[pso_packet(0x0B, no_flag)] | ||||||
| pub struct PatchStartList { | pub struct PatchStartList { | ||||||
| } | } | ||||||
| @ -169,7 +160,7 @@ impl FileInfo { | |||||||
|             *dst = *src |             *dst = *src | ||||||
|         }; |         }; | ||||||
|         FileInfo { |         FileInfo { | ||||||
|             id: id, |             id, | ||||||
|             filename: f, |             filename: f, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -200,8 +191,8 @@ pub struct FilesToPatchMetadata { | |||||||
| impl FilesToPatchMetadata { | impl FilesToPatchMetadata { | ||||||
|     pub fn new(data_size: u32, file_count: u32) -> FilesToPatchMetadata { |     pub fn new(data_size: u32, file_count: u32) -> FilesToPatchMetadata { | ||||||
|         FilesToPatchMetadata { |         FilesToPatchMetadata { | ||||||
|             data_size: data_size, |             data_size, | ||||||
|             file_count: file_count, |             file_count, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -221,7 +212,7 @@ impl Message { | |||||||
|     pub fn new(mut msg: String) -> Message { |     pub fn new(mut msg: String) -> Message { | ||||||
|         msg.push('\0'); |         msg.push('\0'); | ||||||
|         Message { |         Message { | ||||||
|             msg: msg, |             msg, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -237,8 +228,8 @@ pub struct RedirectClient { | |||||||
| impl RedirectClient { | impl RedirectClient { | ||||||
|     pub fn new(ip: u32, port: u16) -> RedirectClient { |     pub fn new(ip: u32, port: u16) -> RedirectClient { | ||||||
|         RedirectClient { |         RedirectClient { | ||||||
|             ip: ip, |             ip, | ||||||
|             port: port, |             port, | ||||||
|             padding: 0, |             padding: 0, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| use psopacket::{pso_packet, PSOPacketData}; | use psopacket::{pso_packet, PSOPacketData}; | ||||||
| use crate::{PSOPacket, PacketParseError, PSOPacketData}; | use crate::{PSOPacket, PacketParseError, PSOPacketData}; | ||||||
| use crate::utf8_to_utf16_array; | use crate::util::utf8_to_utf16_array; | ||||||
| use crate::packet::messages::GameMessage; | use crate::packet::messages::GameMessage; | ||||||
| //use character::character::FullCharacter;
 | //use character::character::FullCharacter;
 | ||||||
| use crate::character::character as character; | use crate::character::character as character; | ||||||
| @ -26,9 +26,9 @@ impl ShipWelcome { | |||||||
|         let mut copyright = [0u8; 0x60]; |         let mut copyright = [0u8; 0x60]; | ||||||
|         copyright[..0x4B].clone_from_slice(b"Phantasy Star Online Blue Burst Game Server. Copyright 1999-2004 SONICTEAM."); |         copyright[..0x4B].clone_from_slice(b"Phantasy Star Online Blue Burst Game Server. Copyright 1999-2004 SONICTEAM."); | ||||||
|         ShipWelcome { |         ShipWelcome { | ||||||
|             copyright: copyright, |             copyright, | ||||||
|             server_key: server_key, |             server_key, | ||||||
|             client_key: client_key, |             client_key, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -82,13 +82,13 @@ impl ShipBlockList { | |||||||
|                 menu: BLOCK_MENU_ID, |                 menu: BLOCK_MENU_ID, | ||||||
|                 item: 0, |                 item: 0, | ||||||
|                 flags: 0, |                 flags: 0, | ||||||
|                 name: utf8_to_utf16_array!(shipname, 0x11) |                 name: utf8_to_utf16_array(shipname) | ||||||
|             }, |             }, | ||||||
|             blocks: (0..num_blocks).map(|i| BlockEntry { |             blocks: (0..num_blocks).map(|i| BlockEntry { | ||||||
|                 menu: BLOCK_MENU_ID, |                 menu: BLOCK_MENU_ID, | ||||||
|                 item: i as u32 + 1, |                 item: i as u32 + 1, | ||||||
|                 flags: 0, |                 flags: 0, | ||||||
|                 name: utf8_to_utf16_array!(format!("Block {}", i+1), 0x11) |                 name: utf8_to_utf16_array(format!("Block {}", i+1)) | ||||||
|             }).collect() |             }).collect() | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -149,8 +149,8 @@ pub struct BurstDone72 { | |||||||
|     target: u8, |     target: u8, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl BurstDone72 { | impl Default for BurstDone72 { | ||||||
|     pub fn new() -> BurstDone72 { |     fn default() -> BurstDone72 { | ||||||
|         BurstDone72 { |         BurstDone72 { | ||||||
|             msg: 0x72, |             msg: 0x72, | ||||||
|             len: 3, |             len: 3, | ||||||
| @ -169,7 +169,7 @@ pub struct Message { | |||||||
| impl Message { | impl Message { | ||||||
|     pub fn new(msg: GameMessage) -> Message { |     pub fn new(msg: GameMessage) -> Message { | ||||||
|         Message { |         Message { | ||||||
|             msg: msg, |             msg, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -184,7 +184,7 @@ impl DirectMessage { | |||||||
|     pub fn new(target: u32, msg: GameMessage) -> DirectMessage { |     pub fn new(target: u32, msg: GameMessage) -> DirectMessage { | ||||||
|         DirectMessage { |         DirectMessage { | ||||||
|             flag: target, |             flag: target, | ||||||
|             msg: msg, |             msg, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -280,7 +280,7 @@ impl SmallDialog { | |||||||
|         } |         } | ||||||
|         SmallDialog { |         SmallDialog { | ||||||
|             padding: [0; 0x02], |             padding: [0; 0x02], | ||||||
|             msg: msg, |             msg, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -299,7 +299,7 @@ impl RightText { | |||||||
|         } |         } | ||||||
|         RightText { |         RightText { | ||||||
|             padding: [0; 0x02], |             padding: [0; 0x02], | ||||||
|             msg: msg, |             msg, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -317,7 +317,7 @@ impl SmallLeftDialog { | |||||||
|         } |         } | ||||||
|         SmallLeftDialog { |         SmallLeftDialog { | ||||||
|             padding: [0x00004500, 0x45004500], |             padding: [0x00004500, 0x45004500], | ||||||
|             msg: msg, |             msg, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -335,7 +335,7 @@ impl LargeDialog { | |||||||
|         } |         } | ||||||
|         LargeDialog { |         LargeDialog { | ||||||
|             padding: [0, 0x45000000], |             padding: [0, 0x45000000], | ||||||
|             msg: msg, |             msg, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -383,8 +383,8 @@ pub struct LeaveLobby { | |||||||
| impl LeaveLobby { | impl LeaveLobby { | ||||||
|     pub fn new(client: u8, leader: u8) -> LeaveLobby { |     pub fn new(client: u8, leader: u8) -> LeaveLobby { | ||||||
|         LeaveLobby { |         LeaveLobby { | ||||||
|             client: client, |             client, | ||||||
|             leader: leader, |             leader, | ||||||
|             _padding: 0, |             _padding: 0, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -400,8 +400,8 @@ pub struct LeaveRoom { | |||||||
| impl LeaveRoom { | impl LeaveRoom { | ||||||
|     pub fn new(client: u8, leader: u8) -> LeaveRoom { |     pub fn new(client: u8, leader: u8) -> LeaveRoom { | ||||||
|         LeaveRoom { |         LeaveRoom { | ||||||
|             client: client, |             client, | ||||||
|             leader: leader, |             leader, | ||||||
|             _padding: 0, |             _padding: 0, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -418,8 +418,8 @@ impl PlayerChat { | |||||||
|     pub fn new(guildcard: u32, message: String) -> PlayerChat { |     pub fn new(guildcard: u32, message: String) -> PlayerChat { | ||||||
|         PlayerChat { |         PlayerChat { | ||||||
|             unknown: 0x00010000, |             unknown: 0x00010000, | ||||||
|             guildcard: guildcard, |             guildcard, | ||||||
|             message: message, |             message, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -501,7 +501,7 @@ pub struct LobbyEntry { | |||||||
| impl LobbyEntry { | impl LobbyEntry { | ||||||
|     pub fn new(menu_id: u32, lobby_id: u32) -> LobbyEntry { |     pub fn new(menu_id: u32, lobby_id: u32) -> LobbyEntry { | ||||||
|         LobbyEntry { |         LobbyEntry { | ||||||
|             menu_id: menu_id, |             menu_id, | ||||||
|             item_id: lobby_id, |             item_id: lobby_id, | ||||||
|             padding: 0, |             padding: 0, | ||||||
|         } |         } | ||||||
| @ -514,8 +514,8 @@ pub struct LobbyList { | |||||||
|     entries: [LobbyEntry; 16], |     entries: [LobbyEntry; 16], | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl LobbyList { | impl Default for LobbyList { | ||||||
|     pub fn new() -> LobbyList { |     fn default() -> LobbyList { | ||||||
|         let lobbies = (0..16).fold([LobbyEntry::default(); 16], |         let lobbies = (0..16).fold([LobbyEntry::default(); 16], | ||||||
|             |mut acc, index| { |             |mut acc, index| { | ||||||
|                 acc[index].menu_id = LOBBY_MENU_ID; |                 acc[index].menu_id = LOBBY_MENU_ID; | ||||||
|  | |||||||
							
								
								
									
										44
									
								
								src/util.rs
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								src/util.rs
									
									
									
									
									
								
							| @ -2,7 +2,7 @@ | |||||||
| pub fn array_to_utf8<const X: usize>(array: [u8; X]) -> Result<String, std::string::FromUtf8Error> { | pub fn array_to_utf8<const X: usize>(array: [u8; X]) -> Result<String, std::string::FromUtf8Error> { | ||||||
|     String::from_utf8(array.to_vec()) |     String::from_utf8(array.to_vec()) | ||||||
|         .map(|mut s| { |         .map(|mut s| { | ||||||
|             if let Some(index) = s.find("\u{0}") { |             if let Some(index) = s.find('\u{0}') { | ||||||
|                 s.truncate(index); |                 s.truncate(index); | ||||||
|             } |             } | ||||||
|             s |             s | ||||||
| @ -12,36 +12,24 @@ pub fn array_to_utf8<const X: usize>(array: [u8; X]) -> Result<String, std::stri | |||||||
| pub fn array_to_utf16(array: &[u8]) -> String { | pub fn array_to_utf16(array: &[u8]) -> String { | ||||||
|     unsafe { |     unsafe { | ||||||
|         let (_, data, _) = array.align_to(); |         let (_, data, _) = array.align_to(); | ||||||
|         String::from_utf16_lossy(&data).trim_matches(char::from(0)).into() |         String::from_utf16_lossy(data).trim_matches(char::from(0)).into() | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | pub fn utf8_to_array<const N: usize>(s: impl Into<String>) -> [u8; N] { | ||||||
| // TODO: const fn version of this! (helpful with tests)
 |     let mut array = [0u8; N]; | ||||||
| #[macro_export] |     let s = s.into(); | ||||||
| macro_rules! utf8_to_array { |     let bytes = s.as_bytes(); | ||||||
|     ($s: expr, $size: expr) => { |     array[..bytes.len()].clone_from_slice(bytes); | ||||||
|         { |  | ||||||
|             let mut array = [0u8; $size]; |  | ||||||
|             let bytes = $s.as_bytes(); |  | ||||||
|             array[..bytes.len()].clone_from_slice(&bytes); |  | ||||||
|     array |     array | ||||||
| } | } | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| #[macro_export] | pub fn utf8_to_utf16_array<const N: usize>(s: impl Into<String>) -> [u16; N] { | ||||||
| macro_rules! utf8_to_utf16_array { |     let mut array = [0u16; N]; | ||||||
|     ($s: expr, $size: expr) => { |     let bytes = s.into().encode_utf16().collect::<Vec<_>>(); | ||||||
|         { |  | ||||||
|             let mut array = [0u16; $size]; |  | ||||||
|             //let bytes = $s.as_bytes();
 |  | ||||||
|             let bytes = $s.encode_utf16().collect::<Vec<_>>(); |  | ||||||
|     array[..bytes.len()].clone_from_slice(&bytes); |     array[..bytes.len()].clone_from_slice(&bytes); | ||||||
|     array |     array | ||||||
| } | } | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| pub fn vec_to_array<T: Default + Copy, const N: usize>(vec: Vec<T>) -> [T; N] { | pub fn vec_to_array<T: Default + Copy, const N: usize>(vec: Vec<T>) -> [T; N] { | ||||||
|     let mut result: [T; N] = [T::default(); N]; |     let mut result: [T; N] = [T::default(); N]; | ||||||
| @ -53,10 +41,12 @@ pub fn vec_to_array<T: Default + Copy, const N: usize>(vec: Vec<T>) -> [T; N] { | |||||||
| 
 | 
 | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod test { | mod test { | ||||||
|  |     use super::*; | ||||||
|  | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_utf8_to_array() { |     fn test_utf8_to_array() { | ||||||
|         let s = "asdf".to_owned(); |         let s = "asdf".to_owned(); | ||||||
|         let a = utf8_to_array!(s, 8); |         let a = utf8_to_array(s); | ||||||
| 
 | 
 | ||||||
|         let mut e = [0u8; 8]; |         let mut e = [0u8; 8]; | ||||||
|         e[..4].clone_from_slice(b"asdf"); |         e[..4].clone_from_slice(b"asdf"); | ||||||
| @ -64,14 +54,14 @@ mod test { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn utf8_to_utf16_array() { |     fn test_utf8_to_utf16_array() { | ||||||
|         let utf16 = utf8_to_utf16_array!("asdf", 16); |         let utf16 = utf8_to_utf16_array("asdf"); | ||||||
|         assert!(utf16 == [97, 115, 100, 102, 0,0,0,0,0,0,0,0,0,0,0,0]) |         assert!(utf16 == [97, 115, 100, 102, 0,0,0,0,0,0,0,0,0,0,0,0]) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn utf8_to_utf16_array_unicode() { |     fn test_utf8_to_utf16_array_unicode() { | ||||||
|         let utf16 = utf8_to_utf16_array!("あいうえお", 16); |         let utf16 = utf8_to_utf16_array("あいうえお"); | ||||||
|         assert!(utf16 == [0x3042 , 0x3044, 0x3046, 0x3048, 0x304A, 0,0,0,0,0,0,0,0,0,0,0]) |         assert!(utf16 == [0x3042 , 0x3044, 0x3046, 0x3048, 0x304A, 0,0,0,0,0,0,0,0,0,0,0]) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user