diff options
Diffstat (limited to 'third_party/rust/winreg/src')
-rw-r--r-- | third_party/rust/winreg/src/decoder/mod.rs | 111 | ||||
-rw-r--r-- | third_party/rust/winreg/src/decoder/serialization_serde.rs | 221 | ||||
-rw-r--r-- | third_party/rust/winreg/src/encoder/mod.rs | 105 | ||||
-rw-r--r-- | third_party/rust/winreg/src/encoder/serialization_serde.rs | 312 | ||||
-rw-r--r-- | third_party/rust/winreg/src/enums.rs | 58 | ||||
-rw-r--r-- | third_party/rust/winreg/src/lib.rs | 1170 | ||||
-rw-r--r-- | third_party/rust/winreg/src/transaction.rs | 105 | ||||
-rw-r--r-- | third_party/rust/winreg/src/types.rs | 141 |
8 files changed, 2223 insertions, 0 deletions
diff --git a/third_party/rust/winreg/src/decoder/mod.rs b/third_party/rust/winreg/src/decoder/mod.rs new file mode 100644 index 0000000000..e832050a7e --- /dev/null +++ b/third_party/rust/winreg/src/decoder/mod.rs @@ -0,0 +1,111 @@ +// Copyright 2017, Igor Shaula +// Licensed under the MIT License <LICENSE or +// http://opensource.org/licenses/MIT>. This file +// may not be copied, modified, or distributed +// except according to those terms. +use std::io; +use std::fmt; +use std::error::Error; +use winapi::shared::minwindef::DWORD; +use super::{RegKey}; +use super::enums::*; + +macro_rules! read_value{ + ($s:ident) => ( + match mem::replace(&mut $s.f_name, None) { + Some(ref s) => { + $s.key.get_value(s) + .map_err(DecoderError::IoError) + }, + None => Err(DecoderError::NoFieldName) + } + ) +} + +macro_rules! parse_string{ + ($s:ident) => ({ + let s: String = read_value!($s)?; + s.parse().map_err(|e| DecoderError::ParseError(format!("{:?}", e))) + }) +} + +macro_rules! no_impl { + ($e:expr) => ( + Err(DecoderError::DecodeNotImplemented($e.to_owned())) + ) +} + +#[cfg(feature = "serialization-serde")] mod serialization_serde; + +#[derive(Debug)] +pub enum DecoderError{ + DecodeNotImplemented(String), + DeserializerError(String), + IoError(io::Error), + ParseError(String), + NoFieldName, +} + +impl fmt::Display for DecoderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +impl Error for DecoderError { + fn description(&self) -> &str { + use self::DecoderError::*; + match *self { + DecodeNotImplemented(ref s) | DeserializerError(ref s) | ParseError(ref s) => s, + IoError(ref e) => e.description(), + NoFieldName => "No field name" + } + } +} + +impl From<io::Error> for DecoderError { + fn from(err: io::Error) -> DecoderError { + DecoderError::IoError(err) + } +} + +pub type DecodeResult<T> = Result<T, DecoderError>; + +#[derive(Debug)] +enum DecoderReadingState { + WaitingForKey, + WaitingForValue, +} + +#[derive(Debug)] +enum DecoderEnumerationState { + EnumeratingKeys(DWORD), + EnumeratingValues(DWORD), +} + +#[derive(Debug)] +pub struct Decoder { + key: RegKey, + f_name: Option<String>, + reading_state: DecoderReadingState, + enumeration_state: DecoderEnumerationState, +} + +const DECODER_SAM: DWORD = KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS; + +impl Decoder { + pub fn from_key(key: &RegKey) -> DecodeResult<Decoder> { + key.open_subkey_with_flags("", DECODER_SAM) + .map(Decoder::new) + .map_err(DecoderError::IoError) + } + + fn new(key: RegKey) -> Decoder { + Decoder{ + key: key, + f_name: None, + reading_state: DecoderReadingState::WaitingForKey, + enumeration_state: DecoderEnumerationState::EnumeratingKeys(0) + } + } +} diff --git a/third_party/rust/winreg/src/decoder/serialization_serde.rs b/third_party/rust/winreg/src/decoder/serialization_serde.rs new file mode 100644 index 0000000000..0c8aec5984 --- /dev/null +++ b/third_party/rust/winreg/src/decoder/serialization_serde.rs @@ -0,0 +1,221 @@ +// Copyright 2017, Igor Shaula +// Licensed under the MIT License <LICENSE or +// http://opensource.org/licenses/MIT>. This file +// may not be copied, modified, or distributed +// except according to those terms. +use std::mem; +use std::fmt; +use serde::de::*; +use super::{DecoderError, DecodeResult, DecoderReadingState, DecoderEnumerationState, Decoder, DECODER_SAM}; +use super::super::FromRegValue; + +impl Error for DecoderError { + fn custom<T: fmt::Display>(msg: T) -> Self { + DecoderError::DeserializerError(format!("{}", msg)) + } +} + +impl<'de, 'a> Deserializer<'de> for &'a mut Decoder { + type Error = DecoderError; + fn deserialize_any<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + use self::DecoderEnumerationState::*; + match self.enumeration_state { + EnumeratingKeys(..) => no_impl!("deserialize_any for keys"), + EnumeratingValues(..) => { + let s = self.f_name.as_ref().ok_or(DecoderError::NoFieldName)?; + let v = self.key.get_raw_value(s)?; + use RegType::*; + match v.vtype { + REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => visitor.visit_string(String::from_reg_value(&v)?), + REG_DWORD => visitor.visit_u32(u32::from_reg_value(&v)?), + REG_QWORD => visitor.visit_u64(u64::from_reg_value(&v)?), + _ => Err(DecoderError::DecodeNotImplemented("value type deserialization not implemented".to_owned())) + } + } + } + } + + fn deserialize_bool<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + visitor.visit_bool(read_value!(self).map(|v: u32| v > 0)?) + } + + fn deserialize_u8<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + self.deserialize_u32(visitor) + } + + fn deserialize_u16<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + self.deserialize_u32(visitor) + } + + fn deserialize_u32<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + visitor.visit_u32(read_value!(self)?) + } + + fn deserialize_u64<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + visitor.visit_u64(read_value!(self)?) + } + + fn deserialize_i8<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + visitor.visit_i8(parse_string!(self)?) + } + + fn deserialize_i16<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + visitor.visit_i16(parse_string!(self)?) + } + + fn deserialize_i32<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + visitor.visit_i32(parse_string!(self)?) + } + + fn deserialize_i64<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + visitor.visit_i64(parse_string!(self)?) + } + + fn deserialize_f32<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + visitor.visit_f32(parse_string!(self)?) + } + + fn deserialize_f64<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + visitor.visit_f64(parse_string!(self)?) + } + + fn deserialize_char<V>(self, _visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + no_impl!("deserialize_char") + } + + fn deserialize_str<V>(self, _visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + no_impl!("deserialize_str") + } + + fn deserialize_string<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + use self::DecoderReadingState::*; + match self.reading_state { + WaitingForKey => { + let s = self.f_name.as_ref().ok_or(DecoderError::NoFieldName)?; + visitor.visit_string(s.clone()) + } + WaitingForValue => visitor.visit_string(read_value!(self)?) + } + } + + fn deserialize_bytes<V>(self, _visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + no_impl!("deserialize_bytes") + } + + fn deserialize_byte_buf<V>(self, _visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + no_impl!("deserialize_byte_buf") + } + + fn deserialize_option<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + let v = { + let s = self.f_name.as_ref().ok_or(DecoderError::NoFieldName)?; + self.key.get_raw_value(s) + }; + match v { + Ok(..) => visitor.visit_some(&mut *self), + Err(..) => visitor.visit_none() + } + } + + fn deserialize_unit<V>(self, _visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + no_impl!("deserialize_unit") + } + + fn deserialize_unit_struct<V>(self, _name: &'static str, _visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + no_impl!("deserialize_unit_struct") + } + + fn deserialize_newtype_struct<V>(self, _name: &'static str, _visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + no_impl!("deserialize_newtype_struct") + } + + fn deserialize_seq<V>(self, _visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + no_impl!("deserialize_seq") + } + + fn deserialize_tuple<V>(self, _len: usize, _visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + no_impl!("deserialize_tuple") + } + + fn deserialize_tuple_struct<V>(self, _name: &'static str, _len: usize, _visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + no_impl!("deserialize_tuple_struct") + } + + fn deserialize_map<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + visitor.visit_map(self) + } + + fn deserialize_struct<V>(self, _name: &'static str, _fields: &'static [&'static str], visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + visitor.visit_map(self) + } + + fn deserialize_identifier<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + self.deserialize_string(visitor) + } + + fn deserialize_enum<V>(self, _name: &'static str, _variants: &'static [&'static str], _visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + no_impl!("deserialize_enum") + } + + fn deserialize_ignored_any<V>(self, visitor: V) -> DecodeResult<V::Value> where V: Visitor<'de> { + self.deserialize_any(visitor) + } +} + +impl<'de, 'a> MapAccess<'de> for Decoder { + type Error = DecoderError; + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error> + where K: DeserializeSeed<'de> + { + self.reading_state = DecoderReadingState::WaitingForKey; + use self::DecoderEnumerationState::*; + match self.enumeration_state { + EnumeratingKeys(index) => { + match self.key.enum_key(index) { + Some(res) => { + self.f_name = Some(res?); + self.enumeration_state = EnumeratingKeys(index + 1); + seed.deserialize(&mut *self).map(Some) + } + None => { + self.enumeration_state = EnumeratingValues(0); + self.next_key_seed(seed) + } + } + } + EnumeratingValues(index) => { + let next_value = self.key.enum_value(index); + match next_value { + Some(res) => { + self.f_name = Some(res?.0); + self.enumeration_state = EnumeratingValues(index + 1); + seed.deserialize(&mut *self).map(Some) + } + None => Ok(None), + } + } + } + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error> + where V: DeserializeSeed<'de> + { + self.reading_state = DecoderReadingState::WaitingForValue; + use self::DecoderEnumerationState::*; + match self.enumeration_state { + EnumeratingKeys(..) => { + let f_name = self.f_name.as_ref().ok_or(DecoderError::NoFieldName)?; + match self.key.open_subkey_with_flags(f_name, DECODER_SAM) { + Ok(subkey) => { + let mut nested = Decoder::new(subkey); + seed.deserialize(&mut nested) + } + Err(err) => Err(DecoderError::IoError(err)), + } + }, + EnumeratingValues(..) => { + seed.deserialize(&mut *self) + } + } + } +} diff --git a/third_party/rust/winreg/src/encoder/mod.rs b/third_party/rust/winreg/src/encoder/mod.rs new file mode 100644 index 0000000000..dcb178397b --- /dev/null +++ b/third_party/rust/winreg/src/encoder/mod.rs @@ -0,0 +1,105 @@ +// Copyright 2017, Igor Shaula +// Licensed under the MIT License <LICENSE or +// http://opensource.org/licenses/MIT>. This file +// may not be copied, modified, or distributed +// except according to those terms. +use std::io; +use std::fmt; +use std::error::Error; +use winapi::shared::minwindef::DWORD; +use super::RegKey; +use super::enums::*; +use super::transaction::Transaction; +use self::EncoderState::*; + +macro_rules! emit_value{ + ($s:ident, $v:ident) => ( + match mem::replace(&mut $s.state, Start) { + NextKey(ref s) => { + $s.keys[$s.keys.len()-1].set_value(s, &$v) + .map_err(EncoderError::IoError) + }, + Start => Err(EncoderError::NoFieldName) + } + ) +} + +macro_rules! no_impl { + ($e:expr) => ( + Err(EncoderError::EncodeNotImplemented($e.to_owned())) + ) +} + +#[cfg(feature = "serialization-serde")] mod serialization_serde; + +#[derive(Debug)] +pub enum EncoderError{ + EncodeNotImplemented(String), + SerializerError(String), + IoError(io::Error), + NoFieldName, +} + +impl fmt::Display for EncoderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +impl Error for EncoderError { + fn description(&self) -> &str { + use self::EncoderError::*; + match *self { + EncodeNotImplemented(ref s) | SerializerError(ref s) => s, + IoError(ref e) => e.description(), + NoFieldName => "No field name" + } + } +} + +pub type EncodeResult<T> = Result<T, EncoderError>; + +impl From<io::Error> for EncoderError { + fn from(err: io::Error) -> EncoderError { + EncoderError::IoError(err) + } +} + +#[derive(Debug)] +enum EncoderState { + Start, + NextKey(String), + // NextMapKey, +} + +#[derive(Debug)] +pub struct Encoder { + keys: Vec<RegKey>, + tr: Transaction, + state: EncoderState, +} + +const ENCODER_SAM: DWORD = KEY_CREATE_SUB_KEY|KEY_SET_VALUE; + +impl Encoder { + pub fn from_key(key: &RegKey) -> EncodeResult<Encoder> { + let tr = try!(Transaction::new()); + key.open_subkey_transacted_with_flags("", &tr, ENCODER_SAM) + .map(|k| Encoder::new(k, tr)) + .map_err(EncoderError::IoError) + } + + fn new(key: RegKey, tr: Transaction) -> Encoder { + let mut keys = Vec::with_capacity(5); + keys.push(key); + Encoder{ + keys: keys, + tr: tr, + state: Start, + } + } + + pub fn commit(&mut self) -> EncodeResult<()> { + self.tr.commit().map_err(EncoderError::IoError) + } +} diff --git a/third_party/rust/winreg/src/encoder/serialization_serde.rs b/third_party/rust/winreg/src/encoder/serialization_serde.rs new file mode 100644 index 0000000000..d46ba31836 --- /dev/null +++ b/third_party/rust/winreg/src/encoder/serialization_serde.rs @@ -0,0 +1,312 @@ +// Copyright 2017, Igor Shaula +// Licensed under the MIT License <LICENSE or +// http://opensource.org/licenses/MIT>. This file +// may not be copied, modified, or distributed +// except according to those terms. +use std::fmt; +use std::mem; +use super::{Encoder, EncoderError, EncodeResult, ENCODER_SAM}; +use super::EncoderState::*; +use serde::ser::*; + +impl Error for EncoderError { + fn custom<T: fmt::Display>(msg: T) -> Self { + EncoderError::SerializerError(format!("{}", msg)) + } +} + + +impl<'a> Serializer for &'a mut Encoder { + type Ok = (); + type Error = EncoderError; + + type SerializeSeq = SeqEncoder; + type SerializeTuple = TupleEncoder; + type SerializeTupleStruct = TupleStructEncoder; + type SerializeTupleVariant = TupleVariantEncoder; + type SerializeMap = MapEncoder<'a>; + type SerializeStruct = StructEncoder<'a>; + type SerializeStructVariant = StructVariantEncoder; + + fn serialize_bool(self, value: bool) -> EncodeResult<Self::Ok> { + self.serialize_u32(value as u32) + } + + fn serialize_i8(self, value: i8) -> EncodeResult<Self::Ok> { + self.serialize_i64(value as i64) + } + + fn serialize_i16(self, value: i16) -> EncodeResult<Self::Ok> { + self.serialize_i64(value as i64) + } + + fn serialize_i32(self, value: i32) -> EncodeResult<Self::Ok> { + self.serialize_i64(value as i64) + } + + fn serialize_i64(self, value: i64) -> EncodeResult<Self::Ok> { + let s = value.to_string(); + emit_value!(self, s) + } + + fn serialize_u8(self, value: u8) -> EncodeResult<Self::Ok> { + self.serialize_u32(value as u32) + } + + fn serialize_u16(self, value: u16) -> EncodeResult<Self::Ok> { + self.serialize_u32(value as u32) + } + + fn serialize_u32(self, value: u32) -> EncodeResult<Self::Ok> { + emit_value!(self, value) + } + + fn serialize_u64(self, value: u64) -> EncodeResult<Self::Ok> { + emit_value!(self, value) + } + + fn serialize_f32(self, value: f32) -> EncodeResult<Self::Ok> { + let s = value.to_string(); + emit_value!(self, s) + } + + fn serialize_f64(self, value: f64) -> EncodeResult<Self::Ok> { + let s = value.to_string(); + emit_value!(self, s) + } + + fn serialize_char(self, _value: char) -> EncodeResult<Self::Ok> { + no_impl!("serialize_char") + } + + fn serialize_str(self, value: &str) -> EncodeResult<Self::Ok> { + emit_value!(self, value) + } + + fn serialize_bytes(self, _value: &[u8]) -> EncodeResult<Self::Ok> { + no_impl!("serialize_bytes") + } + + fn serialize_none(self) -> EncodeResult<Self::Ok> { + no_impl!("serialize_none") + } + + fn serialize_some<T: ?Sized + Serialize>(self, _value: &T) -> EncodeResult<Self::Ok> { + no_impl!("serialize_some") + } + + fn serialize_unit(self) -> EncodeResult<Self::Ok> { + no_impl!("serialize_unit") + } + + fn serialize_unit_struct(self, _name: &'static str) -> EncodeResult<Self::Ok> { + no_impl!("serialize_unit_struct") + } + + fn serialize_unit_variant(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str) + -> EncodeResult<Self::Ok> { + no_impl!("serialize_unit_variant") + } + + fn serialize_newtype_struct<T: ?Sized + Serialize>(self, + _name: &'static str, + _value: &T) + -> EncodeResult<Self::Ok> { + no_impl!("serialize_newtype_struct") + } + + fn serialize_newtype_variant<T: ?Sized + Serialize>(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T) + -> EncodeResult<Self::Ok> { + no_impl!("serialize_newtype_variant") + } + + fn serialize_seq(self, _len: Option<usize>) -> EncodeResult<Self::SerializeSeq> { + no_impl!("serialize_seq") + } + + fn serialize_tuple(self, _len: usize) -> EncodeResult<Self::SerializeTuple> { + no_impl!("serialize_tuple") + } + + fn serialize_tuple_struct(self, + _name: &'static str, + _len: usize) + -> EncodeResult<Self::SerializeTupleStruct> { + no_impl!("serialize_tuple_struct") + } + + fn serialize_tuple_variant(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize) + -> EncodeResult<Self::SerializeTupleVariant> { + no_impl!("serialize_tuple_variant") + } + + fn serialize_map(self, _len: Option<usize>) -> EncodeResult<Self::SerializeMap> { + Ok(MapEncoder { _enc: self }) + } + + fn serialize_struct(self, + _name: &'static str, + _len: usize) + -> EncodeResult<Self::SerializeStruct> { + match mem::replace(&mut self.state, Start) { + Start => { + // root structure + Ok(StructEncoder { enc: self, is_root: true }) + } + NextKey(ref s) => { + // nested structure + match self.keys[self.keys.len() - 1] + .create_subkey_transacted_with_flags(&s, &self.tr, ENCODER_SAM) { + Ok(subkey) => { + self.keys.push(subkey); + Ok(StructEncoder { enc: self, is_root: true }) + } + Err(err) => Err(EncoderError::IoError(err)), + } + } + } + } + + fn serialize_struct_variant(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize) + -> EncodeResult<Self::SerializeStructVariant> { + no_impl!("serialize_struct_variant") + } +} + +pub struct SeqEncoder {} + +impl SerializeSeq for SeqEncoder { + type Ok = (); + type Error = EncoderError; + fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> EncodeResult<Self::Ok> { + no_impl!("SerializeSeq::serialize_element") + } + fn end(self) -> EncodeResult<Self::Ok> { + no_impl!("SerializeSeq::end") + } +} + +pub struct TupleEncoder {} + +impl SerializeTuple for TupleEncoder { + type Ok = (); + type Error = EncoderError; + + fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> EncodeResult<Self::Ok> { + no_impl!("SerializeTuple::serialize_element") + } + + fn end(self) -> EncodeResult<Self::Ok> { + no_impl!("SerializeTuple::end") + } +} + +pub struct TupleStructEncoder {} + +impl SerializeTupleStruct for TupleStructEncoder { + type Ok = (); + type Error = EncoderError; + + fn serialize_field<T: ?Sized + Serialize>(&mut self, _value: &T) -> EncodeResult<Self::Ok> { + no_impl!("SerializeTupleStruct::serialize_field") + } + + fn end(self) -> EncodeResult<Self::Ok> { + no_impl!("SerializeTupleStruct::end") + } +} + +pub struct TupleVariantEncoder {} + +impl SerializeTupleVariant for TupleVariantEncoder { + type Ok = (); + type Error = EncoderError; + + fn serialize_field<T: ?Sized + Serialize>(&mut self, _value: &T) -> EncodeResult<Self::Ok> { + no_impl!("SerializeTupleVariant::serialize_field") + } + + fn end(self) -> EncodeResult<Self::Ok> { + no_impl!("SerializeTupleVariant::end") + } +} + +pub struct MapEncoder<'a> { + _enc: &'a mut Encoder, +} + +impl<'a> SerializeMap for MapEncoder<'a> { + type Ok = (); + type Error = EncoderError; + + fn serialize_key<T: ?Sized + Serialize>(&mut self, _key: &T) -> EncodeResult<Self::Ok> { + no_impl!("SerializeMap::serialize_key") + } + + fn serialize_value<T: ?Sized + Serialize>(&mut self, _value: &T) -> EncodeResult<Self::Ok> { + no_impl!("SerializeMap::serialize_value") + } + + fn end(self) -> EncodeResult<Self::Ok> { + no_impl!("SerializeMap::end") + } +} + +pub struct StructEncoder<'a> { + enc: &'a mut Encoder, + is_root: bool +} + +impl<'a> SerializeStruct for StructEncoder<'a> { + type Ok = (); + type Error = EncoderError; + + fn serialize_field<T: ?Sized + Serialize>(&mut self, + key: &'static str, + value: &T) + -> EncodeResult<Self::Ok> { + self.enc.state = NextKey(String::from(key)); + value.serialize(&mut *self.enc) + } + + fn end(self) -> EncodeResult<Self::Ok> { + if self.is_root { + self.enc.keys.pop(); + } + Ok(()) + } +} + +pub struct StructVariantEncoder {} + +impl SerializeStructVariant for StructVariantEncoder { + type Ok = (); + type Error = EncoderError; + + fn serialize_field<T: ?Sized + Serialize>(&mut self, + _key: &'static str, + _value: &T) + -> EncodeResult<Self::Ok> { + no_impl!("SerializeStructVariant::serialize_field") + } + + fn end(self) -> EncodeResult<Self::Ok> { + no_impl!("SerializeStructVariant::end") + } +} + diff --git a/third_party/rust/winreg/src/enums.rs b/third_party/rust/winreg/src/enums.rs new file mode 100644 index 0000000000..00518cb447 --- /dev/null +++ b/third_party/rust/winreg/src/enums.rs @@ -0,0 +1,58 @@ +// Copyright 2015, Igor Shaula +// Licensed under the MIT License <LICENSE or +// http://opensource.org/licenses/MIT>. This file +// may not be copied, modified, or distributed +// except according to those terms. + +//! `use winreg::enums::*;` to import all needed enumerations and constants +use super::winapi; +pub use winapi::um::winreg::{HKEY_CLASSES_ROOT, + HKEY_CURRENT_USER, + HKEY_LOCAL_MACHINE, + HKEY_USERS, + HKEY_PERFORMANCE_DATA, + HKEY_PERFORMANCE_TEXT, + HKEY_PERFORMANCE_NLSTEXT, + HKEY_CURRENT_CONFIG, + HKEY_DYN_DATA, + HKEY_CURRENT_USER_LOCAL_SETTINGS}; +pub use winapi::um::winnt::{KEY_QUERY_VALUE, + KEY_SET_VALUE, + KEY_CREATE_SUB_KEY, + KEY_ENUMERATE_SUB_KEYS, + KEY_NOTIFY, + KEY_CREATE_LINK, + KEY_WOW64_32KEY, + KEY_WOW64_64KEY, + KEY_WOW64_RES, + KEY_READ, + KEY_WRITE, + KEY_EXECUTE, + KEY_ALL_ACCESS}; + +macro_rules! winapi_enum{ + ($t:ident, $doc:expr => [$($v:ident),*]) => ( + #[doc=$doc] + #[allow(non_camel_case_types)] + #[derive(Debug,Clone,PartialEq)] + pub enum $t { + $( $v = winapi::um::winnt::$v as isize ),* + } + ) +} + +winapi_enum!(RegType, "Enumeration of possible registry value types" => [ +REG_NONE, +REG_SZ, +REG_EXPAND_SZ, +REG_BINARY, +REG_DWORD, +REG_DWORD_BIG_ENDIAN, +REG_LINK, +REG_MULTI_SZ, +REG_RESOURCE_LIST, +REG_FULL_RESOURCE_DESCRIPTOR, +REG_RESOURCE_REQUIREMENTS_LIST, +REG_QWORD +]); +pub use self::RegType::*; diff --git a/third_party/rust/winreg/src/lib.rs b/third_party/rust/winreg/src/lib.rs new file mode 100644 index 0000000000..285259f822 --- /dev/null +++ b/third_party/rust/winreg/src/lib.rs @@ -0,0 +1,1170 @@ +// Copyright 2015, Igor Shaula +// Licensed under the MIT License <LICENSE or +// http://opensource.org/licenses/MIT>. This file +// may not be copied, modified, or distributed +// except according to those terms. + +//! Crate for accessing MS Windows registry +//! +//!## Usage +//! +//!### Basic usage +//! +//!```toml,ignore +//!# Cargo.toml +//![dependencies] +//!winreg = "0.5" +//!``` +//! +//!```no_run +//!extern crate winreg; +//!use std::path::Path; +//!use std::io; +//!use winreg::RegKey; +//!use winreg::enums::*; +//! +//!fn main() { +//! println!("Reading some system info..."); +//! let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); +//! let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion").unwrap(); +//! let pf: String = cur_ver.get_value("ProgramFilesDir").unwrap(); +//! let dp: String = cur_ver.get_value("DevicePath").unwrap(); +//! println!("ProgramFiles = {}\nDevicePath = {}", pf, dp); +//! let info = cur_ver.query_info().unwrap(); +//! println!("info = {:?}", info); +//! +//! println!("And now lets write something..."); +//! let hkcu = RegKey::predef(HKEY_CURRENT_USER); +//! let path = Path::new("Software").join("WinregRsExample1"); +//! let key = hkcu.create_subkey(&path).unwrap(); +//! +//! key.set_value("TestSZ", &"written by Rust").unwrap(); +//! let sz_val: String = key.get_value("TestSZ").unwrap(); +//! key.delete_value("TestSZ").unwrap(); +//! println!("TestSZ = {}", sz_val); +//! +//! key.set_value("TestDWORD", &1234567890u32).unwrap(); +//! let dword_val: u32 = key.get_value("TestDWORD").unwrap(); +//! println!("TestDWORD = {}", dword_val); +//! +//! key.set_value("TestQWORD", &1234567891011121314u64).unwrap(); +//! let qword_val: u64 = key.get_value("TestQWORD").unwrap(); +//! println!("TestQWORD = {}", qword_val); +//! +//! key.create_subkey("sub\\key").unwrap(); +//! hkcu.delete_subkey_all(&path).unwrap(); +//! +//! println!("Trying to open nonexistent key..."); +//! let key2 = hkcu.open_subkey(&path) +//! .unwrap_or_else(|e| match e.kind() { +//! io::ErrorKind::NotFound => panic!("Key doesn't exist"), +//! io::ErrorKind::PermissionDenied => panic!("Access denied"), +//! _ => panic!("{:?}", e) +//! }); +//!} +//!``` +//! +//!### Iterators +//! +//!```no_run +//!extern crate winreg; +//!use winreg::RegKey; +//!use winreg::enums::*; +//! +//!fn main() { +//! println!("File extensions, registered in system:"); +//! for i in RegKey::predef(HKEY_CLASSES_ROOT) +//! .enum_keys().map(|x| x.unwrap()) +//! .filter(|x| x.starts_with(".")) +//! { +//! println!("{}", i); +//! } +//! +//! let system = RegKey::predef(HKEY_LOCAL_MACHINE) +//! .open_subkey("HARDWARE\\DESCRIPTION\\System").unwrap(); +//! for (name, value) in system.enum_values().map(|x| x.unwrap()) { +//! println!("{} = {:?}", name, value); +//! } +//!} +//!``` +//! +#![cfg_attr(feature="clippy", feature(plugin))] +#![cfg_attr(feature="clippy", plugin(clippy))] +#![cfg_attr(feature="clippy", warn(option_unwrap_used))] +#![cfg_attr(feature="clippy", warn(result_unwrap_used))] +extern crate winapi; +#[cfg(feature = "serialization-serde")] +extern crate serde; +use std::ptr; +use std::slice; +use std::fmt; +use std::default::Default; +use std::ffi::OsStr; +use std::os::windows::ffi::OsStrExt; +use std::mem::transmute; +use std::io; +use winapi::shared::winerror; +pub use winapi::shared::minwindef::HKEY; +use winapi::shared::minwindef::{DWORD, BYTE, LPBYTE}; +use winapi::um::winnt::{self, WCHAR}; +use winapi::um::winreg as winapi_reg; +use enums::*; +use types::{FromRegValue, ToRegValue}; +#[cfg(feature = "transactions")] +use transaction::Transaction; + +macro_rules! werr { + ($e:expr) => ( + Err(io::Error::from_raw_os_error($e as i32)) + ) +} + +pub mod enums; +pub mod types; +#[cfg(feature = "transactions")] +pub mod transaction; +#[cfg(feature = "serialization-serde")] +mod encoder; +#[cfg(feature = "serialization-serde")] +mod decoder; + +/// Metadata returned by `RegKey::query_info` +#[derive(Debug,Default)] +pub struct RegKeyMetadata { + // pub Class: winapi::LPWSTR, + // pub ClassLen: DWORD, + pub sub_keys: DWORD, + pub max_sub_key_len: DWORD, + pub max_class_len: DWORD, + pub values: DWORD, + pub max_value_name_len: DWORD, + pub max_value_len: DWORD, + // pub SecurityDescriptor: DWORD, + // pub LastWriteTime: winapi::PFILETIME, +} + +/// Raw registry value +#[derive(PartialEq)] +pub struct RegValue { + pub bytes: Vec<u8>, + pub vtype: RegType, +} + +macro_rules! format_reg_value { + ($e:expr => $t:ident) => ( + match $t::from_reg_value($e) { + Ok(val) => format!("{:?}", val), + Err(_) => return Err(fmt::Error), + } + ) +} + +impl fmt::Debug for RegValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let f_val = match self.vtype { + REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => { + format_reg_value!(self => String) + }, + REG_DWORD => { + format_reg_value!(self => u32) + }, + REG_QWORD => { + format_reg_value!(self => u64) + }, + _ => format!("{:?}", self.bytes) //TODO: implement more types + }; + write!(f, "RegValue({:?}: {})", self.vtype, f_val) + } +} + +/// Handle of opened registry key +#[derive(Debug)] +pub struct RegKey { + hkey: HKEY, +} + +unsafe impl Send for RegKey {} + +impl RegKey { + /// Open one of predefined keys: + /// + /// * `HKEY_CLASSES_ROOT` + /// * `HKEY_CURRENT_USER` + /// * `HKEY_LOCAL_MACHINE` + /// * `HKEY_USERS` + /// * `HKEY_PERFORMANCE_DATA` + /// * `HKEY_PERFORMANCE_TEXT` + /// * `HKEY_PERFORMANCE_NLSTEXT` + /// * `HKEY_CURRENT_CONFIG` + /// * `HKEY_DYN_DATA` + /// * `HKEY_CURRENT_USER_LOCAL_SETTINGS` + /// + /// # Examples + /// + /// ```no_run + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + /// ``` + pub fn predef(hkey: HKEY) -> RegKey { + RegKey{ hkey: hkey } + } + + /// Return inner winapi HKEY of a key: + /// + /// # Examples + /// + /// ```no_run + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + /// let soft = hklm.open_subkey("SOFTWARE").unwrap(); + /// let handle = soft.raw_handle(); + /// ``` + pub fn raw_handle(&self) -> HKEY { + self.hkey + } + + /// Open subkey with `KEY_READ` permissions. + /// Will open another handle to itself if `path` is an empty string. + /// To open with different permissions use `open_subkey_with_flags`. + /// You can also use `create_subkey` to open with `KEY_ALL_ACCESS` permissions. + /// + /// # Examples + /// + /// ```no_run + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// let soft = RegKey::predef(HKEY_CURRENT_USER) + /// .open_subkey("Software").unwrap(); + /// ``` + pub fn open_subkey<P: AsRef<OsStr>>(&self, path: P) -> io::Result<RegKey> { + self.open_subkey_with_flags(path, enums::KEY_READ) + } + + /// Open subkey with desired permissions. + /// Will open another handle to itself if `path` is an empty string. + /// + /// # Examples + /// + /// ```no_run + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + /// hklm.open_subkey_with_flags("SOFTWARE\\Microsoft", KEY_READ).unwrap(); + /// ``` + pub fn open_subkey_with_flags<P: AsRef<OsStr>>(&self, path: P, perms: winapi_reg::REGSAM) -> io::Result<RegKey> { + let c_path = to_utf16(path); + let mut new_hkey: HKEY = ptr::null_mut(); + match unsafe { + winapi_reg::RegOpenKeyExW( + self.hkey, + c_path.as_ptr(), + 0, + perms, + &mut new_hkey, + ) as DWORD + } { + 0 => Ok(RegKey{ hkey: new_hkey }), + err => werr!(err) + } + } + + /// Part of `transactions` feature. + #[cfg(feature = "transactions")] + pub fn open_subkey_transacted<P: AsRef<OsStr>>(&self, path: P, t: &Transaction) -> io::Result<RegKey> { + self.open_subkey_transacted_with_flags(path, t, winnt::KEY_READ) + } + + /// Part of `transactions` feature. + #[cfg(feature = "transactions")] + pub fn open_subkey_transacted_with_flags<P: AsRef<OsStr>>(&self, path: P, t: &Transaction, perms: winapi_reg::REGSAM) + -> io::Result<RegKey> + { + let c_path = to_utf16(path); + let mut new_hkey: HKEY = ptr::null_mut(); + match unsafe { + winapi_reg::RegOpenKeyTransactedW( + self.hkey, + c_path.as_ptr(), + 0, + perms, + &mut new_hkey, + t.handle, + ptr::null_mut(), + ) as DWORD + } { + 0 => Ok(RegKey{ hkey: new_hkey }), + err => werr!(err) + } + } + + /// Create subkey (and all missing parent keys) + /// and open it with `KEY_ALL_ACCESS` permissions. + /// Will just open key if it already exists. + /// Will open another handle to itself if `path` is an empty string. + /// To create with different permissions use `create_subkey_with_flags`. + /// + /// # Examples + /// + /// ```no_run + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let settings = hkcu.create_subkey("Software\\MyProduct\\Settings").unwrap(); + /// ``` + pub fn create_subkey<P: AsRef<OsStr>>(&self, path: P) -> io::Result<RegKey> { + self.create_subkey_with_flags(path, enums::KEY_ALL_ACCESS) + } + + pub fn create_subkey_with_flags<P: AsRef<OsStr>>(&self, path: P, perms: winapi_reg::REGSAM) -> io::Result<RegKey> { + let c_path = to_utf16(path); + let mut new_hkey: HKEY = ptr::null_mut(); + let mut disp: DWORD = 0; + match unsafe { + winapi_reg::RegCreateKeyExW( + self.hkey, + c_path.as_ptr(), + 0, + ptr::null_mut(), + winnt::REG_OPTION_NON_VOLATILE, + perms, + ptr::null_mut(), + &mut new_hkey, + &mut disp // TODO: return this somehow + ) + } { + 0 => Ok(RegKey{ hkey: new_hkey }), + err => werr!(err) + } + } + + /// Part of `transactions` feature. + #[cfg(feature = "transactions")] + pub fn create_subkey_transacted<P: AsRef<OsStr>>(&self, path: P, t: &Transaction) -> io::Result<RegKey> { + self.create_subkey_transacted_with_flags(path, t, winnt::KEY_ALL_ACCESS) + } + + /// Part of `transactions` feature. + #[cfg(feature = "transactions")] + pub fn create_subkey_transacted_with_flags<P: AsRef<OsStr>>(&self, path: P, t: &Transaction, perms: winapi_reg::REGSAM) + -> io::Result<RegKey> + { + let c_path = to_utf16(path); + let mut new_hkey: HKEY = ptr::null_mut(); + let mut disp: DWORD = 0; + match unsafe { + winapi_reg::RegCreateKeyTransactedW( + self.hkey, + c_path.as_ptr(), + 0, + ptr::null_mut(), + winnt::REG_OPTION_NON_VOLATILE, + perms, + ptr::null_mut(), + &mut new_hkey, + &mut disp, // TODO: return this somehow + t.handle, + ptr::null_mut(), + ) as DWORD + } { + 0 => Ok(RegKey{ hkey: new_hkey }), + err => werr!(err) + } + } + + /// Copy all the values and subkeys from `path` to `dest` key. + /// WIll copy the content of `self` if `path` is an empty string. + /// + /// # Examples + /// + /// ```no_run + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let src = hkcu.open_subkey_with_flags("Software\\MyProduct", KEY_READ).unwrap(); + /// let dst = hkcu.create_subkey("Software\\MyProduct\\Section2").unwrap(); + /// src.copy_tree("Section1", &dst).unwrap(); + /// ``` + pub fn copy_tree<P: AsRef<OsStr>>(&self, path: P, dest: &RegKey) -> io::Result<()> { + let c_path = to_utf16(path); + match unsafe { + winapi_reg::RegCopyTreeW( + self.hkey, + c_path.as_ptr(), + dest.hkey, + ) + } { + 0 => Ok(()), + err => werr!(err) + } + } + + pub fn query_info(&self) -> io::Result<RegKeyMetadata> { + let mut info: RegKeyMetadata = Default::default(); + match unsafe { + winapi_reg::RegQueryInfoKeyW( + self.hkey, + ptr::null_mut(), // Class: winapi::LPWSTR, + ptr::null_mut(), // ClassLen: DWORD, + ptr::null_mut(), // Reserved + &mut info.sub_keys, + &mut info.max_sub_key_len, + &mut info.max_class_len, + &mut info.values, + &mut info.max_value_name_len, + &mut info.max_value_len, + ptr::null_mut(), // lpcbSecurityDescriptor: winapi::LPDWORD, + ptr::null_mut(), // lpftLastWriteTime: winapi::PFILETIME, + ) as DWORD + } { + 0 => Ok(info), + err => werr!(err) + } + } + + /// Return an iterator over subkeys names. + /// + /// # Examples + /// + /// ```no_run + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// println!("File extensions, registered in this system:"); + /// for i in RegKey::predef(HKEY_CLASSES_ROOT) + /// .enum_keys().map(|x| x.unwrap()) + /// .filter(|x| x.starts_with(".")) + /// { + /// println!("{}", i); + /// } + /// ``` + pub fn enum_keys(&self) -> EnumKeys { + EnumKeys{key: self, index: 0} + } + + /// Return an iterator over values. + /// + /// # Examples + /// + /// ```no_run + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// let system = RegKey::predef(HKEY_LOCAL_MACHINE) + /// .open_subkey_with_flags("HARDWARE\\DESCRIPTION\\System", KEY_READ) + /// .unwrap(); + /// for (name, value) in system.enum_values().map(|x| x.unwrap()) { + /// println!("{} = {:?}", name, value); + /// } + /// ``` + pub fn enum_values(&self) -> EnumValues { + EnumValues{key: self, index: 0} + } + + /// Delete key.Key names are not case sensitive. + /// Cannot delete if it has subkeys. + /// Use `delete_subkey_all` for that. + /// + /// # Examples + /// + /// ```no_run + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// RegKey::predef(HKEY_CURRENT_USER) + /// .delete_subkey(r"Software\MyProduct\History").unwrap(); + /// ``` + pub fn delete_subkey<P: AsRef<OsStr>>(&self, path: P) -> io::Result<()> { + let c_path = to_utf16(path); + match unsafe { + winapi_reg::RegDeleteKeyW( + self.hkey, + c_path.as_ptr(), //This parameter cannot be NULL. + ) as DWORD + } { + 0 => Ok(()), + err => werr!(err) + } + } + + /// Part of `transactions` feature. + #[cfg(feature = "transactions")] + pub fn delete_subkey_transacted<P: AsRef<OsStr>>(&self, path: P, t: &Transaction) -> io::Result<()> { + let c_path = to_utf16(path); + match unsafe { + winapi_reg::RegDeleteKeyTransactedW( + self.hkey, + c_path.as_ptr(), //The value of this parameter cannot be NULL. + 0, + 0, + t.handle, + ptr::null_mut(), + ) as DWORD + } { + 0 => Ok(()), + err => werr!(err) + } + } + + /// Recursively delete subkey with all its subkeys and values. + /// If `path` is an empty string, the subkeys and values of this key are deleted. + /// + /// # Examples + /// + /// ```no_run + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// RegKey::predef(HKEY_CURRENT_USER) + /// .delete_subkey_all("Software\\MyProduct").unwrap(); + /// ``` + pub fn delete_subkey_all<P: AsRef<OsStr>>(&self, path: P) -> io::Result<()> { + let c_path; + let path_ptr; + if path.as_ref().is_empty(){ + path_ptr = ptr::null(); + }else{ + c_path = to_utf16(path); + path_ptr = c_path.as_ptr(); + } + match unsafe{ + winapi_reg::RegDeleteTreeW( + self.hkey, + path_ptr,//If this parameter is NULL, the subkeys and values of this key are deleted. + ) as DWORD + } { + 0 => Ok(()), + err => werr!(err) + } + } + + /// Get a value from registry and seamlessly convert it to the specified rust type + /// with `FromRegValue` implemented (currently `String`, `u32` and `u64`). + /// Will get the `Default` value if `name` is an empty string. + /// + /// # Examples + /// + /// ```no_run + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings").unwrap(); + /// let server: String = settings.get_value("server").unwrap(); + /// let port: u32 = settings.get_value("port").unwrap(); + /// ``` + pub fn get_value<T: FromRegValue, N: AsRef<OsStr>>(&self, name: N) -> io::Result<T> { + match self.get_raw_value(name) { + Ok(ref val) => FromRegValue::from_reg_value(val), + Err(err) => Err(err) + } + } + + /// Get raw bytes from registry value. + /// Will get the `Default` value if `name` is an empty string. + /// + /// # Examples + /// + /// ```no_run + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings").unwrap(); + /// let data = settings.get_raw_value("data").unwrap(); + /// println!("Bytes: {:?}", data.bytes); + /// ``` + pub fn get_raw_value<N: AsRef<OsStr>>(&self, name: N) -> io::Result<RegValue> { + let c_name = to_utf16(name); + let mut buf_len: DWORD = 2048; + let mut buf_type: DWORD = 0; + let mut buf: Vec<u8> = Vec::with_capacity(buf_len as usize); + loop { + match unsafe { + winapi_reg::RegQueryValueExW( + self.hkey, + c_name.as_ptr() as *const u16, + ptr::null_mut(), + &mut buf_type, + buf.as_mut_ptr() as LPBYTE, + &mut buf_len + ) as DWORD + } { + 0 => { + unsafe{ buf.set_len(buf_len as usize); } + // minimal check before transmute to RegType + if buf_type > winnt::REG_QWORD { + return werr!(winerror::ERROR_BAD_FILE_TYPE); + } + let t: RegType = unsafe{ transmute(buf_type as u8) }; + return Ok(RegValue{ bytes: buf, vtype: t }) + }, + winerror::ERROR_MORE_DATA => { + buf.reserve(buf_len as usize); + }, + err => return werr!(err), + } + } + } + + /// Seamlessly convert a value from a rust type and write it to the registry value + /// with `ToRegValue` trait implemented (currently `String`, `&str`, `u32` and `u64`). + /// Will set the `Default` value if `name` is an empty string. + /// + /// # Examples + /// + /// ```no_run + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let settings = hkcu.create_subkey("Software\\MyProduct\\Settings").unwrap(); + /// settings.set_value("server", &"www.example.com").unwrap(); + /// settings.set_value("port", &8080u32).unwrap(); + /// ``` + pub fn set_value<T: ToRegValue, N: AsRef<OsStr>>(&self, name: N, value: &T) -> io::Result<()> { + self.set_raw_value(name, &value.to_reg_value()) + } + + /// Write raw bytes from `RegValue` struct to a registry value. + /// Will set the `Default` value if `name` is an empty string. + /// + /// # Examples + /// + /// ```no_run + /// use winreg::{RegKey, RegValue}; + /// use winreg::enums::*; + /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings").unwrap(); + /// let bytes: Vec<u8> = vec![1, 2, 3, 5, 8, 13, 21, 34, 55, 89]; + /// let data = RegValue{ vtype: REG_BINARY, bytes: bytes}; + /// settings.set_raw_value("data", &data).unwrap(); + /// println!("Bytes: {:?}", data.bytes) + /// ``` + pub fn set_raw_value<N: AsRef<OsStr>>(&self, name: N, value: &RegValue) -> io::Result<()> { + let c_name = to_utf16(name); + let t = value.vtype.clone() as DWORD; + match unsafe{ + winapi_reg::RegSetValueExW( + self.hkey, + c_name.as_ptr(), + 0, + t, + value.bytes.as_ptr() as *const BYTE, + value.bytes.len() as u32 + ) as DWORD + } { + 0 => Ok(()), + err => werr!(err) + } + } + + /// Delete specified value from registry. + /// Will delete the `Default` value if `name` is an empty string. + /// + /// # Examples + /// + /// ```no_run + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings").unwrap(); + /// settings.delete_value("data").unwrap(); + /// ``` + pub fn delete_value<N: AsRef<OsStr>>(&self, name: N) -> io::Result<()> { + let c_name = to_utf16(name); + match unsafe { + winapi_reg::RegDeleteValueW( + self.hkey, + c_name.as_ptr(), + ) as DWORD + } { + 0 => Ok(()), + err => werr!(err) + } + } + + /// Save `Encodable` type to a registry key. + /// Part of `serialization-serde` feature. + /// + /// # Examples + /// + /// ```no_run + /// #[macro_use] + /// extern crate serde_derive; + /// extern crate winreg; + /// # fn main() { + /// use winreg::RegKey; + /// use winreg::enums::*; + /// + /// #[derive(Serialize)] + /// struct Rectangle{ + /// x: u32, + /// y: u32, + /// w: u32, + /// h: u32, + /// } + /// + /// #[derive(Serialize)] + /// struct Settings{ + /// current_dir: String, + /// window_pos: Rectangle, + /// show_in_tray: bool, + /// } + /// + /// let s: Settings = Settings{ + /// current_dir: "C:\\".to_owned(), + /// window_pos: Rectangle{ x:200, y: 100, w: 800, h: 500 }, + /// show_in_tray: false, + /// }; + /// let s_key = RegKey::predef(HKEY_CURRENT_USER) + /// .open_subkey("Software\\MyProduct\\Settings").unwrap(); + /// s_key.encode(&s).unwrap(); + /// # } + /// ``` + #[cfg(feature = "serialization-serde")] + pub fn encode<T: serde::Serialize>(&self, value: &T) + -> encoder::EncodeResult<()> + { + let mut encoder = try!( + encoder::Encoder::from_key(self) + ); + try!(value.serialize(&mut encoder)); + encoder.commit() + } + + /// Load `Decodable` type from a registry key. + /// Part of `serialization-serde` feature. + /// + /// # Examples + /// + /// ```no_run + /// #[macro_use] + /// extern crate serde_derive; + /// extern crate winreg; + /// # fn main() { + /// use winreg::RegKey; + /// use winreg::enums::*; + /// + /// #[derive(Deserialize)] + /// struct Rectangle{ + /// x: u32, + /// y: u32, + /// w: u32, + /// h: u32, + /// } + /// + /// #[derive(Deserialize)] + /// struct Settings{ + /// current_dir: String, + /// window_pos: Rectangle, + /// show_in_tray: bool, + /// } + /// + /// let s_key = RegKey::predef(HKEY_CURRENT_USER) + /// .open_subkey("Software\\MyProduct\\Settings").unwrap(); + /// let s: Settings = s_key.decode().unwrap(); + /// # } + /// ``` + #[cfg(feature = "serialization-serde")] + pub fn decode<'de, T: serde::Deserialize<'de>>(&self) + -> decoder::DecodeResult<T> + { + let mut decoder = try!( + decoder::Decoder::from_key(self) + ); + T::deserialize(&mut decoder) + } + + fn close_(&mut self) -> io::Result<()> { + // don't try to close predefined keys + if self.hkey >= enums::HKEY_CLASSES_ROOT { return Ok(()) }; + match unsafe { + winapi_reg::RegCloseKey(self.hkey) as DWORD + } { + 0 => Ok(()), + err => werr!(err) + } + } + + fn enum_key(&self, index: DWORD) -> Option<io::Result<String>> { + let mut name_len = 2048; + let mut name = [0 as WCHAR; 2048]; + match unsafe { + winapi_reg::RegEnumKeyExW( + self.hkey, + index, + name.as_mut_ptr(), + &mut name_len, + ptr::null_mut(), // reserved + ptr::null_mut(), // lpClass: LPWSTR, + ptr::null_mut(), // lpcClass: LPDWORD, + ptr::null_mut(), // lpftLastWriteTime: PFILETIME, + ) as DWORD + } { + 0 => { + match String::from_utf16(&name[..name_len as usize]) { + Ok(s) => Some(Ok(s)), + Err(_) => Some(werr!(winerror::ERROR_INVALID_BLOCK)) + } + }, + winerror::ERROR_NO_MORE_ITEMS => None, + err => { + Some(werr!(err)) + } + } + } + + fn enum_value(&self, index: DWORD) -> Option<io::Result<(String, RegValue)>> { + let mut name_len = 2048; + let mut name = [0 as WCHAR; 2048]; + + let mut buf_len: DWORD = 2048; + let mut buf_type: DWORD = 0; + let mut buf: Vec<u8> = Vec::with_capacity(buf_len as usize); + loop { + match unsafe { + winapi_reg::RegEnumValueW( + self.hkey, + index, + name.as_mut_ptr(), + &mut name_len, + ptr::null_mut(), // reserved + &mut buf_type, + buf.as_mut_ptr() as LPBYTE, + &mut buf_len, + ) as DWORD + } { + 0 => { + let name = match String::from_utf16(&name[..name_len as usize]) { + Ok(s) => s, + Err(_) => return Some(werr!(winerror::ERROR_INVALID_DATA)) + }; + unsafe{ buf.set_len(buf_len as usize); } + // minimal check before transmute to RegType + if buf_type > winnt::REG_QWORD { + return Some(werr!(winerror::ERROR_BAD_FILE_TYPE)); + } + let t: RegType = unsafe{ transmute(buf_type as u8) }; + let value = RegValue{ bytes: buf, vtype: t }; + return Some(Ok((name, value))) + }, + winerror::ERROR_MORE_DATA => { + name_len += 1; //for NULL char + buf.reserve(buf_len as usize); + }, + winerror::ERROR_NO_MORE_ITEMS => return None, + err => return Some(werr!(err)) + } + } + } +} + +impl Drop for RegKey { + fn drop(&mut self) { + self.close_().unwrap_or(()); + } +} + +/// Iterator over subkeys names +pub struct EnumKeys<'key> { + key: &'key RegKey, + index: DWORD, +} + +impl<'key> Iterator for EnumKeys<'key> { + type Item = io::Result<String>; + + fn next(&mut self) -> Option<io::Result<String>> { + match self.key.enum_key(self.index) { + v @ Some(_) => { + self.index += 1; + v + }, + e @ None => e + } + } +} + +/// Iterator over values +pub struct EnumValues<'key> { + key: &'key RegKey, + index: DWORD, +} + +impl<'key> Iterator for EnumValues<'key> { + type Item = io::Result<(String, RegValue)>; + + fn next(&mut self) -> Option<io::Result<(String, RegValue)>> { + match self.key.enum_value(self.index) { + v @ Some(_) => { + self.index += 1; + v + }, + e @ None => e + } + } +} + +fn to_utf16<P: AsRef<OsStr>>(s: P) -> Vec<u16> { + s.as_ref().encode_wide().chain(Some(0).into_iter()).collect() +} + +fn v16_to_v8(v: &[u16]) -> Vec<u8> { + unsafe { + slice::from_raw_parts(v.as_ptr() as *const u8, v.len()*2).to_vec() + } +} + +#[cfg(all(test, feature = "serialization-serde"))] +#[macro_use] +extern crate serde_derive; + +#[cfg(test)] +#[cfg_attr(feature="clippy", allow(option_unwrap_used))] +#[cfg_attr(feature="clippy", allow(result_unwrap_used))] +mod test { + extern crate rand; + use super::*; + use std::collections::HashMap; + use self::rand::Rng; + use std::ffi::{OsStr,OsString}; + + #[test] + fn test_raw_handle() { + let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + let handle = hklm.raw_handle(); + assert_eq!(HKEY_LOCAL_MACHINE, handle); + } + + #[test] + fn test_open_subkey_with_flags_query_info() { + let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + let win = hklm.open_subkey_with_flags("Software\\Microsoft\\Windows", KEY_READ).unwrap(); + assert!(win.query_info().is_ok()); + assert!(win.open_subkey_with_flags("CurrentVersion\\", KEY_READ).is_ok()); + assert!(hklm.open_subkey_with_flags("i\\just\\hope\\nobody\\created\\that\\key", KEY_READ).is_err()); + } + + macro_rules! with_key { + ($k:ident, $path:expr => $b:block) => {{ + let mut path = "Software\\WinRegRsTest".to_owned(); + path.push_str($path); + let $k = RegKey::predef(HKEY_CURRENT_USER) + .create_subkey(&path).unwrap(); + $b + RegKey::predef(HKEY_CURRENT_USER) + .delete_subkey_all(path).unwrap(); + }} + } + + #[test] + fn test_delete_subkey() { + let path = "Software\\WinRegRsTestDeleteSubkey"; + RegKey::predef(HKEY_CURRENT_USER).create_subkey(path).unwrap(); + assert!(RegKey::predef(HKEY_CURRENT_USER) + .delete_subkey(path).is_ok()); + } + + #[test] + fn test_copy_tree() { + with_key!(key, "CopyTree" => { + let sub_tree = key.create_subkey("Src\\Sub\\Tree").unwrap(); + for v in &["one", "two", "three"] { + sub_tree.set_value(v, v).unwrap(); + } + let dst = key.create_subkey("Dst").unwrap(); + assert!(key.copy_tree("Src", &dst).is_ok()); + }); + } + + #[test] + fn test_long_value() { + with_key!(key, "LongValue" => { + let name = "RustLongVal"; + let val1 = RegValue { vtype: REG_BINARY, bytes: (0..6000).map(|_| rand::random::<u8>()).collect() }; + key.set_raw_value(name, &val1).unwrap(); + let val2 = key.get_raw_value(name).unwrap(); + assert_eq!(val1, val2); + }); + } + + #[test] + fn test_string_value() { + with_key!(key, "StringValue" => { + let name = "RustStringVal"; + let val1 = "Test123 \n$%^&|+-*/\\()".to_owned(); + key.set_value(name, &val1).unwrap(); + let val2: String = key.get_value(name).unwrap(); + assert_eq!(val1, val2); + }); + } + + #[test] + fn test_long_string_value() { + with_key!(key, "LongStringValue" => { + let name = "RustLongStringVal"; + let val1 : String = rand::thread_rng().gen_ascii_chars().take(7000).collect(); + key.set_value(name, &val1).unwrap(); + let val2: String = key.get_value(name).unwrap(); + assert_eq!(val1, val2); + }); + } + + #[test] + fn test_os_string_value() { + with_key!(key, "OsStringValue" => { + let name = "RustOsStringVal"; + let val1 = OsStr::new("Test123 \n$%^&|+-*/\\()\u{0}"); + key.set_value(name, &val1).unwrap(); + let val2: OsString = key.get_value(name).unwrap(); + assert_eq!(val1, val2); + }); + } + + #[test] + fn test_long_os_string_value() { + with_key!(key, "LongOsStringValue" => { + let name = "RustLongOsStringVal"; + let mut val1 = rand::thread_rng().gen_ascii_chars().take(7000).collect::<String>(); + val1.push('\u{0}'); + let val1 = OsStr::new(&val1); + key.set_value(name, &val1).unwrap(); + let val2: OsString = key.get_value(name).unwrap(); + assert_eq!(val1, val2); + }); + } + + #[test] + fn test_u32_value() { + with_key!(key, "U32Value" => { + let name = "RustU32Val"; + let val1 = 1234567890u32; + key.set_value(name, &val1).unwrap(); + let val2: u32 = key.get_value(name).unwrap(); + assert_eq!(val1, val2); + }); + } + + #[test] + fn test_u64_value() { + with_key!(key, "U64Value" => { + let name = "RustU64Val"; + let val1 = 1234567891011121314u64; + key.set_value(name, &val1).unwrap(); + let val2: u64 = key.get_value(name).unwrap(); + assert_eq!(val1, val2); + }); + } + + #[test] + fn test_delete_value() { + with_key!(key, "DeleteValue" => { + let name = "WinregRsTestVal"; + key.set_value(name, &"Qwerty123").unwrap(); + assert!(key.delete_value(name).is_ok()); + }); + } + + #[test] + fn test_enum_keys() { + with_key!(key, "EnumKeys" => { + let mut keys1 = vec!("qwerty", "asdf", "1", "2", "3", "5", "8", "йцукен"); + keys1.sort(); + for i in &keys1 { + key.create_subkey(i).unwrap(); + } + let keys2: Vec<_> = key.enum_keys().map(|x| x.unwrap()).collect(); + assert_eq!(keys1, keys2); + }); + } + + #[test] + fn test_enum_values() { + with_key!(key, "EnumValues" => { + let mut vals1 = vec!("qwerty", "asdf", "1", "2", "3", "5", "8", "йцукен"); + vals1.sort(); + for i in &vals1 { + key.set_value(i,i).unwrap(); + } + let mut vals2: Vec<String> = Vec::with_capacity(vals1.len()); + let mut vals3: Vec<String> = Vec::with_capacity(vals1.len()); + for (name, val) in key.enum_values() + .map(|x| x.unwrap()) + { + vals2.push(name); + vals3.push(String::from_reg_value(&val).unwrap()); + } + assert_eq!(vals1, vals2); + assert_eq!(vals1, vals3); + }); + } + + #[test] + fn test_enum_long_values() { + with_key!(key, "EnumLongValues" => { + let mut vals = HashMap::with_capacity(3); + + for i in &[5500, 9500, 15000] { + let name: String = format!("val{}", i); + let val = RegValue { vtype: REG_BINARY, bytes: (0..*i).map(|_| rand::random::<u8>()).collect() }; + vals.insert(name, val); + } + + for (name, val) in key.enum_values() + .map(|x| x.unwrap()) + { + assert_eq!(val.bytes, vals[&name].bytes); + } + }); + } + + #[cfg(feature = "serialization-serde")] + #[test] + fn test_serialization() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Rectangle{ + x: u32, + y: u32, + w: u32, + h: u32, + } + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Test { + t_bool: bool, + t_u8: u8, + t_u16: u16, + t_u32: u32, + t_u64: u64, + t_usize: usize, + t_struct: Rectangle, + t_string: String, + t_i8: i8, + t_i16: i16, + t_i32: i32, + t_i64: i64, + t_isize: isize, + t_f64: f64, + t_f32: f32, + } + + let v1 = Test{ + t_bool: false, + t_u8: 127, + t_u16: 32768, + t_u32: 123456789, + t_u64: 123456789101112, + t_usize: 1234567891, + t_struct: Rectangle{ x: 55, y: 77, w: 500, h: 300 }, + t_string: "Test123 \n$%^&|+-*/\\()".to_owned(), + t_i8: -123, + t_i16: -2049, + t_i32: 20100, + t_i64: -12345678910, + t_isize: -1234567890, + t_f64: -0.01, + t_f32: 3.14, + }; + + with_key!(key, "Serialization" => { + key.encode(&v1).unwrap(); + let v2: Test = key.decode().unwrap(); + assert_eq!(v1, v2); + }); + } +} diff --git a/third_party/rust/winreg/src/transaction.rs b/third_party/rust/winreg/src/transaction.rs new file mode 100644 index 0000000000..5686e96b32 --- /dev/null +++ b/third_party/rust/winreg/src/transaction.rs @@ -0,0 +1,105 @@ +// Copyright 2015, Igor Shaula +// Licensed under the MIT License <LICENSE or +// http://opensource.org/licenses/MIT>. This file +// may not be copied, modified, or distributed +// except according to those terms. + +//! Structure for a registry transaction. +//! Part of `transactions` feature. +//! +//!```no_run +//!extern crate winreg; +//!use std::io; +//!use winreg::RegKey; +//!use winreg::enums::*; +//!use winreg::transaction::Transaction; +//! +//!fn main() { +//! let t = Transaction::new().unwrap(); +//! let hkcu = RegKey::predef(HKEY_CURRENT_USER); +//! let key = hkcu.create_subkey_transacted("Software\\RustTransaction", &t).unwrap(); +//! key.set_value("TestQWORD", &1234567891011121314u64).unwrap(); +//! key.set_value("TestDWORD", &1234567890u32).unwrap(); +//! +//! println!("Commit transaction? [y/N]:"); +//! let mut input = String::new(); +//! io::stdin().read_line(&mut input).unwrap(); +//! input = input.trim_right().to_owned(); +//! if input == "y" || input == "Y" { +//! t.commit().unwrap(); +//! println!("Transaction committed."); +//! } +//! else { +//! // this is optional, if transaction wasn't committed, +//! // it will be rolled back on disposal +//! t.rollback().unwrap(); +//! +//! println!("Transaction wasn't committed, it will be rolled back."); +//! } +//!} +//!``` +#![cfg(feature = "transactions")] +use std::ptr; +use std::io; +use winapi::um::winnt; +use winapi::um::handleapi; +use winapi::um::ktmw32; + +#[derive(Debug)] +pub struct Transaction { + pub handle: winnt::HANDLE, +} + +impl Transaction { + //TODO: add arguments + pub fn new() -> io::Result<Transaction> { + unsafe { + let handle = ktmw32::CreateTransaction( + ptr::null_mut(), + ptr::null_mut(), + 0, + 0, + 0, + 0, + ptr::null_mut(), + ); + if handle == handleapi::INVALID_HANDLE_VALUE { + return Err(io::Error::last_os_error()) + }; + Ok(Transaction{ handle: handle }) + } + } + + pub fn commit(&self) -> io::Result<()> { + unsafe { + match ktmw32::CommitTransaction(self.handle) { + 0 => Err(io::Error::last_os_error()), + _ => Ok(()) + } + } + } + + pub fn rollback(&self) -> io::Result<()> { + unsafe { + match ktmw32::RollbackTransaction(self.handle) { + 0 => Err(io::Error::last_os_error()), + _ => Ok(()) + } + } + } + + fn close_(&mut self) -> io::Result<()> { + unsafe { + match handleapi::CloseHandle(self.handle) { + 0 => Err(io::Error::last_os_error()), + _ => Ok(()) + } + } + } +} + +impl Drop for Transaction { + fn drop(&mut self) { + self.close_().unwrap_or(()); + } +} diff --git a/third_party/rust/winreg/src/types.rs b/third_party/rust/winreg/src/types.rs new file mode 100644 index 0000000000..fd605fa855 --- /dev/null +++ b/third_party/rust/winreg/src/types.rs @@ -0,0 +1,141 @@ +// Copyright 2015, Igor Shaula +// Licensed under the MIT License <LICENSE or +// http://opensource.org/licenses/MIT>. This file +// may not be copied, modified, or distributed +// except according to those terms. + +//! Traits for loading/saving Registry values +use std::slice; +use std::io; +use std::ffi::{OsStr,OsString}; +use std::os::windows::ffi::{OsStrExt,OsStringExt}; +use super::winapi::shared::winerror; +use super::{RegValue}; +use super::enums::*; +use super::{to_utf16,v16_to_v8}; + +/// A trait for types that can be loaded from registry values. +/// +/// **NOTE:** Uses `from_utf16_lossy` when converting to `String`. +/// +/// **NOTE:** When converting to `String`, trailing `NULL` characters are trimmed +/// and line separating `NULL` characters in `REG_MULTI_SZ` are replaced by `\n`. +/// When converting to `OsString`, all `NULL` characters are left as is. +pub trait FromRegValue : Sized { + fn from_reg_value(val: &RegValue) -> io::Result<Self>; +} + +impl FromRegValue for String { + fn from_reg_value(val: &RegValue) -> io::Result<String> { + match val.vtype { + REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => { + let words = unsafe { + slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2) + }; + let mut s = String::from_utf16_lossy(words); + while s.ends_with('\u{0}') {s.pop();} + if val.vtype == REG_MULTI_SZ { + return Ok(s.replace("\u{0}", "\n")) + } + Ok(s) + }, + _ => werr!(winerror::ERROR_BAD_FILE_TYPE) + } + } +} + +impl FromRegValue for OsString { + fn from_reg_value(val: &RegValue) -> io::Result<OsString> { + match val.vtype { + REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => { + let words = unsafe { + slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2) + }; + let s = OsString::from_wide(words); + Ok(s) + }, + _ => werr!(winerror::ERROR_BAD_FILE_TYPE) + } + } +} + +impl FromRegValue for u32 { + fn from_reg_value(val: &RegValue) -> io::Result<u32> { + match val.vtype { + REG_DWORD => { + Ok(unsafe{ *(val.bytes.as_ptr() as *const u32) }) + }, + _ => werr!(winerror::ERROR_BAD_FILE_TYPE) + } + } +} + +impl FromRegValue for u64 { + fn from_reg_value(val: &RegValue) -> io::Result<u64> { + match val.vtype { + REG_QWORD => { + Ok(unsafe{ *(val.bytes.as_ptr() as *const u64) }) + }, + _ => werr!(winerror::ERROR_BAD_FILE_TYPE) + } + } +} + +/// A trait for types that can be written into registry values. +/// +/// **NOTE:** Adds trailing `NULL` character to `str` and `String` values +/// but **not** to `OsStr` values. +pub trait ToRegValue { + fn to_reg_value(&self) -> RegValue; +} + +impl ToRegValue for String { + fn to_reg_value(&self) -> RegValue { + RegValue{ + bytes: v16_to_v8(&to_utf16(self)), + vtype: REG_SZ + } + } +} + +impl<'a> ToRegValue for &'a str { + fn to_reg_value(&self) -> RegValue { + RegValue{ + bytes: v16_to_v8(&to_utf16(self)), + vtype: REG_SZ + } + } +} + +impl<'a> ToRegValue for &'a OsStr { + fn to_reg_value(&self) -> RegValue { + RegValue{ + bytes: v16_to_v8(&(self.encode_wide().collect::<Vec<_>>())), + vtype: REG_SZ + } + } +} + +impl ToRegValue for u32 { + fn to_reg_value(&self) -> RegValue { + let bytes: Vec<u8> = unsafe { + slice::from_raw_parts((self as *const u32) as *const u8, 4).to_vec() + }; + RegValue{ + bytes: bytes, + vtype: REG_DWORD + } + } +} + +impl ToRegValue for u64 { + fn to_reg_value(&self) -> RegValue { + let bytes: Vec<u8> = unsafe { + slice::from_raw_parts((self as *const u64) as *const u8, 8).to_vec() + }; + RegValue{ + bytes: bytes, + vtype: REG_QWORD + } + } +} |