pubstruct BinaryWriter<W: Write> {
writer: PosWriter<W>,
events: Vec<Event>,
dictionary_key_events: Vec<usize>,
values: IndexMap<Value<'static>, ValueState>, /// Pointers into `events` for each of the currently unclosed `Collection` events.
collection_stack: Vec<usize>, /// The number of `Collection` and unique `Value` events in `events`.
num_objects: usize,
}
/// An array of `len` elements is stored as a `Collection` event followed by `skip_len` events /// containing the contents of the array. e.g. /// /// Collection(ty: Array, len: 2, skip_len: 2) /// Value /// Value /// /// If the array contains another array or dictionary `len` and `skip_len` will differ. e.g. /// /// Collection(ty: Array, len: 2, skip_len: 3) /// Value /// Collection(ty: Array, len: 1, skip_len: 1) /// Value /// /// A dictionary of `len` (key, value) pairs is stored as a `Collection` event followed by /// `skip_len` events containing the contents of the dictionary. The dictionary values are stored /// first. These are followed by a `DictionaryKeys` event and then the keys themselves. e.g. /// /// Collection(ty: Dictionary, len: 2, skip_len: 6) /// Value /// Collection(ty: Array, len: 1, skip_len: 1) /// Value /// DictionaryKeys(2) /// Value (Key) /// Value (Key) /// /// This arrangement simplifies writing dictionaries as they must be written in the order /// (key, key, value, value) instead of (key, value, key, value) as they are passed to the writer. /// Unclosed dictionaries have their keys stored in `dictionary_key_events` and these are only /// moved to the end of the `BinaryWriter::events` array once the dictionary is closed in /// `write_end_collection`. enum Event {
Collection(Collection), /// Index of the value in the `values` map.
Value(usize), /// The number of dictionary keys following this event.
DictionaryKeys(usize),
}
struct Collection {
ty: CollectionType, /// The number of elements in an array or (key, value) pairs in a dictionary. /// Unclosed dictionaries have a `len` equal to the number of keys plus the number of values /// written so far. This is fixed up in `write_end_collection`.
len: usize, /// The number of events to skip to get to the next element after the collection.
skip: usize,
object_ref: Option<ObjectRef>,
}
#[derive(Eq, Hash, PartialEq)] enum Value<'a> {
Boolean(bool),
Data(Cow<'a, [u8]>),
Date(Date),
Integer(Integer), /// Floats are deduplicated based on their bitwise value.
Real(u64),
String(Cow<'a, str>),
Uid(Uid),
}
enum ValueState { /// The value has not been assigned an object reference.
Unassigned, /// The value has been assigned an object reference but has not yet been written.
Unwritten(ObjectRef), /// The value has been written with the given object reference.
Written(ObjectRef),
}
let current_event_index = self.events.len() - 1; let c = iflet Event::Collection(c) = &mutself.events[collection_event_index] {
c
} else {
unreachable!("items in `collection_stack` always point to a collection event");
};
iflet CollectionType::Dictionary = c.ty { // Ensure that every dictionary key is paired with a value. if !is_even(c.len) { return Err(ErrorKind::UnexpectedEventType {
expected: EventKind::DictionaryKeyOrEndCollection,
found: EventKind::EndCollection,
}
.without_position());
}
// Fix up the dictionary length. It should contain the number of key-value pairs, // not the number of keys and values.
c.len /= 2;
// To skip past a dictionary we also need to skip the `DictionaryKeys` event and the // keys that follow it.
c.skip += 1 + c.len; let len = c.len; self.events.push(Event::DictionaryKeys(len));
// Move the cached dictionary keys to the end of the events array. let keys_start_index = self.dictionary_key_events.len() - len; self.events.extend( self.dictionary_key_events
.drain(keys_start_index..)
.map(Event::Value),
);
}
// Ensure that all dictionary keys are strings. match (&value, expecting_dictionary_key) {
(Value::String(_), true) | (_, false) => (),
(_, true) => { return Err(ErrorKind::UnexpectedEventType {
expected: EventKind::DictionaryKeyOrEndCollection,
found: value.event_kind(),
}
.without_position())
}
}
// Deduplicate `value`. There is one entry in `values` for each unqiue `Value` in the // plist. let value_index = iflet Some((value_index, _, _)) = self.values.get_full(&value) {
value_index
} else { self.num_objects += 1; let value = value.into_owned(); let (value_index, _) = self.values.insert_full(value, ValueState::Unassigned);
value_index
};
// Dictionary keys are buffered in `dictionary_key_events` until the dictionary is closed // in `write_end_collection` when they are moved to the end of the `events` array. if expecting_dictionary_key { self.dictionary_key_events.push(value_index);
} else { self.events.push(Event::Value(value_index));
}
fn write_plist_collection(
&mutself,
collection: &Collection,
events: &mut [Event],
ref_size: u8,
next_object_ref: &mut ObjectRef,
offset_table: &mut Vec<usize>,
) -> Result<(), Error> { iflet Some(object_ref) = &collection.object_ref {
offset_table[object_ref.value()] = self.writer.pos;
} else {
unreachable!("collection object refs are assigned before this function is called");
}
// Split the events in the current collection into keys and values (arrays contain only // values). This is required as dictionary keys appear after values in the `events array // but all keys must be written before any values. let (keys, values, ty) = match collection.ty {
CollectionType::Array => (&mut [][..], events, 0xa0),
CollectionType::Dictionary => { let keys_start_offset = events.len() - collection.len - 1; let (values, keys) = events.split_at_mut(keys_start_offset);
(&mut keys[1..], values, 0xd0)
}
}; letmut collection_events = keys.iter_mut().chain(values);
// Collections are written as a length prefixed array of object references. For an array // the length is the number of elements. For a dictionary it is the number of (key, value) // pairs.
write_plist_value_ty_and_size(&mutself.writer, ty, collection.len)?; whilelet Some(event) = collection_events.next() { let object_ref = match event {
Event::Collection(c) => { // We only want to write references to top level elements in the collection so // we skip over the contents of any sub-collections. if c.skip > 0 { let _ = collection_events.nth(c.skip - 1);
}
// Collections are not deduplicated so they must be assigned an object // reference here.
assert!(c.object_ref.is_none()); let object_ref = next_object_ref.clone_and_increment_self();
c.object_ref = Some(object_ref.clone());
object_ref
}
Event::Value(value_index) => { // Values are deduplicated so we only assign an object reference if we have not // already done so previously. let (_, value_state) = value_mut(&mutself.values, *value_index); match value_state {
ValueState::Unassigned => { let object_ref = next_object_ref.clone_and_increment_self();
*value_state = ValueState::Unwritten(object_ref.clone());
object_ref
}
ValueState::Unwritten(object_ref) | ValueState::Written(object_ref) => {
object_ref.clone()
}
}
}
Event::DictionaryKeys(_) => unreachable!( "`DictionaryKeys` events are specifically excluded from the iterator"
),
};
write_plist_ref(&mutself.writer, ref_size, object_ref.value())?;
}
// We write dictionary keys here as they appear after values in the `events` array but // should come before values in the plist stream to reduce seeking on read. for key in keys { iflet Event::Value(value_index) = key { self.write_plist_value(*value_index, offset_table)?;
} else {
unreachable!("dictionary keys are assigned as values in `write_end_collection`");
}
}
let object_ref = match value_state {
ValueState::Unassigned => {
unreachable!("value object refs are assigned before this function is called");
}
ValueState::Unwritten(object_ref) => object_ref.clone(),
ValueState::Written(_) => return Ok(()),
};
fn plist_ref_size(max_value: usize) -> u8 { let significant_bits = 64 - (max_value as u64).leading_zeros() as u8; // Convert to number of bytes let significant_bytes = (significant_bits + 7) / 8; // Round up to the next integer byte size which must be power of two.
significant_bytes.next_power_of_two()
}
fn write_plist_ref(
writer: &mut PosWriter<impl Write>,
ref_size: u8,
value: usize,
) -> Result<(), Error> { match ref_size { 1 => writer.write_exact(&[value as u8]), 2 => writer.write_exact(&(value as u16).to_be_bytes()), 4 => writer.write_exact(&(value as u32).to_be_bytes()), 8 => writer.write_exact(&(value as u64).to_be_bytes()),
_ => unreachable!("`ref_size` is a power of two less than or equal to 8"),
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.