1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//! Utilities for [RuneScape] cache interaction.
//! 
//! # Features
//! 
//! The following features are currently provided:
//! - Reading from the cache.
//! - Huffman buffer access.
//! - Checksum with simple-to-use validation.
//! - Compression and decompression:
//!   - [Gzip]
//!   - [Bzip2]
//! 
//! # Quick Start
//! 
//! A possible use case of this utility is to read data from the RuneScape cache and send them to the 
//! client during the update protocol.
//! The example listed below quickly shows how you can pass the `index_id` and the `archive_id` to the cache
//! and get the correct data to send to the client.
//! 
//! ```
//! # use std::net::TcpStream;
//! # use std::io::Write;
//! use rscache::{ Cache, CacheError, LinkedListExt };
//! # struct UpdatePacket { 
//! #   pub index_id: u8,
//! #   pub archive_id: u16
//! # }
//! 
//! fn process_update(packet: UpdatePacket, stream: &mut TcpStream) -> Result<(), CacheError> {
//! #    let cache = Cache::new("path/to/cache")?;
//!     // read the specified archive from the given index to an owned vector.
//!     let buffer = cache.read(packet.index_id, packet.archive_id)?.to_vec();
//!     
//!     // ... format buffer.
//! #    let formatted_buffer = buffer;
//! 
//!     // send formatted_buffer to client.
//!     stream.write_all(&formatted_buffer)?;
//! 
//!     Ok(())
//! }
//! ```
//! 
//! In the above example the data that was read from the cache is transformed into a vector of bytes.
//! You can also use the `LinkedList<&[u8]>` to `iter()` over the `data_block`s instead of making the bytes owned.
//! 
//! ```
//! # use std::net::TcpStream;
//! # use std::io::Write;
//! # use rscache::{ Cache, CacheError, LinkedListExt };
//! # struct UpdatePacket { 
//! #   pub index_id: u8,
//! #   pub archive_id: u16
//! # }
//! # fn process_update(packet: UpdatePacket, stream: &mut TcpStream) -> Result<(), CacheError> {
//! #    let cache = Cache::new("path/to/cache")?;
//! #    // read the specified archive from the given index to an owned vector.
//! let buffer = cache.read(packet.index_id, packet.archive_id)?;
//! 
//! for data_block in buffer.iter() {
//!     // data_block contains 512 byte slices that directly link into the MainData buffer.
//!     // this can be useful when creating a new formatted buffer.
//! }
//! #    Ok(())
//! # }
//! ```
//! 
//! # Definitions
//! 
//! Currently only item definitions are supported.
//! These definitions are fields that can be looked up for a certain item id.
//! i.e. you need to know if a certain item is stackable or members only the [ItemDefinition](struct.ItemDefinition.html) struct
//! contains that information.
//! 
//! See the [ItemDefinition](struct.ItemDefinition.html) struct to view the available fields each item might have.
//! 
//! ### Example
//! 
//! ```
//! # use rscache::{ Cache, CacheError };
//! use rscache::ItemLoader;
//! 
//! # fn main() -> Result<(), CacheError> {
//! # let path = "./data/cache";
//! # let cache = Cache::new(path)?;
//! let item_loader = ItemLoader::new(&cache)?;
//! 
//! // magic logs id = 1513
//! let magic_logs = item_loader.load(1513);
//! 
//! match magic_logs {
//!     Some(item_def) => {
//!         assert_eq!("Magic logs", item_def.name);
//!         assert_eq!(false, item_def.stackable);
//!         assert_eq!(true, item_def.members_only);
//!     },
//!     None => (),
//! }
//! # Ok(())
//! # }
//! ```
//! 
//! [RuneScape]: https://oldschool.runescape.com/
//! [Gzip]: https://crates.io/crates/libflate
//! [Bzip2]: https://crates.io/crates/bzip2

#![warn(clippy::all, clippy::nursery, clippy::clone_on_ref_ptr, clippy::redundant_clone, clippy::default_trait_access, clippy::expl_impl_clone_on_copy,
    clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map, clippy::filter_map_next, clippy::find_map, clippy::get_unwrap,
    clippy::items_after_statements, clippy::large_digit_groups, clippy::map_flatten, clippy::match_same_arms, clippy::maybe_infinite_iter, clippy::mem_forget,
    clippy::missing_inline_in_public_items, clippy::multiple_inherent_impl, clippy::mut_mut, clippy::needless_continue,
    clippy::needless_pass_by_value, clippy::option_map_unwrap_or, clippy::option_map_unwrap_or_else, clippy::pub_enum_variant_names, clippy::unused_self,
    clippy::result_map_unwrap_or_else, clippy::similar_names, clippy::single_match_else, clippy::too_many_lines, clippy::type_repetition_in_bounds,
    clippy::unseparated_literal_suffix, clippy::used_underscore_binding)]

#![allow(clippy::suspicious_else_formatting)]

mod cache;
mod checksum;
mod errors;
mod traits;
mod definitions;
pub mod codec;

pub use cache::Cache;
pub use checksum::Checksum;
pub use errors::*;
pub use traits::*;
pub use definitions::*;

mod djd2 {
    #[inline]
    pub fn hash(string: &str) -> i32 {
        let mut hash = 0;

        for index in 0..string.len() {
            hash = string.chars().nth(index).unwrap() as i32 + ((hash << 5) - hash);
        }
        
        hash
    }
}