Compare commits
8 Commits
b33dc356c4
...
bd13092188
Author | SHA1 | Date |
---|---|---|
an | bd13092188 | |
an | 745f32f3bd | |
an | 49b4b56aea | |
an | 9b73cb3513 | |
an | f5ceea654e | |
an | 9bea0d895f | |
an | 25488e7faa | |
an | 8d504612cb |
|
@ -18,6 +18,7 @@ members = ["source/leela", "source/tycho"]
|
|||
bitflags = "1.0"
|
||||
failure = {version = "0.1", features = ["std"]}
|
||||
serde = {version = "1.0", features = ["derive"]}
|
||||
memchr = "2.0"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 1
|
||||
|
|
138
LICENSE
138
LICENSE
|
@ -1,19 +1,125 @@
|
|||
Copyright (c) 2018-2019 Alison Sanderson
|
||||
To the extent possible under law, I, Alison Sanderson, have waived all
|
||||
copyright and related or neighboring rights to this Document as described by
|
||||
the Creative Commons Zero license as follows:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
Creative Commons Legal Code
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
CC0 1.0 Universal
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without fear
|
||||
of later claims of infringement build upon, modify, incorporate in other
|
||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||
and for any purposes, including without limitation commercial purposes.
|
||||
These owners may contribute to the Commons to promote the ideal of a free
|
||||
culture and the further production of creative, cultural and scientific
|
||||
works, or to gain reputation or greater distribution for their Work in
|
||||
part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not
|
||||
limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation
|
||||
thereof, including any amended or successor version of such
|
||||
directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||
of action, whether now known or unknown (including existing as well as
|
||||
future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||
treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional
|
||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||
member of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal or
|
||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||
as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||
be judged legally invalid or ineffective under applicable law, then the
|
||||
Waiver shall be preserved to the maximum extent permitted taking into
|
||||
account Affirmer's express Statement of Purpose. In addition, to the
|
||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
maximum duration provided by applicable law or treaty (including future
|
||||
time extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any
|
||||
reason be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||
of the License, and in such case Affirmer hereby affirms that he or she
|
||||
will not (i) exercise any of his or her remaining Copyright and Related
|
||||
Rights in the Work or (ii) assert any associated claims and causes of
|
||||
action with respect to the Work, in either case contrary to Affirmer's
|
||||
express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or
|
||||
the present or absence of errors, whether or not discoverable, all to
|
||||
the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the Work.
|
||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the
|
||||
Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
To the extent possible under law, I, Alison Sanderson, have waived all
|
||||
copyright and related or neighboring rights to this Document as described by
|
||||
the Creative Commons Zero license linked below.
|
||||
the Creative Commons Zero license included in this project under the `LICENSE`
|
||||
file, or if unavailable, the link below:
|
||||
|
||||
<http://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
|
@ -10,8 +11,8 @@ All of the information in this Document is original research. Marathon and
|
|||
Forge are owned by Bungie, Inc. QuickDraw, QuickTime and Macintosh are owned by
|
||||
Apple. Aleph One (also referred to as A1 in this Document) is owned by Bungie,
|
||||
Inc. et al. Igni Ferroque, Ferro, and Atque are owned by Gregory Smith
|
||||
(treellama.) Maraiah is owned by Project Golan. Any other copyrights belong to
|
||||
their respective owners.
|
||||
(treellama.) Any other copyrights not mentioned here belong to their respective
|
||||
owners and not me.
|
||||
|
||||
If you need explanation on anything in this document don't hesitate to ask me.
|
||||
Contact information is available at <http://greyserv.net>.
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
Maraiah
|
||||
=======
|
||||
|
||||
e
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
MIT
|
||||
Public domain tools for editing data for the Marathon engine. The name
|
||||
"Maraiah" is derived from the Japanese transliteration of "Mariah," and is
|
||||
pronounced "mah-rye-uhh" (/mɑɹaɪʌ/ in IPA.) It has no special meaning.
|
||||
|
|
|
@ -156,17 +156,26 @@ macro_rules! _durandal_read_impl {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[macro_export(local_inner_macros)]
|
||||
#[macro_export]
|
||||
macro_rules! read_data {
|
||||
(
|
||||
$sz:expr , $ty:ident in $b:ident =>
|
||||
$( $nam:ident = $t:ident [ $n:expr ] $( $ex:ident )* ; )*
|
||||
) => {
|
||||
$crate::check_data!($sz, $b);
|
||||
$($crate::_durandal_read_impl!($ty $b $nam $($ex)* $t $n);)*
|
||||
};
|
||||
}
|
||||
|
||||
/// Checks if there is enough data in `b`.
|
||||
#[macro_export]
|
||||
macro_rules! check_data {
|
||||
(
|
||||
$sz:expr , $b:ident
|
||||
) => {
|
||||
if $b.len() < $sz {
|
||||
return Err(err_msg("not enough data"));
|
||||
}
|
||||
|
||||
$($crate::_durandal_read_impl!($ty $b $nam $($ex)* $t $n);)*
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -342,8 +351,7 @@ pub fn rd_array_num<T, F>(b: &[u8], n: usize, read: F)
|
|||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// A panic will occur if the `read` function returns a disjoint index or
|
||||
/// otherwise panics (by an out of bounds index to `b` or otherwise.)
|
||||
/// A panic will occur if the `read` function panics.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
|
@ -360,11 +368,7 @@ pub fn rd_ofstable<T, F>(b: &[u8],
|
|||
|
||||
for _ in 0..num {
|
||||
let ofs = usize_from_u32(u32b(&b[p..p + 4]));
|
||||
|
||||
if ofs >= b.len() {
|
||||
bail!("not enough data");
|
||||
}
|
||||
|
||||
check_data!(ofs, b);
|
||||
v.push(read(&b[ofs..])?);
|
||||
p += 4;
|
||||
}
|
||||
|
@ -383,7 +387,7 @@ impl OptU16
|
|||
///
|
||||
/// assert_eq!(OptU16::none(), OptU16::from_repr(u16::max_value()));
|
||||
/// ```
|
||||
pub const fn none() -> Self {OptU16(None)}
|
||||
pub const fn none() -> Self {Self(None)}
|
||||
|
||||
/// Creates an `OptU16` from a `u16`.
|
||||
pub fn from_repr(n: u16) -> Self
|
||||
|
@ -408,7 +412,7 @@ impl OptU16
|
|||
/// assert_eq!(OptU16::from_repr(u16max).get_repr(), u16max);
|
||||
/// assert_eq!(OptU16::from_repr(0u16).get_repr(), 0u16);
|
||||
/// ```
|
||||
pub fn get_repr(&self) -> u16
|
||||
pub fn get_repr(self) -> u16
|
||||
{
|
||||
match self.0 {
|
||||
None => u16::max_value(),
|
||||
|
@ -427,7 +431,7 @@ impl OptU16
|
|||
/// assert_eq!(OptU16::from_repr(u16::max_value()).get(), None);
|
||||
/// assert_eq!(OptU16::from_repr(0u16).get(), Some(0u16));
|
||||
/// ```
|
||||
pub fn get(&self) -> Option<u16>
|
||||
pub fn get(self) -> Option<u16>
|
||||
{
|
||||
match self.0 {
|
||||
None => None,
|
||||
|
|
|
@ -2,108 +2,160 @@
|
|||
|
||||
use crate::durandal::err::*;
|
||||
|
||||
/// Reads `width` bits from `b` starting at bit `cr_ptr` into an integer.
|
||||
/// Reads `width` bits from `b` starting at bit `cr_bit` into an integer, most
|
||||
/// significant bit first.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// The function will return an error if `width` is 0 or more than 64, or if
|
||||
/// `(cr_ptr + width - 1) / 8` would overflow an index into `b`.
|
||||
pub fn read_bits(b: &[u8], cr_ptr: usize, width: u8) -> ResultS<(usize, u64)>
|
||||
/// The function will return an error if `width` is more than 64, or if
|
||||
/// `(cr_bit + width - 1) / 8` would overflow an index into `b`.
|
||||
pub fn read_bits_b(b: &[u8], cr_bit: usize, width: u8) -> ResultS<u64>
|
||||
{
|
||||
if width < 1 || width > 64 {
|
||||
if width == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
if width > 64 {
|
||||
bail!("invalid number of bits");
|
||||
}
|
||||
|
||||
let nx_ptr = cr_ptr + usize::from(width);
|
||||
let ed_ptr = nx_ptr - 1;
|
||||
let last = (cr_bit + usize::from(width) - 1) / 8;
|
||||
|
||||
let first_byte = cr_ptr / 8;
|
||||
let last_byte = ed_ptr / 8;
|
||||
|
||||
if b.len() <= last_byte {
|
||||
if last >= b.len() {
|
||||
bail!("not enough data");
|
||||
}
|
||||
|
||||
let first_bits = cr_ptr as u32 % 8;
|
||||
let last_bits = nx_ptr as u32 % 8;
|
||||
let mut byte_ptr = cr_bit / 8;
|
||||
let mut bits_ptr = cr_bit % 8;
|
||||
|
||||
let last_mask = ((1u128 << last_bits) - 1) as u64;
|
||||
let mut res = 0;
|
||||
|
||||
let num_bytes = last_byte - first_byte;
|
||||
for _ in 0..width {
|
||||
res <<= 1;
|
||||
|
||||
let bytes = get_bytes(b, num_bytes, first_byte);
|
||||
if b[byte_ptr] & (1 << bits_ptr) != 0 {
|
||||
res |= 1;
|
||||
}
|
||||
|
||||
let bits = u64::from_be_bytes(bytes);
|
||||
let bits = bits.wrapping_shl(first_bits);
|
||||
let bits = bits >> (64 - width);
|
||||
bits_ptr += 1;
|
||||
|
||||
// special case for over byte boundary
|
||||
let bits = if num_bytes == 8 {
|
||||
let lbyt = u64::from(b[last_byte]);
|
||||
let lbyt = lbyt >> (8 - last_bits);
|
||||
let lbyt = lbyt & last_mask;
|
||||
if bits_ptr > 7 {
|
||||
bits_ptr = 0;
|
||||
byte_ptr += 1;
|
||||
}
|
||||
}
|
||||
|
||||
(bits & !last_mask) | lbyt
|
||||
} else {
|
||||
bits
|
||||
};
|
||||
|
||||
Ok((nx_ptr, bits))
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn get_bytes(b: &[u8], num_bytes: usize, f: usize) -> [u8; 8]
|
||||
/// The same as `read_bits_b`, but least-significant bit first.
|
||||
pub fn read_bits_l(b: &[u8], cr_bit: usize, width: u8) -> ResultS<u64>
|
||||
{
|
||||
match num_bytes {
|
||||
8 |
|
||||
7 => [b[f], b[f+1], b[f+2], b[f+3], b[f+4], b[f+5], b[f+6], b[f+7]],
|
||||
6 => [b[f], b[f+1], b[f+2], b[f+3], b[f+4], b[f+5], b[f+6], 0],
|
||||
5 => [b[f], b[f+1], b[f+2], b[f+3], b[f+4], b[f+5], 0, 0],
|
||||
4 => [b[f], b[f+1], b[f+2], b[f+3], b[f+4], 0, 0, 0],
|
||||
3 => [b[f], b[f+1], b[f+2], b[f+3], 0, 0, 0, 0],
|
||||
2 => [b[f], b[f+1], b[f+2], 0, 0, 0, 0, 0],
|
||||
1 => [b[f], b[f+1], 0, 0, 0, 0, 0, 0],
|
||||
0 => [b[f], 0, 0, 0, 0, 0, 0, 0],
|
||||
_ => panic!("invalid number of bytes to read ({})", num_bytes),
|
||||
if width == 0 {
|
||||
Ok(0)
|
||||
} else {
|
||||
let res = read_bits_b(b, cr_bit, width)?;
|
||||
|
||||
Ok(reverse_bits(res) >> (64 - width))
|
||||
}
|
||||
}
|
||||
|
||||
fn reverse_bits(v: u64) -> u64
|
||||
{
|
||||
// TODO: change this to u64::reverse_bits when stabilized
|
||||
let v = v >> 1 & 0x5555_5555_5555_5555 | ((v & 0x5555_5555_5555_5555) << 1);
|
||||
let v = v >> 2 & 0x3333_3333_3333_3333 | ((v & 0x3333_3333_3333_3333) << 2);
|
||||
let v = v >> 4 & 0x0F0F_0F0F_0F0F_0F0F | ((v & 0x0F0F_0F0F_0F0F_0F0F) << 4);
|
||||
v.swap_bytes()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bit_tests()
|
||||
{
|
||||
const INPUT: &[u8] = &[0b011_00101, 0b10101010, 0b00010000, 0b00000000,
|
||||
const INPUT: &[u8] = &[0b01100101, 0b10101010, 0b00010000, 0b00000000,
|
||||
0b11111111, 0b11100001, 0b10101100, 0b00110011,
|
||||
0b10_1001_01, 0b11100_000, 0b00000111, 0b000000_01,
|
||||
0b11001010, 0b10101111, 0b00101011, 0b0_1101010,
|
||||
0b11010101, 0b10100011, 0b01010101, 0b11_000001];
|
||||
0b10100101, 0b11100000, 0b00000111, 0b00000001,
|
||||
0b11001010, 0b10101111, 0b00101011, 0b01101010,
|
||||
0b11010101, 0b10100011, 0b01010101, 0b11000001];
|
||||
|
||||
let (p, n) = read_bits(INPUT, 0, 3).unwrap();
|
||||
assert_eq!(n, 0b011);
|
||||
let mut p = 0;
|
||||
|
||||
let (p, n) = read_bits(INPUT, p, 63).unwrap();
|
||||
assert_eq!(n, 0x16A8_4003_FF86_B0CE);
|
||||
let n = read_bits_b(INPUT, p, 3).unwrap();
|
||||
assert_eq!(n, 0b101);
|
||||
p += 3;
|
||||
|
||||
let (p, n) = read_bits(INPUT, p, 4).unwrap();
|
||||
let n = read_bits_b(INPUT, p, 63).unwrap();
|
||||
assert_eq!(n, 0b001100101010100001000000000001111111110000111001101011100110010);
|
||||
p += 63;
|
||||
|
||||
let n = read_bits_b(INPUT, p, 4).unwrap();
|
||||
assert_eq!(n, 0b1001);
|
||||
p += 4;
|
||||
|
||||
let (p, n) = read_bits(INPUT, p, 7).unwrap();
|
||||
assert_eq!(n, 0b0111100);
|
||||
let n = read_bits_b(INPUT, p, 7).unwrap();
|
||||
assert_eq!(n, 0b0100000);
|
||||
p += 7;
|
||||
|
||||
let (p, n) = read_bits(INPUT, p, 17).unwrap();
|
||||
assert_eq!(n, 0b00000000111000000);
|
||||
let n = read_bits_b(INPUT, p, 17).unwrap();
|
||||
assert_eq!(n, 0b11111100000100000);
|
||||
p += 17;
|
||||
|
||||
let (p, n) = read_bits(INPUT, p, 27).unwrap();
|
||||
assert_eq!(n, 0b011100101010101111001010110);
|
||||
let n = read_bits_b(INPUT, p, 27).unwrap();
|
||||
assert_eq!(n, 0b000101001111110101110101000);
|
||||
p += 27;
|
||||
|
||||
let (p, n) = read_bits(INPUT, p, 33).unwrap();
|
||||
assert_eq!(n, 0b110101011010101101000110101010111);
|
||||
let n = read_bits_b(INPUT, p, 33).unwrap();
|
||||
assert_eq!(n, 0b101011010101011110001011010101010);
|
||||
p += 33;
|
||||
|
||||
let (p, n) = read_bits(INPUT, p, 6).unwrap();
|
||||
assert_eq!(n, 1);
|
||||
let n = read_bits_b(INPUT, p, 6).unwrap();
|
||||
assert_eq!(n, 0b000011);
|
||||
p += 6;
|
||||
|
||||
let e = read_bits(INPUT, p, 1);
|
||||
let e = read_bits_b(INPUT, p, 1);
|
||||
assert!(if let Err(_) = e {true} else {false});
|
||||
|
||||
let e = read_bits(INPUT, p, 2);
|
||||
let e = read_bits_b(INPUT, p, 2);
|
||||
assert!(if let Err(_) = e {true} else {false});
|
||||
|
||||
let mut p = 0;
|
||||
|
||||
let n = read_bits_l(INPUT, 0, 3).unwrap();
|
||||
assert_eq!(n, 0b101);
|
||||
p += 3;
|
||||
|
||||
let n = read_bits_l(INPUT, p, 63).unwrap();
|
||||
assert_eq!(n, 0b010011001110101100111000011111111100000000000100001010101001100);
|
||||
p += 63;
|
||||
|
||||
let n = read_bits_l(INPUT, p, 4).unwrap();
|
||||
assert_eq!(n, 0b1001);
|
||||
p += 4;
|
||||
|
||||
let n = read_bits_l(INPUT, p, 7).unwrap();
|
||||
assert_eq!(n, 0b0000010);
|
||||
p += 7;
|
||||
|
||||
let n = read_bits_l(INPUT, p, 17).unwrap();
|
||||
assert_eq!(n, 0b00000100000111111);
|
||||
p += 17;
|
||||
|
||||
let n = read_bits_l(INPUT, p, 27).unwrap();
|
||||
assert_eq!(n, 0b000101011101011111100101000);
|
||||
p += 27;
|
||||
|
||||
let n = read_bits_l(INPUT, p, 33).unwrap();
|
||||
assert_eq!(n, 0b010101010110100011110101010110101);
|
||||
p += 33;
|
||||
|
||||
let n = read_bits_l(INPUT, p, 6).unwrap();
|
||||
assert_eq!(n, 0b110000);
|
||||
p += 6;
|
||||
|
||||
let e = read_bits_l(INPUT, p, 1);
|
||||
assert!(if let Err(_) = e {true} else {false});
|
||||
|
||||
let e = read_bits_l(INPUT, p, 2);
|
||||
assert!(if let Err(_) = e {true} else {false});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//! Fixed point numbers.
|
||||
#![allow(clippy::use_self)]
|
||||
|
||||
use std::{fmt::{self, Write}, ops::*};
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
//! Text conversion utilities.
|
||||
|
||||
use crate::durandal::err::*;
|
||||
|
||||
/// Formats a binary size string for any given number.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -103,14 +101,17 @@ pub fn mac_roman_conv(s: &[u8]) -> String
|
|||
/// ```
|
||||
/// use maraiah::durandal::text::mac_roman_cstr;
|
||||
///
|
||||
/// assert_eq!(mac_roman_cstr(b"I\xd5ve awaken\0ed").unwrap(), "I’ve awaken");
|
||||
/// assert_eq!(mac_roman_cstr(b"I\xd5ve awaken\0ed"), "I’ve awaken");
|
||||
/// assert_eq!(mac_roman_cstr(b"I\xd5ve awaken\0"), "I’ve awaken");
|
||||
/// assert_eq!(mac_roman_cstr(b"I\xd5ve awaken"), "I’ve awaken");
|
||||
/// ```
|
||||
pub fn mac_roman_cstr(s: &[u8]) -> ResultS<String>
|
||||
#[inline]
|
||||
pub fn mac_roman_cstr(s: &[u8]) -> String
|
||||
{
|
||||
if let Some(s) = s.split(|&n| n == 0).nth(0) {
|
||||
Ok(mac_roman_conv(s))
|
||||
if let Some(n) = memchr::memchr(0, s) {
|
||||
mac_roman_conv(&s[..n])
|
||||
} else {
|
||||
bail!("no null in C string");
|
||||
mac_roman_conv(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,44 @@
|
|||
//! DEFLATE loader.
|
||||
|
||||
use crate::durandal::err::*;
|
||||
use crate::durandal::{bit::*, err::*};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
/// Loads a ZLIB file header.
|
||||
pub fn load_zlib_header(b: &[u8]) -> ResultS<usize>
|
||||
{
|
||||
const CM: u8 = 0b0000_1111;
|
||||
const CINFO: u8 = 0b1111_0000;
|
||||
const FDICT: u8 = 0b0010_0000;
|
||||
|
||||
read_data! {
|
||||
2, BE in b =>
|
||||
fcheck = u16[0];
|
||||
cmf = u8[0];
|
||||
flg = u8[1];
|
||||
}
|
||||
|
||||
let cm = cmf & CM;
|
||||
let cinfo = cmf & CINFO >> 4;
|
||||
|
||||
if cm != 8 || fcheck % 31 != 0 || cinfo > 7 {
|
||||
bail!("not zlib format");
|
||||
}
|
||||
|
||||
if flg & FDICT != 0 {
|
||||
bail!("dictionary not supported");
|
||||
}
|
||||
|
||||
Ok(2)
|
||||
}
|
||||
|
||||
/// Loads a GZIP file header.
|
||||
pub fn load_gzip_header(b: &[u8]) -> ResultS<usize>
|
||||
{
|
||||
const FHCRC: u8 = 1 << 1;
|
||||
const FEXTRA: u8 = 1 << 2;
|
||||
const FNAME: u8 = 1 << 3;
|
||||
const FCOMMENT: u8 = 1 << 4;
|
||||
const FHCRC: u8 = 1 << 1;
|
||||
const FEXTRA: u8 = 1 << 2;
|
||||
const FNAME: u8 = 1 << 3;
|
||||
const FCOMMENT: u8 = 1 << 4;
|
||||
const FRESERVED: u8 = 0xE0;
|
||||
|
||||
read_data! {
|
||||
10, LE in b =>
|
||||
|
@ -23,26 +53,27 @@ pub fn load_gzip_header(b: &[u8]) -> ResultS<usize>
|
|||
|
||||
let mut p = 10;
|
||||
|
||||
if fl & FRESERVED != 0 {
|
||||
bail!("reserved flags set");
|
||||
}
|
||||
|
||||
if fl & FEXTRA != 0 {
|
||||
read_data!(p + 2, LE in b => xlen = u16[p] usize;);
|
||||
|
||||
if p + 2 + xlen > b.len() {
|
||||
bail!("not enough data");
|
||||
}
|
||||
check_data!(p + 2 + xlen, b);
|
||||
|
||||
p += xlen;
|
||||
}
|
||||
|
||||
if fl & FNAME != 0 {
|
||||
p = skip_zero_terminated_item(&b[p..])?;
|
||||
p += skip_zero_terminated_item(&b[p..])?;
|
||||
}
|
||||
|
||||
if fl & FCOMMENT != 0 {
|
||||
p = skip_zero_terminated_item(&b[p..])?;
|
||||
p += skip_zero_terminated_item(&b[p..])?;
|
||||
}
|
||||
|
||||
if fl & FHCRC != 0 {
|
||||
read_data!(p + 2, LE in b => _crc = u16[p];);
|
||||
check_data!(p + 2, b);
|
||||
|
||||
p += 2;
|
||||
}
|
||||
|
@ -53,10 +84,315 @@ pub fn load_gzip_header(b: &[u8]) -> ResultS<usize>
|
|||
fn skip_zero_terminated_item(b: &[u8]) -> ResultS<usize>
|
||||
{
|
||||
if let Some(i) = b.iter().position(|&n| n == 0) {
|
||||
Ok(i)
|
||||
Ok(i + 1)
|
||||
} else {
|
||||
bail!("no end of zero terminated item");
|
||||
}
|
||||
}
|
||||
|
||||
/// Decompresses a DEFLATE compressed bitstream.
|
||||
pub fn load_deflate(b: &[u8]) -> ResultS<(usize, Vec<u8>)>
|
||||
{
|
||||
let mut v = Vec::new();
|
||||
let p = stream_deflate(&mut v, b, 0)?;
|
||||
|
||||
Ok((p / 8, v))
|
||||
}
|
||||
|
||||
fn stream_deflate(v: &mut Vec<u8>, b: &[u8], p: usize) -> ResultS<usize>
|
||||
{
|
||||
let bfinal = read_bits_l(b, p, 1)?;
|
||||
let btype = read_bits_l(b, p + 1, 2)?;
|
||||
|
||||
let p = p + 3;
|
||||
|
||||
let p = match btype {
|
||||
0b10 => stream_dynamic(v, b, p)?,
|
||||
0b01 => stream_s_table(v, b, p)?,
|
||||
0b00 => stream_literal(v, b, p)?,
|
||||
_ => bail!("bad btype"),
|
||||
};
|
||||
|
||||
if bfinal == 0 {
|
||||
stream_deflate(v, b, p)
|
||||
} else {
|
||||
Ok(p)
|
||||
}
|
||||
}
|
||||
|
||||
fn stream_dynamic(v: &mut Vec<u8>, b: &[u8], mut p: usize) -> ResultS<usize>
|
||||
{
|
||||
const CODE_ORDERING: [usize; NUM_CODES] = [
|
||||
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
||||
];
|
||||
|
||||
const NUM_CODES: usize = 19;
|
||||
|
||||
const MAX_LIT_CODES: usize = 286;
|
||||
const MAX_DST_CODES: usize = 30;
|
||||
|
||||
// read header (number of literal alphabet codes, number of distance
|
||||
// alphabet codes, and number of lengths for decoding the alphabet)
|
||||
let hlit = read_bits_l(b, p, 5)?; p += 5;
|
||||
let hdist = read_bits_l(b, p, 5)?; p += 5;
|
||||
let hclen = read_bits_l(b, p, 4)?; p += 4;
|
||||
|
||||
let hlit = 257 + hlit as usize;
|
||||
let hdist = 1 + hdist as usize;
|
||||
let hclen = 4 + hclen as usize;
|
||||
|
||||
let alphabet_total = hlit + hdist;
|
||||
|
||||
// first, get the huffman coding for the alphabet (which is also compressed)
|
||||
let mut code_lengths = [0; NUM_CODES];
|
||||
|
||||
for i in 0..hclen {
|
||||
let len = read_bits_l(b, p, 3)? as u16;
|
||||
p += 3;
|
||||
|
||||
code_lengths[CODE_ORDERING[i]] = len;
|
||||
}
|
||||
|
||||
let code_lengths = HuffmanTable::new(&code_lengths)?;
|
||||
let mut alphabet = [0; MAX_LIT_CODES + MAX_DST_CODES];
|
||||
|
||||
// then, we decode the alphabet (doing both types at the same time, because
|
||||
// they're encoded the same anyways)
|
||||
let mut i = 0;
|
||||
while i < alphabet_total {
|
||||
let (bits, sym) = code_lengths.decode(b, p)?;
|
||||
p += bits;
|
||||
|
||||
match sym {
|
||||
0..=15 => {
|
||||
// raw code
|
||||
alphabet[i] = sym;
|
||||
i += 1;
|
||||
}
|
||||
16 => {
|
||||
// copy previous code 3-6 times
|
||||
if i == 0 {bail!("cannot copy on first alphabet code");}
|
||||
|
||||
let len = usize::from(read_bits_l(b, p, 2)? as u8 + 3);
|
||||
let lst = alphabet[i - 1];
|
||||
p += 2;
|
||||
|
||||
for _ in 0..len {
|
||||
alphabet[i] = lst;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
17 => {
|
||||
// repeat '0' 3-10 times
|
||||
let len = usize::from(read_bits_l(b, p, 3)? as u8 + 3);
|
||||
p += 3;
|
||||
|
||||
for _ in 0..len {
|
||||
alphabet[i] = 0;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
18 => {
|
||||
// repeat '0' 11-138 times
|
||||
let len = usize::from(read_bits_l(b, p, 7)? as u8 + 11);
|
||||
p += 7;
|
||||
|
||||
for _ in 0..len {
|
||||
alphabet[i] = 0;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
bail!("bad symbol in alphabet");
|
||||
}
|
||||
}
|
||||
|
||||
if i > alphabet_total {
|
||||
bail!("too many codes");
|
||||
}
|
||||
}
|
||||
|
||||
if alphabet[256] == 0 {
|
||||
bail!("no way to end block");
|
||||
}
|
||||
|
||||
let len_sta = 0;
|
||||
let len_end = hlit;
|
||||
let dst_sta = len_end;
|
||||
let dst_end = dst_sta + hdist;
|
||||
|
||||
let table_len = HuffmanTable::new(&alphabet[len_sta..len_end])?;
|
||||
let table_dst = HuffmanTable::new(&alphabet[dst_sta..dst_end])?;
|
||||
|
||||
output_tables(v, b, p, table_len, table_dst)
|
||||
}
|
||||
|
||||
fn stream_s_table(_v: &mut Vec<u8>, _b: &[u8], _p: usize) -> ResultS<usize>
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn stream_literal(v: &mut Vec<u8>, b: &[u8], p: usize) -> ResultS<usize>
|
||||
{
|
||||
// copy data directly from byte boundary
|
||||
let mut p = p / 8 + 1;
|
||||
|
||||
read_data! {
|
||||
p + 4, LE in b =>
|
||||
len = u16[p] usize;
|
||||
}
|
||||
|
||||
p += 4;
|
||||
v.extend_from_slice(ok!(b.get(p..p + len), "not enough data")?);
|
||||
|
||||
Ok((p + len) * 8)
|
||||
}
|
||||
|
||||
fn output_tables(v: &mut Vec<u8>,
|
||||
b: &[u8],
|
||||
mut p: usize,
|
||||
table_len: HuffmanTable,
|
||||
table_dst: HuffmanTable)
|
||||
-> ResultS<usize>
|
||||
{
|
||||
const LEN_BASE: [usize; 29] = [
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
|
||||
67, 83, 99, 115, 131, 163, 195, 227, 258
|
||||
];
|
||||
|
||||
const LEN_EXTRA_BITS: [u8; 29] = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
|
||||
5, 5, 5, 5, 0
|
||||
];
|
||||
|
||||
const DST_BASE: [usize; 30] = [
|
||||
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
|
||||
769, 1025, 1537, 2049, 3073, 4097, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001
|
||||
];
|
||||
|
||||
const DST_EXTRA_BITS: [u8; 30] = [
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
|
||||
11, 11, 12, 12, 13, 13
|
||||
];
|
||||
|
||||
let (bits, sym) = table_len.decode(b, p)?;
|
||||
p += bits;
|
||||
|
||||
match sym.cmp(&256) {
|
||||
Ordering::Less => {
|
||||
v.push(sym as u8);
|
||||
output_tables(v, b, p, table_len, table_dst)
|
||||
}
|
||||
Ordering::Equal => {
|
||||
Ok(p)
|
||||
}
|
||||
Ordering::Greater => {
|
||||
let sym = sym - 257;
|
||||
|
||||
if sym > 29 {
|
||||
Err(err_msg("invalid fixed code"))
|
||||
} else {
|
||||
let sym = usize::from(sym);
|
||||
|
||||
let bits = LEN_EXTRA_BITS[sym];
|
||||
let leng = LEN_BASE[sym] + read_bits_l(b, p, bits)? as usize;
|
||||
p += usize::from(bits);
|
||||
|
||||
let (bits, sym) = table_dst.decode(b, p)?;
|
||||
p += bits;
|
||||
|
||||
let sym = usize::from(sym);
|
||||
|
||||
let bits = DST_EXTRA_BITS[sym];
|
||||
let dist = DST_BASE[sym] + read_bits_l(b, p, bits)? as usize;
|
||||
p += usize::from(bits);
|
||||
|
||||
if dist > v.len() {
|
||||
bail!("bad distance");
|
||||
}
|
||||
|
||||
for _ in 0..leng {
|
||||
v.push(v[v.len() - dist]);
|
||||
}
|
||||
|
||||
output_tables(v, b, p, table_len, table_dst)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HuffmanTable
|
||||
{
|
||||
fn new(table: &[u16]) -> ResultS<Self>
|
||||
{
|
||||
let mut syms = vec![0; table.len()];
|
||||
let mut nums = [0; 16];
|
||||
|
||||
// count the number of symbols for each bit length
|
||||
for &length in table {
|
||||
nums[usize::from(length)] += 1;
|
||||
}
|
||||
|
||||
if usize::from(nums[0]) == table.len() {
|
||||
bail!("bad table lengths");
|
||||
}
|
||||
|
||||
// make offsets into the symbol table for each bit count
|
||||
let mut ofs = [0; 16];
|
||||
|
||||
for i in 1..=14 {
|
||||
ofs[i + 1] = ofs[i] + usize::from(nums[i]);
|
||||
}
|
||||
|
||||
// make the actual bit pattern table
|
||||
for (n, &length) in table.iter().enumerate() {
|
||||
// length 0 means this code isn't used, so only try to make bit
|
||||
// patterns for codes that actually exist
|
||||
if length != 0 {
|
||||
// make sure to make each offset unique
|
||||
let offset = &mut ofs[usize::from(length)];
|
||||
syms[*offset] = n as u16;
|
||||
*offset += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self{nums, syms})
|
||||
}
|
||||
|
||||
fn decode(&self, b: &[u8], mut p: usize) -> ResultS<(usize, u16)>
|
||||
{
|
||||
let mut code = 0_u16;
|
||||
let mut first = 0_u16;
|
||||
let mut index = 0_u16;
|
||||
|
||||
for i in 1..=15 {
|
||||
// add bit from file
|
||||
code |= read_bits_l(b, p, 1)? as u16;
|
||||
p += 1;
|
||||
|
||||
// check our symbol table for this one (quick tree check)
|
||||
let count = u16::from(self.nums[i]);
|
||||
|
||||
if i32::from(code) - i32::from(count) < i32::from(first) {
|
||||
return Ok((i, self.syms[usize::from(index + code - first)]));
|
||||
}
|
||||
|
||||
// continue on, trying to find the correct sequence
|
||||
index += count;
|
||||
first += count;
|
||||
|
||||
first <<= 1;
|
||||
code <<= 1;
|
||||
}
|
||||
|
||||
Err(err_msg("code not found in symbol tree"))
|
||||
}
|
||||
}
|
||||
|
||||
struct HuffmanTable
|
||||
{
|
||||
nums: [u8; 16],
|
||||
syms: Vec<u16>,
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
|
|
@ -55,7 +55,7 @@ pub fn read_minf(b: &[u8]) -> ResultS<Minf>
|
|||
skypict_id = u16[4];
|
||||
miss_flags = u16[6];
|
||||
envi_flags = u16[8];
|
||||
level_name = mac_roman_cstr[18..84];
|
||||
level_name = mac_roman_cstr[18..84] no_try;
|
||||
entr_flags = u32[84];
|
||||
}
|
||||
|
||||
|
@ -88,9 +88,7 @@ pub fn read_old_minf(b: &[u8]) -> ResultS<Minf>
|
|||
/// Reads an `iidx` chunk.
|
||||
pub fn read_iidx(b: &[u8]) -> ResultS<(u16, usize)>
|
||||
{
|
||||
if b.len() < 2 {
|
||||
bail!("not enough data");
|
||||
}
|
||||
check_data!(2, b);
|
||||
|
||||
Ok((u16b(b), 2))
|
||||
}
|
||||
|
@ -427,7 +425,7 @@ pub fn read_note(b: &[u8]) -> ResultS<(Note, usize)>
|
|||
72, BE in b =>
|
||||
pos = read_point[2..6];
|
||||
poly = u16[6];
|
||||
text = mac_roman_cstr[8..72];
|
||||
text = mac_roman_cstr[8..72] no_try;
|
||||
}
|
||||
|
||||
Ok((Note{pos, poly, text}, 72))
|
||||
|
@ -499,7 +497,7 @@ impl Default for Minf
|
|||
{
|
||||
fn default() -> Self
|
||||
{
|
||||
Minf{texture_id: 0,
|
||||
Self{texture_id: 0,
|
||||
physics_id: 1,
|
||||
skypict_id: 0,
|
||||
miss_flags: MsnFlags::empty(),
|
||||
|
|
|
@ -88,11 +88,12 @@ pub fn read_bitmap(b: &[u8]) -> ResultS<Bitmap>
|
|||
fst = u16[p] usize;
|
||||
lst = u16[p + 2] usize;
|
||||
}
|
||||
|
||||
let end = lst - fst;
|
||||
|
||||
p += 4;
|
||||
|
||||
if lst < fst || fst > pitch || lst > pitch || b.len() < p + end {
|
||||
if lst < fst || fst > pitch || lst > pitch {
|
||||
bail!("invalid compressed scanline");
|
||||
}
|
||||
|
||||
|
@ -110,10 +111,6 @@ pub fn read_bitmap(b: &[u8]) -> ResultS<Bitmap>
|
|||
}
|
||||
} else {
|
||||
// simple copy
|
||||
if b.len() < p + width * height {
|
||||
bail!("invalid scanline");
|
||||
}
|
||||
|
||||
bmp.cr.extend_from_slice(ok!(b.get(p..p + width * height),
|
||||
"not enough data")?);
|
||||
}
|
||||
|
@ -286,7 +283,7 @@ impl Color for ColorShp
|
|||
{
|
||||
match *self {
|
||||
ColorShp::Translucent => 0,
|
||||
ColorShp::Opaque{r, ..} => r,
|
||||
ColorShp::Opaque{r, ..} |
|
||||
ColorShp::Lit {r, ..} => r,
|
||||
}
|
||||
}
|
||||
|
@ -295,7 +292,7 @@ impl Color for ColorShp
|
|||
{
|
||||
match *self {
|
||||
ColorShp::Translucent => 0,
|
||||
ColorShp::Opaque{g, ..} => g,
|
||||
ColorShp::Opaque{g, ..} |
|
||||
ColorShp::Lit {g, ..} => g,
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +301,7 @@ impl Color for ColorShp
|
|||
{
|
||||
match *self {
|
||||
ColorShp::Translucent => 0,
|
||||
ColorShp::Opaque{b, ..} => b,
|
||||
ColorShp::Opaque{b, ..} |
|
||||
ColorShp::Lit {b, ..} => b,
|
||||
}
|
||||
}
|
||||
|
@ -313,7 +310,7 @@ impl Color for ColorShp
|
|||
{
|
||||
match *self {
|
||||
ColorShp::Translucent => 0,
|
||||
ColorShp::Opaque{..} => u16::max_value(),
|
||||
ColorShp::Opaque{..} |
|
||||
ColorShp::Lit {..} => u16::max_value(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ pub fn read_term(b: &[u8]) -> ResultS<(Terminal, usize)>
|
|||
let beg = grp.beg;
|
||||
let len = grp.len;
|
||||
let text = ok!(text.get(beg..beg + len), "bad offset")?;
|
||||
let text = mac_roman_cstr(text)?;
|
||||
let text = mac_roman_cstr(text);
|
||||
|
||||
groups.push(Group{flags, ttype, lines, text});
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ pub fn read_wad(b: &[u8]) -> ResultS<Wad>
|
|||
128, BE in b =>
|
||||
ver_wad = u16[0];
|
||||
ver_dat = u16[2];
|
||||
name = mac_roman_cstr[4..68];
|
||||
name = mac_roman_cstr[4..68] no_try;
|
||||
siz_app = u16[78] usize;
|
||||
siz_wcnk = u16[80] usize;
|
||||
siz_went = u16[82] usize;
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
Alice was beginning to get very tired of sitting by her sister on the bank, and
|
||||
of having nothing to do: once or twice she had peeped into the book her sister
|
||||
was reading, but it had no pictures or conversations in it, 'and what is the
|
||||
use of a book,' thought Alice 'without pictures or conversations?'
|
||||
|
||||
So she was considering in her own mind (as well as she could, for the hot day
|
||||
made her feel very sleepy and stupid), whether the pleasure of making a
|
||||
daisy-chain would be worth the trouble of getting up and picking the daisies,
|
||||
when suddenly a White Rabbit with pink eyes ran close by her.
|
||||
|
||||
There was nothing so VERY remarkable in that; nor did Alice think it so VERY
|
||||
much out of the way to hear the Rabbit say to itself, 'Oh dear! Oh dear! I
|
||||
shall be late!' (when she thought it over afterwards, it occurred to her that
|
||||
she ought to have wondered at this, but at the time it all seemed quite
|
||||
natural); but when the Rabbit actually TOOK A WATCH OUT OF ITS
|
||||
WAISTCOAT-POCKET, and looked at it, and then hurried on, Alice started to her
|
||||
feet, for it flashed across her mind that she had never before seen a rabbit
|
||||
with either a waistcoat-pocket, or a watch to take out of it, and burning with
|
||||
curiosity, she ran across the field after it, and fortunately was just in time
|
||||
to see it pop down a large rabbit-hole under the hedge.
|
||||
|
||||
In another moment down went Alice after it, never once considering how in the
|
||||
world she was to get out again.
|
||||
|
||||
The rabbit-hole went straight on like a tunnel for some way, and then dipped
|
||||
suddenly down, so suddenly that Alice had not a moment to think about stopping
|
||||
herself before she found herself falling down a very deep well.
|
||||
|
||||
Either the well was very deep, or she fell very slowly, for she had plenty of
|
||||
time as she went down to look about her and to wonder what was going to happen
|
||||
next. First, she tried to look down and make out what she was coming to, but it
|
||||
was too dark to see anything; then she looked at the sides of the well, and
|
||||
noticed that they were filled with cupboards and book-shelves; here and there
|
||||
she saw maps and pictures hung upon pegs. She took down a jar from one of the
|
||||
shelves as she passed; it was labelled 'ORANGE MARMALADE', but to her great
|
||||
disappointment it was empty: she did not like to drop the jar for fear of
|
||||
killing somebody, so managed to put it into one of the cupboards as she fell
|
||||
past it.
|
||||
|
||||
'Well!' thought Alice to herself, 'after such a fall as this, I shall think
|
||||
nothing of tumbling down stairs! How brave they'll all think me at home! Why, I
|
||||
wouldn't say anything about it, even if I fell off the top of the house!'
|
||||
(Which was very likely true.)
|
||||
|
||||
Down, down, down. Would the fall NEVER come to an end! 'I wonder how many miles
|
||||
I've fallen by this time?' she said aloud. 'I must be getting somewhere near
|
||||
the centre of the earth. Let me see: that would be four thousand miles down, I
|
||||
think--' (for, you see, Alice had learnt several things of this sort in her
|
||||
lessons in the schoolroom, and though this was not a VERY good opportunity for
|
||||
showing off her knowledge, as there was no one to listen to her, still it was
|
||||
good practice to say it over) '--yes, that's about the right distance--but then
|
||||
I wonder what Latitude or Longitude I've got to?' (Alice had no idea what
|
||||
Latitude was, or Longitude either, but thought they were nice grand words to
|
||||
say.)
|
||||
|
||||
Presently she began again. 'I wonder if I shall fall right THROUGH the earth!
|
||||
How funny it'll seem to come out among the people that walk with their heads
|
||||
downward! The Antipathies, I think--' (she was rather glad there WAS no one
|
||||
listening, this time, as it didn't sound at all the right word) '--but I shall
|
||||
have to ask them what the name of the country is, you know. Please, Ma'am, is
|
||||
this New Zealand or Australia?' (and she tried to curtsey as she spoke--fancy
|
||||
CURTSEYING as you're falling through the air! Do you think you could manage
|
||||
it?) 'And what an ignorant little girl she'll think me for asking! No, it'll
|
||||
never do to ask: perhaps I shall see it written up somewhere.'
|
||||
|
||||
Down, down, down. There was nothing else to do, so Alice soon began talking
|
||||
again. 'Dinah'll miss me very much to-night, I should think!' (Dinah was the
|
||||
cat.) 'I hope they'll remember her saucer of milk at tea-time. Dinah my dear! I
|
||||
wish you were down here with me! There are no mice in the air, I'm afraid, but
|
||||
you might catch a bat, and that's very like a mouse, you know. But do cats eat
|
||||
bats, I wonder?' And here Alice began to get rather sleepy, and went on saying
|
||||
to herself, in a dreamy sort of way, 'Do cats eat bats? Do cats eat bats?' and
|
||||
sometimes, 'Do bats eat cats?' for, you see, as she couldn't answer either
|
||||
question, it didn't much matter which way she put it. She felt that she was
|
||||
dozing off, and had just begun to dream that she was walking hand in hand with
|
||||
Dinah, and saying to her very earnestly, 'Now, Dinah, tell me the truth: did
|
||||
you ever eat a bat?' when suddenly, thump! thump! down she came upon a heap of
|
||||
sticks and dry leaves, and the fall was over.
|
||||
|
||||
Alice was not a bit hurt, and she jumped up on to her feet in a moment: she
|
||||
looked up, but it was all dark overhead; before her was another long passage,
|
||||
and the White Rabbit was still in sight, hurrying down it. There was not a
|
||||
moment to be lost: away went Alice like the wind, and was just in time to hear
|
||||
it say, as it turned a corner, 'Oh my ears and whiskers, how late it's
|
||||
getting!' She was close behind it when she turned the corner, but the Rabbit
|
||||
was no longer to be seen: she found herself in a long, low hall, which was lit
|
||||
up by a row of lamps hanging from the roof.
|
||||
|
||||
There were doors all round the hall, but they were all locked; and when Alice
|
||||
had been all the way down one side and up the other, trying every door, she
|
||||
walked sadly down the middle, wondering how she was ever to get out again.
|
||||
|
||||
Suddenly she came upon a little three-legged table, all made of solid glass;
|
||||
there was nothing on it except a tiny golden key, and Alice's first thought was
|
||||
that it might belong to one of the doors of the hall; but, alas! either the
|
||||
locks were too large, or the key was too small, but at any rate it would not
|
||||
open any of them. However, on the second time round, she came upon a low
|
||||
curtain she had not noticed before, and behind it was a little door about
|
||||
fifteen inches high: she tried the little golden key in the lock, and to her
|
||||
great delight it fitted!
|
||||
|
||||
Alice opened the door and found that it led into a small passage, not much
|
||||
larger than a rat-hole: she knelt down and looked along the passage into the
|
||||
loveliest garden you ever saw. How she longed to get out of that dark hall, and
|
||||
wander about among those beds of bright flowers and those cool fountains, but
|
||||
she could not even get her head through the doorway; 'and even if my head would
|
||||
go through,' thought poor Alice, 'it would be of very little use without my
|
||||
shoulders. Oh, how I wish I could shut up like a telescope! I think I could, if
|
||||
I only knew how to begin.' For, you see, so many out-of-the-way things had
|
||||
happened lately, that Alice had begun to think that very few things indeed were
|
||||
really impossible.
|
||||
|
||||
There seemed to be no use in waiting by the little door, so she went back to
|
||||
the table, half hoping she might find another key on it, or at any rate a book
|
||||
of rules for shutting people up like telescopes: this time she found a little
|
||||
bottle on it, ('which certainly was not here before,' said Alice,) and round
|
||||
the neck of the bottle was a paper label, with the words 'DRINK ME' beautifully
|
||||
printed on it in large letters.
|
||||
|
||||
It was all very well to say 'Drink me,' but the wise little Alice was not going
|
||||
to do THAT in a hurry. 'No, I'll look first,' she said, 'and see whether it's
|
||||
marked "poison" or not'; for she had read several nice little histories about
|
||||
children who had got burnt, and eaten up by wild beasts and other unpleasant
|
||||
things, all because they WOULD not remember the simple rules their friends had
|
||||
taught them: such as, that a red-hot poker will burn you if you hold it too
|
||||
long; and that if you cut your finger VERY deeply with a knife, it usually
|
||||
bleeds; and she had never forgotten that, if you drink much from a bottle
|
||||
marked 'poison,' it is almost certain to disagree with you, sooner or later.
|
||||
|
||||
However, this bottle was NOT marked 'poison,' so Alice ventured to taste it,
|
||||
and finding it very nice, (it had, in fact, a sort of mixed flavour of
|
||||
cherry-tart, custard, pine-apple, roast turkey, toffee, and hot buttered
|
||||
toast,) she very soon finished it off.
|
||||
|
||||
* * * * * * *
|
||||
|
||||
* * * * * *
|
||||
|
||||
* * * * * * *
|
||||
|
||||
'What a curious feeling!' said Alice; 'I must be shutting up like a telescope.'
|
||||
|
||||
And so it was indeed: she was now only ten inches high, and her face brightened
|
||||
up at the thought that she was now the right size for going through the little
|
||||
door into that lovely garden. First, however, she waited for a few minutes to
|
||||
see if she was going to shrink any further: she felt a little nervous about
|
||||
this; 'for it might end, you know,' said Alice to herself, 'in my going out
|
||||
altogether, like a candle. I wonder what I should be like then?' And she tried
|
||||
to fancy what the flame of a candle is like after the candle is blown out, for
|
||||
she could not remember ever having seen such a thing.
|
||||
|
||||
After a while, finding that nothing more happened, she decided on going into
|
||||
the garden at once; but, alas for poor Alice! when she got to the door, she
|
||||
found she had forgotten the little golden key, and when she went back to the
|
||||
table for it, she found she could not possibly reach it: she could see it quite
|
||||
plainly through the glass, and she tried her best to climb up one of the legs
|
||||
of the table, but it was too slippery; and when she had tired herself out with
|
||||
trying, the poor little thing sat down and cried.
|
||||
|
||||
'Come, there's no use in crying like that!' said Alice to herself, rather
|
||||
sharply; 'I advise you to leave off this minute!' She generally gave herself
|
||||
very good advice, (though she very seldom followed it), and sometimes she
|
||||
scolded herself so severely as to bring tears into her eyes; and once she
|
||||
remembered trying to box her own ears for having cheated herself in a game of
|
||||
croquet she was playing against herself, for this curious child was very fond
|
||||
of pretending to be two people. 'But it's no use now,' thought poor Alice, 'to
|
||||
pretend to be two people! Why, there's hardly enough of me left to make ONE
|
||||
respectable person!'
|
||||
|
||||
Soon her eye fell on a little glass box that was lying under the table: she
|
||||
opened it, and found in it a very small cake, on which the words 'EAT ME' were
|
||||
beautifully marked in currants. 'Well, I'll eat it,' said Alice, 'and if it
|
||||
makes me grow larger, I can reach the key; and if it makes me grow smaller, I
|
||||
can creep under the door; so either way I'll get into the garden, and I don't
|
||||
care which happens!'
|
||||
|
||||
She ate a little bit, and said anxiously to herself, 'Which way? Which way?',
|
||||
holding her hand on the top of her head to feel which way it was growing, and
|
||||
she was quite surprised to find that she remained the same size: to be sure,
|
||||
this generally happens when one eats cake, but Alice had got so much into the
|
||||
way of expecting nothing but out-of-the-way things to happen, that it seemed
|
||||
quite dull and stupid for life to go on in the common way.
|
||||
|
||||
So she set to work, and very soon finished off the cake.
|
||||
|
||||
* * * * * * *
|
||||
|
||||
* * * * * *
|
||||
|
||||
* * * * * * *
|
Binary file not shown.
Binary file not shown.
|
@ -1,13 +1,33 @@
|
|||
use maraiah::marathon::defl::{self, load_gzip_header};
|
||||
use maraiah::marathon::defl;
|
||||
|
||||
include!("data/rand.rs");
|
||||
|
||||
#[test]
|
||||
fn defl_alice()
|
||||
{
|
||||
const IN_1: &[u8] = include_bytes!("data/alice1.in");
|
||||
const IN_2: &[u8] = include_bytes!("data/alice2.in");
|
||||
const OUT: &[u8] = include_bytes!("data/alice.out");
|
||||
|
||||
let p = defl::load_gzip_header(IN_1).unwrap();
|
||||
assert_eq!(p, 0x14);
|
||||
|
||||
let b = &IN_1[p..];
|
||||
assert_eq!(defl::load_deflate(b).unwrap().1, OUT.to_vec());
|
||||
|
||||
let p = defl::load_gzip_header(IN_2).unwrap();
|
||||
assert_eq!(p, 0x14);
|
||||
|
||||
let b = &IN_2[p..];
|
||||
assert_eq!(defl::load_deflate(b).unwrap().1, OUT.to_vec());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn defl_must_succeed()
|
||||
{
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipok1.bin")).is_ok());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipok2.bin")).is_ok());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipok3.bin")).is_ok());
|
||||
assert!(defl::load_gzip_header(include_bytes!("data/gzipok1.bin")).is_ok());
|
||||
assert!(defl::load_gzip_header(include_bytes!("data/gzipok2.bin")).is_ok());
|
||||
assert!(defl::load_gzip_header(include_bytes!("data/gzipok3.bin")).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -17,13 +37,13 @@ fn defl_must_not_succeed()
|
|||
assert!(defl::load_gzip_header(inp).is_err());
|
||||
}
|
||||
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipbad1.bin")).is_err());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipbad2.bin")).is_err());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipbad3.bin")).is_err());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipbad4.bin")).is_err());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipbad5.bin")).is_err());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipbad6.bin")).is_err());
|
||||
assert!(load_gzip_header(include_bytes!("data/gzipbad7.bin")).is_err());
|
||||
assert!(defl::load_gzip_header(include_bytes!("data/gzbad1.bin")).is_err());
|
||||
assert!(defl::load_gzip_header(include_bytes!("data/gzbad2.bin")).is_err());
|
||||
assert!(defl::load_gzip_header(include_bytes!("data/gzbad3.bin")).is_err());
|
||||
assert!(defl::load_gzip_header(include_bytes!("data/gzbad4.bin")).is_err());
|
||||
assert!(defl::load_gzip_header(include_bytes!("data/gzbad5.bin")).is_err());
|
||||
assert!(defl::load_gzip_header(include_bytes!("data/gzbad6.bin")).is_err());
|
||||
assert!(defl::load_gzip_header(include_bytes!("data/gzbad7.bin")).is_err());
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
|
Loading…
Reference in New Issue