diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /third_party/rust/winreg | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/winreg')
23 files changed, 4135 insertions, 0 deletions
diff --git a/third_party/rust/winreg/.cargo-checksum.json b/third_party/rust/winreg/.cargo-checksum.json new file mode 100644 index 0000000000..c0feadd1a0 --- /dev/null +++ b/third_party/rust/winreg/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"818308f83f82333925a5c79a33070576296820a9ca6f619b3be3b89918916f22","Cargo.toml":"7462003029eaddf0220e48731744d83b9e91b40a71c33ee13543b65995c4fb52","LICENSE":"ea021d8c6383c84d19c15ce90d3b1602cf448fdcc0bf3772c98e43c7bf1bf1d1","README.md":"37ad193ded0a105eecea15743a76249c6ec735b82a06b78312052648564eccb5","appveyor.yml":"92f6bab3b9609448c48983d6c418fb9061dbd851a9d804ccd923f7e34ab742f1","build.rs":"3d34e0c23f6c21e6da11fb0fc3aff792b8f30f3ecfbb6b4f536d0a70394e13e7","examples/basic_usage.rs":"e7dd3af233d3aca6a92676eab2ac55414af1477d4214e7c1c2cdbdf583c83fa1","examples/enum.rs":"9be94d7dde12fc49a3fbe5c7810a6a9ad28eaac9319271e1cabda121301e08f3","examples/installed_apps.rs":"595709b6453b1efb5c613e69795d6f6576d45762867de1ee7247f2c3e988edbb","examples/load_app_key.rs":"16275c44efa22519101c199903c53e0cdca5ad4ebdcb39939c5a285de2fa006c","examples/map_key_serialization.rs":"82b102a36c91f99e8eeb2d1cfde13131f087457de1c84db3af31097fdb4541b0","examples/serialization.rs":"7f5c0e7e50872c9655cf4e54b4efb54a8bc19113dc645279496b8e3d20109295","examples/transactions.rs":"8094aa5dcecedae3acef58ece3ed264a44e908c12cfd4a65ff8c90254dbc7225","src/decoder/mod.rs":"75318907ca32ff0aa3af9bf63be9d728a76d7a75f7d1fdb88bcb3a9df4abeb01","src/decoder/serialization_serde.rs":"3f7cc4249dbff8255ed40cd4a3b4416779ddbad4bd476032094259a8668d0cd2","src/encoder/mod.rs":"a5331802cbe374e0c511aa1335fa32d7bbb3aa972cb136df3fc585b3f3855cf5","src/encoder/serialization_serde.rs":"d63037eb017fd2ece03ed4a140baf2a75516a3ef0315bf10a3eb16d5455880d6","src/enums.rs":"d69acf7106672a1cf2b43091faa12de98d5cf400872e1fcbe6e1891ba5d185ae","src/lib.rs":"130872ae9e213c8705592f3e1eac3245029f93e2c22c8f2337e3ecea25152d49","src/transaction.rs":"adaeecac01dc5886b90ab4ef03889ddd136ce26206dfa8f8da7410f0db80a742","src/types.rs":"d0c3ebc2aaab2f0fac426e60701acefa435c91812540d52dba1532664a0301ee","tests/reg_key.rs":"8a59b554230545e15a3affa82fb6d9061b45ac15e777df6cc383b725b8f4ad93"},"package":"80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"}
\ No newline at end of file diff --git a/third_party/rust/winreg/Cargo.lock b/third_party/rust/winreg/Cargo.lock new file mode 100644 index 0000000000..e021632fd1 --- /dev/null +++ b/third_party/rust/winreg/Cargo.lock @@ -0,0 +1,350 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "libc" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg 1.0.1", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg 1.0.1", +] + +[[package]] +name = "proc-macro2" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" + +[[package]] +name = "serde_derive" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef" +dependencies = [ + "cfg-if", + "libc", + "rand 0.6.5", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winreg" +version = "0.10.1" +dependencies = [ + "chrono", + "rand 0.3.23", + "serde", + "serde_derive", + "tempfile", + "winapi", +] diff --git a/third_party/rust/winreg/Cargo.toml b/third_party/rust/winreg/Cargo.toml new file mode 100644 index 0000000000..adb2e88655 --- /dev/null +++ b/third_party/rust/winreg/Cargo.toml @@ -0,0 +1,75 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "winreg" +version = "0.10.1" +authors = ["Igor Shaula <gentoo90@gmail.com>"] +description = "Rust bindings to MS Windows Registry API" +documentation = "https://docs.rs/winreg" +readme = "README.md" +keywords = ["Windows", "WinSDK", "Registry"] +categories = ["api-bindings", "os::windows-apis"] +license = "MIT" +repository = "https://github.com/gentoo90/winreg-rs" +[package.metadata.docs.rs] +all-features = true +targets = ["x86_64-pc-windows-msvc", "i686-pc-windows-msvc"] + +[[example]] +name = "basic_usage" +required-features = ["chrono"] + +[[example]] +name = "enum" + +[[example]] +name = "load_app_key" + +[[example]] +name = "transactions" +required-features = ["transactions"] + +[[example]] +name = "serialization" +required-features = ["serialization-serde"] + +[[example]] +name = "map_key_serialization" +required-features = ["serialization-serde"] + +[[example]] +name = "installed_apps" +required-features = ["serialization-serde"] +[dependencies.chrono] +version = "0.4.6" +optional = true + +[dependencies.serde] +version = "1" +optional = true + +[dependencies.winapi] +version = "0.3.9" +features = ["impl-default", "impl-debug", "minwindef", "minwinbase", "timezoneapi", "winerror", "winnt", "winreg", "handleapi"] +[dev-dependencies.rand] +version = "0.3" + +[dev-dependencies.serde_derive] +version = "1" + +[dev-dependencies.tempfile] +version = "~3.0" + +[features] +serialization-serde = ["transactions", "serde"] +transactions = ["winapi/ktmw32"] diff --git a/third_party/rust/winreg/LICENSE b/third_party/rust/winreg/LICENSE new file mode 100644 index 0000000000..b9d358e3e7 --- /dev/null +++ b/third_party/rust/winreg/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015 Igor Shaula + +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: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +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. diff --git a/third_party/rust/winreg/README.md b/third_party/rust/winreg/README.md new file mode 100644 index 0000000000..2683a0619f --- /dev/null +++ b/third_party/rust/winreg/README.md @@ -0,0 +1,381 @@ +winreg +[![Winreg on Appveyor][appveyor-image]][appveyor] +[![Winreg on crates.io][cratesio-image]][cratesio] +[![Winreg on docs.rs][docsrs-image]][docsrs] +====== + +[appveyor-image]: https://ci.appveyor.com/api/projects/status/f3lwrt67ghrf5omd?svg=true +[appveyor]: https://ci.appveyor.com/project/gentoo90/winreg-rs +[cratesio-image]: https://img.shields.io/crates/v/winreg.svg +[cratesio]: https://crates.io/crates/winreg +[docsrs-image]: https://docs.rs/winreg/badge.svg +[docsrs]: https://docs.rs/winreg + +Rust bindings to MS Windows Registry API. Work in progress. + +Current features: +* Basic registry operations: + * open/create/delete keys + * load application hive from a file + * read and write values + * seamless conversion between `REG_*` types and rust primitives + * `String` and `OsString` <= `REG_SZ`, `REG_EXPAND_SZ` or `REG_MULTI_SZ` + * `String`, `&str`, `OsString`, `&OsStr` => `REG_SZ` + * `Vec<String>`, `Vec<OsString>` <= `REG_MULTI_SZ` + * `Vec<String>`, `Vec<&str>`, `Vec<OsString>`, `Vec<&OsStr>` => `REG_MULTI_SZ` + * `u32` <=> `REG_DWORD` + * `u64` <=> `REG_QWORD` +* Iteration through key names and through values +* Transactions +* Transacted serialization of rust types into/from registry (only primitives, structures and maps for now) + +## Usage + +### Basic usage + +```toml +# Cargo.toml +[dependencies] +winreg = "0.10" +``` + +```rust +extern crate winreg; +use std::io; +use std::path::Path; +use winreg::enums::*; +use winreg::RegKey; + +fn main() -> io::Result<()> { + println!("Reading some system info..."); + let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion")?; + let pf: String = cur_ver.get_value("ProgramFilesDir")?; + let dp: String = cur_ver.get_value("DevicePath")?; + println!("ProgramFiles = {}\nDevicePath = {}", pf, dp); + let info = cur_ver.query_info()?; + println!("info = {:?}", info); + let mt = info.get_last_write_time_system(); + println!( + "last_write_time as winapi::um::minwinbase::SYSTEMTIME = {}-{:02}-{:02} {:02}:{:02}:{:02}", + mt.wYear, mt.wMonth, mt.wDay, mt.wHour, mt.wMinute, mt.wSecond + ); + + // enable `chrono` feature on `winreg` to make this work + // println!( + // "last_write_time as chrono::NaiveDateTime = {}", + // info.get_last_write_time_chrono() + // ); + + println!("And now lets write something..."); + let hkcu = RegKey::predef(HKEY_CURRENT_USER); + let path = Path::new("Software").join("WinregRsExample1"); + let (key, disp) = hkcu.create_subkey(&path)?; + + match disp { + REG_CREATED_NEW_KEY => println!("A new key has been created"), + REG_OPENED_EXISTING_KEY => println!("An existing key has been opened"), + } + + key.set_value("TestSZ", &"written by Rust")?; + let sz_val: String = key.get_value("TestSZ")?; + key.delete_value("TestSZ")?; + println!("TestSZ = {}", sz_val); + + key.set_value("TestMultiSZ", &vec!["written", "by", "Rust"])?; + let multi_sz_val: Vec<String> = key.get_value("TestMultiSZ")?; + key.delete_value("TestMultiSZ")?; + println!("TestMultiSZ = {:?}", multi_sz_val); + + key.set_value("TestDWORD", &1234567890u32)?; + let dword_val: u32 = key.get_value("TestDWORD")?; + println!("TestDWORD = {}", dword_val); + + key.set_value("TestQWORD", &1234567891011121314u64)?; + let qword_val: u64 = key.get_value("TestQWORD")?; + println!("TestQWORD = {}", qword_val); + + key.create_subkey("sub\\key")?; + hkcu.delete_subkey_all(&path)?; + + println!("Trying to open nonexistent key..."); + 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), + }); + Ok(()) +} +``` + +### Iterators + +```rust +extern crate winreg; +use std::io; +use winreg::RegKey; +use winreg::enums::*; + +fn main() -> io::Result<()> { + 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")?; + for (name, value) in system.enum_values().map(|x| x.unwrap()) { + println!("{} = {:?}", name, value); + } + + Ok(()) +} +``` + +### Transactions + +```toml +# Cargo.toml +[dependencies] +winreg = { version = "0.10", features = ["transactions"] } +``` + +```rust +extern crate winreg; +use std::io; +use winreg::RegKey; +use winreg::enums::*; +use winreg::transaction::Transaction; + +fn main() -> io::Result<()> { + let t = Transaction::new()?; + let hkcu = RegKey::predef(HKEY_CURRENT_USER); + let (key, _disp) = hkcu.create_subkey_transacted("Software\\RustTransaction", &t)?; + key.set_value("TestQWORD", &1234567891011121314u64)?; + key.set_value("TestDWORD", &1234567890u32)?; + + println!("Commit transaction? [y/N]:"); + let mut input = String::new(); + io::stdin().read_line(&mut input)?; + input = input.trim_right().to_owned(); + if input == "y" || input == "Y" { + t.commit()?; + println!("Transaction committed."); + } + else { + // this is optional, if transaction wasn't committed, + // it will be rolled back on disposal + t.rollback()?; + + println!("Transaction wasn't committed, it will be rolled back."); + } + + Ok(()) +} +``` + +### Serialization + +```toml +# Cargo.toml +[dependencies] +winreg = { version = "0.10", features = ["serialization-serde"] } +serde = "1" +serde_derive = "1" +``` + +```rust +#[macro_use] +extern crate serde_derive; +extern crate winreg; +use std::collections::HashMap; +use std::error::Error; +use winreg::enums::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Coords { + x: u32, + y: u32, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Size { + w: u32, + h: u32, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Rectangle { + coords: Coords, + size: Size, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Test { + t_bool: bool, + t_u8: u8, + t_u16: u16, + t_u32: u32, + t_u64: u64, + t_usize: usize, + t_struct: Rectangle, + t_map: HashMap<String, u32>, + t_string: String, + #[serde(rename = "")] // empty name becomes the (Default) value in the registry + t_char: char, + t_i8: i8, + t_i16: i16, + t_i32: i32, + t_i64: i64, + t_isize: isize, + t_f64: f64, + t_f32: f32, +} + +fn main() -> Result<(), Box<dyn Error>> { + let hkcu = winreg::RegKey::predef(HKEY_CURRENT_USER); + let (key, _disp) = hkcu.create_subkey("Software\\RustEncode")?; + + let mut map = HashMap::new(); + map.insert("".to_owned(), 0); // empty name becomes the (Default) value in the registry + map.insert("v1".to_owned(), 1); + map.insert("v2".to_owned(), 2); + map.insert("v3".to_owned(), 3); + + let v1 = Test { + t_bool: false, + t_u8: 127, + t_u16: 32768, + t_u32: 123_456_789, + t_u64: 123_456_789_101_112, + t_usize: 1_234_567_891, + t_struct: Rectangle { + coords: Coords { x: 55, y: 77 }, + size: Size { w: 500, h: 300 }, + }, + t_map: map, + t_string: "test 123!".to_owned(), + t_char: 'a', + t_i8: -123, + t_i16: -2049, + t_i32: 20100, + t_i64: -12_345_678_910, + t_isize: -1_234_567_890, + t_f64: -0.01, + t_f32: 3.15, + }; + + key.encode(&v1)?; + + let v2: Test = key.decode()?; + println!("Decoded {:?}", v2); + + println!("Equal to encoded: {:?}", v1 == v2); + Ok(()) +} +``` + +## Changelog + +### 0.10.1 + +* Bump minimal required version of `winapi` to `0.3.9` (required for `load_app_key`) +* Reexport `REG_PROCESS_APPKEY` and use it in the `load_app_key` example + +### 0.10.0 + +* Add `RegKey::load_app_key()` and `RegKey::load_app_key_with_flags()` ([#30](https://github.com/gentoo90/winreg-rs/issues/30)) +* Update dev dependency `rand` to `0.8` +* Add Github actions +* Fix some clippy warnings + +### 0.9.0 + +* Breaking change: `OsStr` and `OsString` registry values are not `NULL`-terminated any more ([#34](https://github.com/gentoo90/winreg-rs/issues/34), [#42](https://github.com/gentoo90/winreg-rs/issues/42)) +* Refactoring: use macros for `ToRegValue` impls and tests for string values +* Fix `bare_trait_objects` warning in the doctests +* Add `impl ToRegValue for OsString` +* Add conversion between `REG_MULTI_SZ` and vectors of strings ([#16](https://github.com/gentoo90/winreg-rs/issues/16)) +* Fix: set minimal `winapi` version to 0.3.7 (earlier versions don't have `impl-default` and `impl-debug` features which we use) +* Appveyor now checks the crate against `rust-1.31.1` too + +### 0.8.0 + +* Implement serialization of `char` and maps +* Implement `std::fmt::Display` for `RegValue` +* Make `RegKey::{predef,raw_handle,enum_keys,enum_values}` functions `const` +* Give a better error message when compiling on platforms other than Windows ([#38](https://github.com/gentoo90/winreg-rs/pull/38)) +* Tests are moved from `src/lib.rs` to `tests/reg_key.rs` + +### 0.7.0 + +* Breaking change: remove deprecated `Error::description` ([#28](https://github.com/gentoo90/winreg-rs/pull/28)) +* Optimize `Iterator::nth()` for the `Enum*` iterators ([#29](https://github.com/gentoo90/winreg-rs/pull/29)) + +### 0.6.2 + +* Add `RegKey::delete_subkey_with_flags()` ([#27](https://github.com/gentoo90/winreg-rs/pull/27)) + +### 0.6.1 + +* Add `last_write_time` field to `RegKeyMetadata` (returned by `RegKey::query_info()`) ([#25](https://github.com/gentoo90/winreg-rs/pull/25)). +* Add `get_last_write_time_system()` and `get_last_write_time_chrono()` (under `chrono` feature) methods to `RegKeyMetadata`. + +### 0.6.0 + +* Breaking change: `create_subkey`, `create_subkey_with_flags`, `create_subkey_transacted` and +`create_subkey_transacted_with_flags` now return a tuple which contains the subkey and its disposition +which can be `REG_CREATED_NEW_KEY` or `REG_OPENED_EXISTING_KEY` ([#21](https://github.com/gentoo90/winreg-rs/issues/21)). +* Examples fixed to not use `unwrap` according to [Rust API guidelines](https://rust-lang-nursery.github.io/api-guidelines/documentation.html#examples-use--not-try-not-unwrap-c-question-mark). + +### 0.5.1 + +* Reexport `HKEY` ([#15](https://github.com/gentoo90/winreg-rs/issues/15)). +* Add `raw_handle` method ([#18](https://github.com/gentoo90/winreg-rs/pull/18)). + +### 0.5.0 + +* Breaking change: `open_subkey` now opens a key with readonly permissions. +Use `create_subkey` or `open_subkey_with_flags` to open with read-write permissins. +* Breaking change: features `transactions` and `serialization-serde` are now disabled by default. +* Breaking change: serialization now uses `serde` instead of `rustc-serialize`. +* `winapi` updated to `0.3`. +* Documentation fixes ([#14](https://github.com/gentoo90/winreg-rs/pull/14)) + +### 0.4.0 + +* Make transactions and serialization otional features +* Update dependensies + minor fixes ([#12](https://github.com/gentoo90/winreg-rs/pull/12)) + +### 0.3.5 + +* Implement `FromRegValue` for `OsString` and `ToRegValue` for `OsStr` ([#8](https://github.com/gentoo90/winreg-rs/issues/8)) +* Minor fixes + +### 0.3.4 + +* Add `copy_tree` method to `RegKey` +* Now checked with [rust-clippy](https://github.com/Manishearth/rust-clippy) + * no more `unwrap`s + * replaced `to_string` with `to_owned` +* Fix: reading strings longer than 2048 characters ([#6](https://github.com/gentoo90/winreg-rs/pull/6)) + +### 0.3.3 + +* Fix: now able to read values longer than 2048 bytes ([#3](https://github.com/gentoo90/winreg-rs/pull/3)) + +### 0.3.2 + +* Fix: `FromRegValue` trait now requires `Sized` (fixes build with rust 1.4) + +### 0.3.1 + +* Fix: bump `winapi` version to fix build + +### 0.3.0 + +* Add transactions support and make serialization transacted +* Breaking change: use `std::io::{Error,Result}` instead of own `RegError` and `RegResult` diff --git a/third_party/rust/winreg/appveyor.yml b/third_party/rust/winreg/appveyor.yml new file mode 100644 index 0000000000..b690b6a0cb --- /dev/null +++ b/third_party/rust/winreg/appveyor.yml @@ -0,0 +1,37 @@ +version: 0.10.{build} +pull_requests: + do_not_increment_build_number: true + +branches: + except: + - github-actions + +os: Visual Studio 2015 + +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + CHANNEL: 1.31.1 + - TARGET: x86_64-pc-windows-gnu + CHANNEL: stable + - TARGET: x86_64-pc-windows-msvc + CHANNEL: stable + - TARGET: i686-pc-windows-gnu + CHANNEL: stable + - TARGET: i686-pc-windows-msvc + CHANNEL: stable + +install: + - curl -sSf -o rustup-init.exe https://win.rustup.rs + - rustup-init.exe --profile=minimal --component rustfmt,clippy --default-host %TARGET% --default-toolchain %CHANNEL% -y + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - rustc -Vv + - cargo -V + +build: false + +test_script: + - if not "%CHANNEL%"=="1.31.1" cargo fmt --all -- --check + - if not "%CHANNEL%"=="1.31.1" cargo clippy --all-features --all-targets + - cargo test --release --no-default-features + - cargo test --release --all-features diff --git a/third_party/rust/winreg/build.rs b/third_party/rust/winreg/build.rs new file mode 100644 index 0000000000..7acab76640 --- /dev/null +++ b/third_party/rust/winreg/build.rs @@ -0,0 +1,11 @@ +fn main() { + if std::env::var("CARGO_CFG_WINDOWS").is_err() { + eprintln!("error: winreg is only supported on Windows platforms"); + eprintln!( + "help: if your application is multi-platform, use \ + `[target.'cfg(windows)'.dependencies] winreg = \"...\"`" + ); + eprintln!("help: if your application is only supported on Windows, use `--target x86_64-pc-windows-gnu` or some other windows platform"); + std::process::exit(1); + } +} diff --git a/third_party/rust/winreg/examples/basic_usage.rs b/third_party/rust/winreg/examples/basic_usage.rs new file mode 100644 index 0000000000..6422e9eeb2 --- /dev/null +++ b/third_party/rust/winreg/examples/basic_usage.rs @@ -0,0 +1,69 @@ +// 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. +extern crate winreg; +use std::io; +use std::path::Path; +use winreg::enums::*; +use winreg::RegKey; + +fn main() -> io::Result<()> { + println!("Reading some system info..."); + let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion")?; + let pf: String = cur_ver.get_value("ProgramFilesDir")?; + let dp: String = cur_ver.get_value("DevicePath")?; + println!("ProgramFiles = {}\nDevicePath = {}", pf, dp); + let info = cur_ver.query_info()?; + println!("info = {:?}", info); + let mt = info.get_last_write_time_system(); + println!( + "last_write_time as winapi::um::minwinbase::SYSTEMTIME = {}-{:02}-{:02} {:02}:{:02}:{:02}", + mt.wYear, mt.wMonth, mt.wDay, mt.wHour, mt.wMinute, mt.wSecond + ); + println!( + "last_write_time as chrono::NaiveDateTime = {}", + info.get_last_write_time_chrono() + ); + + println!("And now lets write something..."); + let hkcu = RegKey::predef(HKEY_CURRENT_USER); + let path = Path::new("Software").join("WinregRsExample1"); + let (key, disp) = hkcu.create_subkey(&path)?; + + match disp { + REG_CREATED_NEW_KEY => println!("A new key has been created"), + REG_OPENED_EXISTING_KEY => println!("An existing key has been opened"), + } + + key.set_value("TestSZ", &"written by Rust")?; + let sz_val: String = key.get_value("TestSZ")?; + key.delete_value("TestSZ")?; + println!("TestSZ = {}", sz_val); + + key.set_value("TestMultiSZ", &vec!["written", "by", "Rust"])?; + let multi_sz_val: Vec<String> = key.get_value("TestMultiSZ")?; + key.delete_value("TestMultiSZ")?; + println!("TestMultiSZ = {:?}", multi_sz_val); + + key.set_value("TestDWORD", &1_234_567_890u32)?; + let dword_val: u32 = key.get_value("TestDWORD")?; + println!("TestDWORD = {}", dword_val); + + key.set_value("TestQWORD", &1_234_567_891_011_121_314u64)?; + let qword_val: u64 = key.get_value("TestQWORD")?; + println!("TestQWORD = {}", qword_val); + + key.create_subkey("sub\\key")?; + hkcu.delete_subkey_all(&path)?; + + println!("Trying to open nonexistent key..."); + 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), + }); + Ok(()) +} diff --git a/third_party/rust/winreg/examples/enum.rs b/third_party/rust/winreg/examples/enum.rs new file mode 100644 index 0000000000..dd1a78d870 --- /dev/null +++ b/third_party/rust/winreg/examples/enum.rs @@ -0,0 +1,27 @@ +// 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. +extern crate winreg; +use std::io; +use winreg::enums::*; +use winreg::RegKey; + +fn main() -> io::Result<()> { + 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")?; + for (name, value) in system.enum_values().map(|x| x.unwrap()) { + println!("{} = {:?}", name, value); + } + + Ok(()) +} diff --git a/third_party/rust/winreg/examples/installed_apps.rs b/third_party/rust/winreg/examples/installed_apps.rs new file mode 100644 index 0000000000..a7546847db --- /dev/null +++ b/third_party/rust/winreg/examples/installed_apps.rs @@ -0,0 +1,50 @@ +// 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. +#[macro_use] +extern crate serde_derive; +extern crate winreg; +use std::collections::HashMap; +use std::fmt; +use winreg::enums::*; + +#[allow(non_snake_case)] +#[derive(Debug, Serialize, Deserialize)] +struct InstalledApp { + DisplayName: Option<String>, + DisplayVersion: Option<String>, + UninstallString: Option<String>, +} + +macro_rules! str_from_opt { + ($s:expr) => { + $s.as_ref().map(|x| &**x).unwrap_or("") + }; +} + +impl fmt::Display for InstalledApp { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{}-{}", + str_from_opt!(self.DisplayName), + str_from_opt!(self.DisplayVersion) + ) + } +} + +fn main() { + let hklm = winreg::RegKey::predef(HKEY_LOCAL_MACHINE); + let uninstall_key = hklm + .open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall") + .expect("key is missing"); + + let apps: HashMap<String, InstalledApp> = + uninstall_key.decode().expect("deserialization failed"); + + for v in apps.values() { + println!("{}", v); + } +} diff --git a/third_party/rust/winreg/examples/load_app_key.rs b/third_party/rust/winreg/examples/load_app_key.rs new file mode 100644 index 0000000000..2340c82b59 --- /dev/null +++ b/third_party/rust/winreg/examples/load_app_key.rs @@ -0,0 +1,26 @@ +// Copyright 2021, 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. +extern crate winreg; +use std::io; +use winreg::enums::*; +use winreg::RegKey; + +fn main() -> io::Result<()> { + { + // put this in a block so app_key_1 gets out of scope and doesn't prevent us + // from loading the key again later + let app_key_1 = RegKey::load_app_key("myhive.dat", true)?; + app_key_1.set_value("answer", &42u32)?; + } + let answer: u32 = { + // NOTE: on Windows 7 this fails with ERROR_ALREADY_EXISTS + let app_key_2 = + RegKey::load_app_key_with_flags("myhive.dat", KEY_READ, REG_PROCESS_APPKEY)?; + app_key_2.get_value("answer")? + }; + println!("The Answer is {}", answer); + Ok(()) +} diff --git a/third_party/rust/winreg/examples/map_key_serialization.rs b/third_party/rust/winreg/examples/map_key_serialization.rs new file mode 100644 index 0000000000..c0be704913 --- /dev/null +++ b/third_party/rust/winreg/examples/map_key_serialization.rs @@ -0,0 +1,57 @@ +// Copyright 2020, 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. +#[macro_use] +extern crate serde_derive; +extern crate winreg; +use std::collections::HashMap; +use std::error::Error; +use winreg::enums::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Coords { + x: u32, + y: u32, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Size { + w: u32, + h: u32, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Rectangle { + coords: Coords, + size: Size, +} + +fn main() -> Result<(), Box<dyn Error>> { + let hkcu = winreg::RegKey::predef(HKEY_CURRENT_USER); + let (key, _disp) = hkcu.create_subkey("Software\\RustEncodeMapKey")?; + let mut v1 = HashMap::new(); + v1.insert( + "first".to_owned(), + Rectangle { + coords: Coords { x: 55, y: 77 }, + size: Size { w: 500, h: 300 }, + }, + ); + v1.insert( + "second".to_owned(), + Rectangle { + coords: Coords { x: 11, y: 22 }, + size: Size { w: 1000, h: 600 }, + }, + ); + + key.encode(&v1)?; + + let v2: HashMap<String, Rectangle> = key.decode()?; + println!("Decoded {:?}", v2); + + println!("Equal to encoded: {:?}", v1 == v2); + Ok(()) +} diff --git a/third_party/rust/winreg/examples/serialization.rs b/third_party/rust/winreg/examples/serialization.rs new file mode 100644 index 0000000000..462813291a --- /dev/null +++ b/third_party/rust/winreg/examples/serialization.rs @@ -0,0 +1,93 @@ +// 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. +#[macro_use] +extern crate serde_derive; +extern crate winreg; +use std::collections::HashMap; +use std::error::Error; +use winreg::enums::*; + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Coords { + x: u32, + y: u32, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Size { + w: u32, + h: u32, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Rectangle { + coords: Coords, + size: Size, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +struct Test { + t_bool: bool, + t_u8: u8, + t_u16: u16, + t_u32: u32, + t_u64: u64, + t_usize: usize, + t_struct: Rectangle, + t_map: HashMap<String, u32>, + t_string: String, + #[serde(rename = "")] // empty name becomes the (Default) value in the registry + t_char: char, + t_i8: i8, + t_i16: i16, + t_i32: i32, + t_i64: i64, + t_isize: isize, + t_f64: f64, + t_f32: f32, +} + +fn main() -> Result<(), Box<dyn Error>> { + let hkcu = winreg::RegKey::predef(HKEY_CURRENT_USER); + let (key, _disp) = hkcu.create_subkey("Software\\RustEncode")?; + + let mut map = HashMap::new(); + map.insert("".to_owned(), 0); // empty name becomes the (Default) value in the registry + map.insert("v1".to_owned(), 1); + map.insert("v2".to_owned(), 2); + map.insert("v3".to_owned(), 3); + + let v1 = Test { + t_bool: false, + t_u8: 127, + t_u16: 32768, + t_u32: 123_456_789, + t_u64: 123_456_789_101_112, + t_usize: 1_234_567_891, + t_struct: Rectangle { + coords: Coords { x: 55, y: 77 }, + size: Size { w: 500, h: 300 }, + }, + t_map: map, + t_string: "test 123!".to_owned(), + t_char: 'a', + t_i8: -123, + t_i16: -2049, + t_i32: 20100, + t_i64: -12_345_678_910, + t_isize: -1_234_567_890, + t_f64: -0.01, + t_f32: 3.15, + }; + + key.encode(&v1)?; + + let v2: Test = key.decode()?; + println!("Decoded {:?}", v2); + + println!("Equal to encoded: {:?}", v1 == v2); + Ok(()) +} diff --git a/third_party/rust/winreg/examples/transactions.rs b/third_party/rust/winreg/examples/transactions.rs new file mode 100644 index 0000000000..4cc91b7c9f --- /dev/null +++ b/third_party/rust/winreg/examples/transactions.rs @@ -0,0 +1,35 @@ +// 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. +extern crate winreg; +use std::io; +use winreg::enums::*; +use winreg::transaction::Transaction; +use winreg::RegKey; + +fn main() -> io::Result<()> { + let t = Transaction::new()?; + let hkcu = RegKey::predef(HKEY_CURRENT_USER); + let (key, _disp) = hkcu.create_subkey_transacted("Software\\RustTransaction", &t)?; + key.set_value("TestQWORD", &1_234_567_891_011_121_314u64)?; + key.set_value("TestDWORD", &1_234_567_890u32)?; + + println!("Commit transaction? [y/N]:"); + let mut input = String::new(); + io::stdin().read_line(&mut input)?; + input = input.trim_end().to_owned(); + if input == "y" || input == "Y" { + t.commit()?; + println!("Transaction committed."); + } else { + // this is optional, if transaction wasn't committed, + // it will be rolled back on disposal + t.rollback()?; + + println!("Transaction wasn't committed, it will be rolled back."); + } + + Ok(()) +} 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..82493b846d --- /dev/null +++ b/third_party/rust/winreg/src/decoder/mod.rs @@ -0,0 +1,101 @@ +// 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 super::enums::*; +use super::RegKey; +use std::error::Error; +use std::fmt; +use std::io; +use winapi::shared::minwindef::DWORD; + +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 {} + +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, + 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..1287540448 --- /dev/null +++ b/third_party/rust/winreg/src/decoder/serialization_serde.rs @@ -0,0 +1,331 @@ +// 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 super::super::FromRegValue; +use super::{ + DecodeResult, Decoder, DecoderEnumerationState, DecoderError, DecoderReadingState, DECODER_SAM, +}; +use serde::de::*; +use std::fmt; +use std::mem; + +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>, + { + self.deserialize_string(visitor) + } + + 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..f552dc05df --- /dev/null +++ b/third_party/rust/winreg/src/encoder/mod.rs @@ -0,0 +1,97 @@ +// 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 self::EncoderState::*; +use super::enums::*; +use super::transaction::Transaction; +use super::RegKey; +use std::error::Error; +use std::fmt; +use std::io; +use winapi::shared::minwindef::DWORD; + +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, + KeyMustBeAString, +} + +impl fmt::Display for EncoderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +impl Error for EncoderError {} + +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 = 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, + 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..f764cce6ec --- /dev/null +++ b/third_party/rust/winreg/src/encoder/serialization_serde.rs @@ -0,0 +1,513 @@ +// 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 super::EncoderState::*; +use super::{EncodeResult, Encoder, EncoderError, ENCODER_SAM}; +use serde::ser::*; +use std::fmt; +use std::mem; + +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 = StructMapEncoder<'a>; + type SerializeStruct = StructMapEncoder<'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> { + let mut s = String::new(); + s.push(value); + emit_value!(self, s) + } + + 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> { + match mem::replace(&mut self.state, Start) { + // --- + Start => { + // root structure + Ok(StructMapEncoder { + 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, _disp)) => { + self.keys.push(subkey); + Ok(StructMapEncoder { + enc: self, + is_root: true, + }) + } + Err(err) => Err(EncoderError::IoError(err)), + } + } + } + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> EncodeResult<Self::SerializeStruct> { + self.serialize_map(Some(_len)) + } + + 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") + } +} + +struct MapKeySerializer; + +impl serde::Serializer for MapKeySerializer { + type Ok = String; + type Error = EncoderError; + + type SerializeSeq = Impossible<String, EncoderError>; + type SerializeTuple = Impossible<String, EncoderError>; + type SerializeTupleStruct = Impossible<String, EncoderError>; + type SerializeTupleVariant = Impossible<String, EncoderError>; + type SerializeMap = Impossible<String, EncoderError>; + type SerializeStruct = Impossible<String, EncoderError>; + type SerializeStructVariant = Impossible<String, EncoderError>; + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> EncodeResult<Self::Ok> { + Ok(variant.to_owned()) + } + + #[inline] + fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> EncodeResult<Self::Ok> + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_bool(self, _value: bool) -> EncodeResult<Self::Ok> { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_i8(self, value: i8) -> EncodeResult<Self::Ok> { + Ok(value.to_string()) + } + + fn serialize_i16(self, value: i16) -> EncodeResult<Self::Ok> { + Ok(value.to_string()) + } + + fn serialize_i32(self, value: i32) -> EncodeResult<Self::Ok> { + Ok(value.to_string()) + } + + fn serialize_i64(self, value: i64) -> EncodeResult<Self::Ok> { + Ok(value.to_string()) + } + + fn serialize_u8(self, value: u8) -> EncodeResult<Self::Ok> { + Ok(value.to_string()) + } + + fn serialize_u16(self, value: u16) -> EncodeResult<Self::Ok> { + Ok(value.to_string()) + } + + fn serialize_u32(self, value: u32) -> EncodeResult<Self::Ok> { + Ok(value.to_string()) + } + + fn serialize_u64(self, value: u64) -> EncodeResult<Self::Ok> { + Ok(value.to_string()) + } + + fn serialize_f32(self, _value: f32) -> EncodeResult<Self::Ok> { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_f64(self, _value: f64) -> EncodeResult<Self::Ok> { + Err(EncoderError::KeyMustBeAString) + } + + #[inline] + fn serialize_char(self, value: char) -> EncodeResult<Self::Ok> { + Ok({ + let mut s = String::new(); + s.push(value); + s + }) + } + + #[inline] + fn serialize_str(self, value: &str) -> EncodeResult<Self::Ok> { + Ok(value.to_owned()) + } + + fn serialize_bytes(self, _value: &[u8]) -> EncodeResult<Self::Ok> { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_unit(self) -> EncodeResult<Self::Ok> { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_unit_struct(self, _name: &'static str) -> EncodeResult<Self::Ok> { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_newtype_variant<T>( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> EncodeResult<Self::Ok> + where + T: ?Sized + Serialize, + { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_none(self) -> EncodeResult<Self::Ok> { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_some<T>(self, _value: &T) -> EncodeResult<Self::Ok> + where + T: ?Sized + Serialize, + { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_seq(self, _len: Option<usize>) -> EncodeResult<Self::SerializeSeq> { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_tuple(self, _len: usize) -> EncodeResult<Self::SerializeTuple> { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> EncodeResult<Self::SerializeTupleStruct> { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> EncodeResult<Self::SerializeTupleVariant> { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_map(self, _len: Option<usize>) -> EncodeResult<Self::SerializeMap> { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> EncodeResult<Self::SerializeStruct> { + Err(EncoderError::KeyMustBeAString) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> EncodeResult<Self::SerializeStructVariant> { + Err(EncoderError::KeyMustBeAString) + } + + fn collect_str<T: ?Sized>(self, value: &T) -> EncodeResult<String> + where + T: fmt::Display, + { + Ok(value.to_string()) + } +} + +pub struct StructMapEncoder<'a> { + enc: &'a mut Encoder, + is_root: bool, +} + +impl<'a> SerializeStruct for StructMapEncoder<'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(()) + } +} + +impl<'a> SerializeMap for StructMapEncoder<'a> { + type Ok = (); + type Error = EncoderError; + + fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> EncodeResult<Self::Ok> { + self.enc.state = NextKey(key.serialize(MapKeySerializer)?); + Ok(()) + } + + fn serialize_value<T: ?Sized + Serialize>(&mut self, value: &T) -> EncodeResult<Self::Ok> { + 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..b537b287c2 --- /dev/null +++ b/third_party/rust/winreg/src/enums.rs @@ -0,0 +1,51 @@ +// 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::winnt::{ + KEY_ALL_ACCESS, KEY_CREATE_LINK, KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUB_KEYS, KEY_EXECUTE, + KEY_NOTIFY, KEY_QUERY_VALUE, KEY_READ, KEY_SET_VALUE, KEY_WOW64_32KEY, KEY_WOW64_64KEY, + KEY_WOW64_RES, KEY_WRITE, +}; +pub use winapi::um::winreg::{ + HKEY_CLASSES_ROOT, HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER, HKEY_CURRENT_USER_LOCAL_SETTINGS, + HKEY_DYN_DATA, HKEY_LOCAL_MACHINE, HKEY_PERFORMANCE_DATA, HKEY_PERFORMANCE_NLSTEXT, + HKEY_PERFORMANCE_TEXT, HKEY_USERS, REG_PROCESS_APPKEY, +}; + +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::*; + +winapi_enum!(RegDisposition, "Enumeration of possible disposition values" => [ +REG_CREATED_NEW_KEY, +REG_OPENED_EXISTING_KEY +]); +pub use self::RegDisposition::*; diff --git a/third_party/rust/winreg/src/lib.rs b/third_party/rust/winreg/src/lib.rs new file mode 100644 index 0000000000..784976c5c8 --- /dev/null +++ b/third_party/rust/winreg/src/lib.rs @@ -0,0 +1,1143 @@ +// 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.10" +//!``` +//! +//!```no_run +//!extern crate winreg; +//!use std::io; +//!use std::path::Path; +//!use winreg::enums::*; +//!use winreg::RegKey; +//! +//!fn main() -> io::Result<()> { +//! println!("Reading some system info..."); +//! let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); +//! let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion")?; +//! let pf: String = cur_ver.get_value("ProgramFilesDir")?; +//! let dp: String = cur_ver.get_value("DevicePath")?; +//! println!("ProgramFiles = {}\nDevicePath = {}", pf, dp); +//! let info = cur_ver.query_info()?; +//! println!("info = {:?}", info); +//! let mt = info.get_last_write_time_system(); +//! println!( +//! "last_write_time as winapi::um::minwinbase::SYSTEMTIME = {}-{:02}-{:02} {:02}:{:02}:{:02}", +//! mt.wYear, mt.wMonth, mt.wDay, mt.wHour, mt.wMinute, mt.wSecond +//! ); +//! +//! // enable `chrono` feature on `winreg` to make this work +//! // println!( +//! // "last_write_time as chrono::NaiveDateTime = {}", +//! // info.get_last_write_time_chrono() +//! // ); +//! +//! println!("And now lets write something..."); +//! let hkcu = RegKey::predef(HKEY_CURRENT_USER); +//! let path = Path::new("Software").join("WinregRsExample1"); +//! let (key, disp) = hkcu.create_subkey(&path)?; +//! +//! match disp { +//! REG_CREATED_NEW_KEY => println!("A new key has been created"), +//! REG_OPENED_EXISTING_KEY => println!("An existing key has been opened"), +//! } +//! +//! key.set_value("TestSZ", &"written by Rust")?; +//! let sz_val: String = key.get_value("TestSZ")?; +//! key.delete_value("TestSZ")?; +//! println!("TestSZ = {}", sz_val); +//! +//! key.set_value("TestMultiSZ", &vec!["written", "by", "Rust"])?; +//! let multi_sz_val: Vec<String> = key.get_value("TestMultiSZ")?; +//! key.delete_value("TestMultiSZ")?; +//! println!("TestMultiSZ = {:?}", multi_sz_val); +//! +//! key.set_value("TestDWORD", &1234567890u32)?; +//! let dword_val: u32 = key.get_value("TestDWORD")?; +//! println!("TestDWORD = {}", dword_val); +//! +//! key.set_value("TestQWORD", &1234567891011121314u64)?; +//! let qword_val: u64 = key.get_value("TestQWORD")?; +//! println!("TestQWORD = {}", qword_val); +//! +//! key.create_subkey("sub\\key")?; +//! hkcu.delete_subkey_all(&path)?; +//! +//! println!("Trying to open nonexistent key..."); +//! 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), +//! }); +//! Ok(()) +//!} +//!``` +//! +//!### Iterators +//! +//!```no_run +//!extern crate winreg; +//!use std::io; +//!use winreg::RegKey; +//!use winreg::enums::*; +//! +//!fn main() -> io::Result<()> { +//! 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")?; +//! for (name, value) in system.enum_values().map(|x| x.unwrap()) { +//! println!("{} = {:?}", name, value); +//! } +//! +//! Ok(()) +//!} +//!``` +//! +#[cfg(feature = "chrono")] +extern crate chrono; +#[cfg(feature = "serialization-serde")] +extern crate serde; +extern crate winapi; +use enums::*; +use std::default::Default; +use std::ffi::OsStr; +use std::fmt; +use std::io; +use std::mem::transmute; +use std::os::windows::ffi::OsStrExt; +use std::ptr; +use std::slice; +#[cfg(feature = "transactions")] +use transaction::Transaction; +use types::{FromRegValue, ToRegValue}; +pub use winapi::shared::minwindef::HKEY; +use winapi::shared::minwindef::{BYTE, DWORD, FILETIME, LPBYTE}; +use winapi::shared::winerror; +use winapi::um::minwinbase::SYSTEMTIME; +use winapi::um::timezoneapi::FileTimeToSystemTime; +use winapi::um::winnt::{self, WCHAR}; +use winapi::um::winreg as winapi_reg; + +macro_rules! werr { + ($e:expr) => { + Err(io::Error::from_raw_os_error($e as i32)) + }; +} + +#[cfg(feature = "serialization-serde")] +mod decoder; +#[cfg(feature = "serialization-serde")] +mod encoder; +pub mod enums; +#[cfg(feature = "transactions")] +pub mod transaction; +pub mod types; + +/// 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 last_write_time: FILETIME, +} + +impl RegKeyMetadata { + /// Returns `last_write_time` field as `winapi::um::minwinbase::SYSTEMTIME` + pub fn get_last_write_time_system(&self) -> SYSTEMTIME { + let mut st: SYSTEMTIME = unsafe { ::std::mem::zeroed() }; + unsafe { + FileTimeToSystemTime(&self.last_write_time, &mut st); + } + st + } + + /// Returns `last_write_time` field as `chrono::NaiveDateTime`. + /// Part of `chrono` feature. + #[cfg(feature = "chrono")] + pub fn get_last_write_time_chrono(&self) -> chrono::NaiveDateTime { + let st = self.get_last_write_time_system(); + + chrono::NaiveDate::from_ymd(st.wYear.into(), st.wMonth.into(), st.wDay.into()).and_hms( + st.wHour.into(), + st.wMinute.into(), + st.wSecond.into(), + ) + } +} + +/// 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::Display 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, "{}", f_val) + } +} + +impl fmt::Debug for RegValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "RegValue({:?}: {})", self.vtype, self) + } +} + +/// 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 const fn predef(hkey: HKEY) -> RegKey { + RegKey { hkey } + } + + /// Load a registry hive from a file as an application hive. + /// If `lock` is set to `true`, then the hive cannot be loaded again until + /// it's unloaded (i.e. all keys from it go out of scope). + /// + /// # Examples + /// + /// ```no_run + /// # use std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// let handle = RegKey::load_app_key("C:\\myhive.dat", false)?; + /// # Ok(()) + /// # } + /// ``` + pub fn load_app_key<N: AsRef<OsStr>>(filename: N, lock: bool) -> io::Result<RegKey> { + let options = if lock { + winapi_reg::REG_PROCESS_APPKEY + } else { + 0 + }; + RegKey::load_app_key_with_flags(filename, enums::KEY_ALL_ACCESS, options) + } + + /// Load a registry hive from a file as an application hive with desired + /// permissions and options. If `options` is set to `REG_PROCESS_APPKEY`, + /// then the hive cannot be loaded again until it's unloaded (i.e. all keys + /// from it go out of scope). + /// # Examples + /// + /// ```no_run + /// # use std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// let handle = RegKey::load_app_key_with_flags("C:\\myhive.dat", KEY_READ, 0)?; + /// # Ok(()) + /// # } + /// ``` + pub fn load_app_key_with_flags<N: AsRef<OsStr>>( + filename: N, + perms: winapi_reg::REGSAM, + options: DWORD, + ) -> io::Result<RegKey> { + let c_filename = to_utf16(filename); + let mut new_hkey: HKEY = ptr::null_mut(); + match unsafe { + winapi_reg::RegLoadAppKeyW(c_filename.as_ptr(), &mut new_hkey, perms, options, 0) + as DWORD + } { + 0 => Ok(RegKey { hkey: new_hkey }), + err => werr!(err), + } + } + + /// Return inner winapi HKEY of a key: + /// + /// # Examples + /// + /// ```no_run + /// # use std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + /// let soft = hklm.open_subkey("SOFTWARE")?; + /// let handle = soft.raw_handle(); + /// # Ok(()) + /// # } + /// ``` + pub const 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 std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// let soft = RegKey::predef(HKEY_CURRENT_USER) + /// .open_subkey("Software")?; + /// # Ok(()) + /// # } + /// ``` + 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 std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + /// hklm.open_subkey_with_flags("SOFTWARE\\Microsoft", KEY_READ)?; + /// # Ok(()) + /// # } + /// ``` + 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. + /// If succeeds returns a tuple with the created subkey and its disposition, + /// which can be `REG_CREATED_NEW_KEY` or `REG_OPENED_EXISTING_KEY`. + /// 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 std::error::Error; + /// # use winreg::RegKey; + /// use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let (settings, disp) = hkcu.create_subkey("Software\\MyProduct\\Settings")?; + /// + /// match disp { + /// REG_CREATED_NEW_KEY => println!("A new key has been created"), + /// REG_OPENED_EXISTING_KEY => println!("An existing key has been opened") + /// } + /// # Ok(()) + /// # } + /// ``` + pub fn create_subkey<P: AsRef<OsStr>>(&self, path: P) -> io::Result<(RegKey, RegDisposition)> { + 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, RegDisposition)> { + let c_path = to_utf16(path); + let mut new_hkey: HKEY = ptr::null_mut(); + let mut disp_buf: 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_buf, + ) + } { + 0 => { + let disp: RegDisposition = unsafe { transmute(disp_buf as u8) }; + Ok((RegKey { hkey: new_hkey }, disp)) + } + 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, RegDisposition)> { + 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, RegDisposition)> { + let c_path = to_utf16(path); + let mut new_hkey: HKEY = ptr::null_mut(); + let mut disp_buf: 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_buf, + t.handle, + ptr::null_mut(), + ) as DWORD + } { + 0 => { + let disp: RegDisposition = unsafe { transmute(disp_buf as u8) }; + Ok((RegKey { hkey: new_hkey }, disp)) + } + 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 std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let src = hkcu.open_subkey_with_flags("Software\\MyProduct", KEY_READ)?; + /// let (dst, dst_disp) = hkcu.create_subkey("Software\\MyProduct\\Section2")?; + /// src.copy_tree("Section1", &dst)?; + /// # Ok(()) + /// # } + /// ``` + 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, + &mut info.last_write_time, + ) 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 const fn enum_keys(&self) -> EnumKeys { + EnumKeys { + key: self, + index: 0, + } + } + + /// Return an iterator over values. + /// + /// # Examples + /// + /// ```no_run + /// # use std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// let system = RegKey::predef(HKEY_LOCAL_MACHINE) + /// .open_subkey_with_flags("HARDWARE\\DESCRIPTION\\System", KEY_READ)?; + /// for (name, value) in system.enum_values().map(|x| x.unwrap()) { + /// println!("{} = {:?}", name, value); + /// } + /// # Ok(()) + /// # } + /// ``` + pub const 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 std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// RegKey::predef(HKEY_CURRENT_USER) + /// .delete_subkey(r"Software\MyProduct\History")?; + /// # Ok(()) + /// # } + /// ``` + pub fn delete_subkey<P: AsRef<OsStr>>(&self, path: P) -> io::Result<()> { + self.delete_subkey_with_flags(path, 0) + } + + /// Delete key from the desired platform-specific view of the registry. + /// Key names are not case sensitive. + /// + /// # Examples + /// ```no_run + /// # use std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// // delete the key from the 32-bit registry view + /// RegKey::predef(HKEY_LOCAL_MACHINE) + /// .delete_subkey_with_flags(r"Software\MyProduct\History", KEY_WOW64_32KEY)?; + /// # Ok(()) + /// # } + /// ``` + pub fn delete_subkey_with_flags<P: AsRef<OsStr>>( + &self, + path: P, + perms: winapi_reg::REGSAM, + ) -> io::Result<()> { + let c_path = to_utf16(path); + match unsafe { + winapi_reg::RegDeleteKeyExW( + self.hkey, + c_path.as_ptr(), // This parameter cannot be NULL. + perms, + 0, + ) + } { + 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<()> { + self.delete_subkey_transacted_with_flags(path, t, 0) + } + + /// Part of `transactions` feature. + #[cfg(feature = "transactions")] + pub fn delete_subkey_transacted_with_flags<P: AsRef<OsStr>>( + &self, + path: P, + t: &Transaction, + perms: winapi_reg::REGSAM, + ) -> io::Result<()> { + let c_path = to_utf16(path); + match unsafe { + winapi_reg::RegDeleteKeyTransactedW( + self.hkey, + c_path.as_ptr(), // This parameter cannot be NULL. + perms, + 0, + t.handle, + ptr::null_mut(), + ) + } { + 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 std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// RegKey::predef(HKEY_CURRENT_USER) + /// .delete_subkey_all("Software\\MyProduct")?; + /// # Ok(()) + /// # } + /// ``` + 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() { + ptr::null() + } else { + c_path = to_utf16(path); + 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 std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?; + /// let server: String = settings.get_value("server")?; + /// let port: u32 = settings.get_value("port")?; + /// # Ok(()) + /// # } + /// ``` + 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 std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?; + /// let data = settings.get_raw_value("data")?; + /// println!("Bytes: {:?}", data.bytes); + /// # Ok(()) + /// # } + /// ``` + 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 std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let (settings, disp) = hkcu.create_subkey("Software\\MyProduct\\Settings")?; + /// settings.set_value("server", &"www.example.com")?; + /// settings.set_value("port", &8080u32)?; + /// # Ok(()) + /// # } + /// ``` + 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 std::error::Error; + /// use winreg::{RegKey, RegValue}; + /// use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?; + /// 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)?; + /// println!("Bytes: {:?}", data.bytes); + /// # Ok(()) + /// # } + /// ``` + 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 std::error::Error; + /// # use winreg::RegKey; + /// # use winreg::enums::*; + /// # fn main() -> Result<(), Box<dyn Error>> { + /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); + /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?; + /// settings.delete_value("data")?; + /// # Ok(()) + /// # } + /// ``` + 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 + /// # use std::error::Error; + /// #[macro_use] + /// extern crate serde_derive; + /// extern crate winreg; + /// 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, + /// } + /// + /// # fn main() -> Result<(), Box<dyn Error>> { + /// 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")?; + /// s_key.encode(&s)?; + /// # Ok(()) + /// # } + /// ``` + #[cfg(feature = "serialization-serde")] + pub fn encode<T: serde::Serialize>(&self, value: &T) -> encoder::EncodeResult<()> { + let mut encoder = encoder::Encoder::from_key(self)?; + value.serialize(&mut encoder)?; + encoder.commit() + } + + /// Load `Decodable` type from a registry key. + /// Part of `serialization-serde` feature. + /// + /// # Examples + /// + /// ```no_run + /// # use std::error::Error; + /// #[macro_use] + /// extern crate serde_derive; + /// extern crate winreg; + /// 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, + /// } + /// + /// # fn main() -> Result<(), Box<dyn Error>> { + /// let s_key = RegKey::predef(HKEY_CURRENT_USER) + /// .open_subkey("Software\\MyProduct\\Settings")?; + /// let s: Settings = s_key.decode()?; + /// # Ok(()) + /// # } + /// ``` + #[cfg(feature = "serialization-serde")] + pub fn decode<'de, T: serde::Deserialize<'de>>(&self) -> decoder::DecodeResult<T> { + let mut decoder = 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; + #[allow(clippy::unnecessary_cast)] + 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; + #[allow(clippy::unnecessary_cast)] + 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, + } + } + + fn nth(&mut self, n: usize) -> Option<Self::Item> { + self.index += n as DWORD; + self.next() + } +} + +/// 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 nth(&mut self, n: usize) -> Option<Self::Item> { + self.index += n as DWORD; + self.next() + } +} + +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() } +} diff --git a/third_party/rust/winreg/src/transaction.rs b/third_party/rust/winreg/src/transaction.rs new file mode 100644 index 0000000000..e63e3ea17c --- /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, _disp) = 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::io; +use std::ptr; +use winapi::um::handleapi; +use winapi::um::ktmw32; +use winapi::um::winnt; + +#[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 }) + } + } + + 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..37439354eb --- /dev/null +++ b/third_party/rust/winreg/src/types.rs @@ -0,0 +1,199 @@ +// 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 super::enums::*; +use super::winapi::shared::winerror; +use super::RegValue; +use super::{to_utf16, v16_to_v8}; +use std::ffi::{OsStr, OsString}; +use std::io; +use std::os::windows::ffi::OsStringExt; +use std::slice; + +/// 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` or `OsString`, trailing `NULL` characters are trimmed +/// and line separating `NULL` characters in `REG_MULTI_SZ` are replaced by `\n` +/// effectively representing the value as a multiline string. +/// When converting to `Vec<String>` or `Vec<OsString>` `NULL` is used as a strings separator. +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 { + #[allow(clippy::cast_ptr_alignment)] + 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 Vec<String> { + fn from_reg_value(val: &RegValue) -> io::Result<Vec<String>> { + match val.vtype { + 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(); + } + let v: Vec<String> = s.split('\u{0}').map(|x| x.to_owned()).collect(); + Ok(v) + } + _ => 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 mut words = unsafe { + #[allow(clippy::cast_ptr_alignment)] + slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2) + }; + while let Some(0) = words.last() { + words = &words[0..words.len() - 1]; + } + let s = OsString::from_wide(words); + Ok(s) + } + _ => werr!(winerror::ERROR_BAD_FILE_TYPE), + } + } +} + +impl FromRegValue for Vec<OsString> { + fn from_reg_value(val: &RegValue) -> io::Result<Vec<OsString>> { + match val.vtype { + REG_MULTI_SZ => { + let mut words = unsafe { + slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2) + }; + while let Some(0) = words.last() { + words = &words[0..words.len() - 1]; + } + let v: Vec<OsString> = words + .split(|ch| *ch == 0u16) + .map(|x| OsString::from_wide(x)) + .collect(); + Ok(v) + } + _ => werr!(winerror::ERROR_BAD_FILE_TYPE), + } + } +} + +impl FromRegValue for u32 { + fn from_reg_value(val: &RegValue) -> io::Result<u32> { + match val.vtype { + #[allow(clippy::cast_ptr_alignment)] + 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 { + #[allow(clippy::cast_ptr_alignment)] + 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`, `String`, `OsStr` and `OsString` values +pub trait ToRegValue { + fn to_reg_value(&self) -> RegValue; +} + +macro_rules! to_reg_value_sz { + ($t:ty$(, $l:lifetime)*) => { + impl<$($l,)*> ToRegValue for $t { + fn to_reg_value(&self) -> RegValue { + RegValue { + bytes: v16_to_v8(&to_utf16(self)), + vtype: REG_SZ, + } + } + } + } +} + +to_reg_value_sz!(String); +to_reg_value_sz!(&'a str, 'a); +to_reg_value_sz!(OsString); +to_reg_value_sz!(&'a OsStr, 'a); + +macro_rules! to_reg_value_multi_sz { + ($t:ty$(, $l:lifetime)*) => { + impl<$($l,)*> ToRegValue for Vec<$t> { + fn to_reg_value(&self) -> RegValue { + let mut os_strings = self + .into_iter() + .map(to_utf16) + .collect::<Vec<_>>() + .concat(); + os_strings.push(0); + RegValue { + bytes: v16_to_v8(&os_strings), + vtype: REG_MULTI_SZ, + } + } + } + } +} + +to_reg_value_multi_sz!(String); +to_reg_value_multi_sz!(&'a str, 'a); +to_reg_value_multi_sz!(OsString); +to_reg_value_multi_sz!(&'a OsStr, 'a); + +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, + 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, + vtype: REG_QWORD, + } + } +} diff --git a/third_party/rust/winreg/tests/reg_key.rs b/third_party/rust/winreg/tests/reg_key.rs new file mode 100644 index 0000000000..0a79300424 --- /dev/null +++ b/third_party/rust/winreg/tests/reg_key.rs @@ -0,0 +1,364 @@ +extern crate rand; +extern crate tempfile; +extern crate winapi; +extern crate winreg; +#[cfg(feature = "serialization-serde")] +#[macro_use] +extern crate serde_derive; +use self::rand::Rng; +use std::collections::HashMap; +use std::ffi::{OsStr, OsString}; +use tempfile::tempdir; +use winapi::shared::winerror; +use winreg::enums::*; +use winreg::types::FromRegValue; +use winreg::{RegKey, RegValue}; + +#[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_load_appkey() { + let val_name = "LoadKeyTest"; + let dir = tempdir().unwrap(); + let file_path = dir.path().join("RustLoadAppkeyTest.dat"); + let val1 = "Test123".to_owned(); + { + let key1 = RegKey::load_app_key(&file_path, true).unwrap(); + key1.set_value(val_name, &val1).unwrap(); + // this fails on Windows 7 with ERROR_ALREADY_EXISTS + let key_err = RegKey::load_app_key_with_flags(&file_path, KEY_READ, 0).unwrap_err(); + assert_eq!( + key_err.raw_os_error(), + Some(winerror::ERROR_SHARING_VIOLATION as i32) + ); + } + let val2: String = { + // this fails on Windows 7 with ERROR_ALREADY_EXISTS + let key2 = RegKey::load_app_key_with_flags(&file_path, KEY_READ, 1).unwrap(); + key2.get_value(val_name).unwrap() + }; + assert_eq!(val1, val2); +} + +#[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(); + + let info = win.query_info().unwrap(); + info.get_last_write_time_system(); + #[cfg(feature = "chrono")] + info.get_last_write_time_chrono(); + + 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()); +} + +#[test] +fn test_create_subkey_disposition() { + let hkcu = RegKey::predef(HKEY_CURRENT_USER); + let path = "Software\\WinRegRsTestCreateSubkey"; + let (_subkey, disp) = hkcu.create_subkey(path).unwrap(); + assert_eq!(disp, REG_CREATED_NEW_KEY); + let (_subkey2, disp2) = hkcu.create_subkey(path).unwrap(); + assert_eq!(disp2, REG_OPENED_EXISTING_KEY); + hkcu.delete_subkey_all(&path).unwrap(); +} + +macro_rules! with_key { + ($k:ident, $path:expr => $b:block) => {{ + let mut path = "Software\\WinRegRsTest".to_owned(); + path.push_str($path); + let ($k, _disp) = 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_delete_subkey_with_flags() { + let path = "Software\\Classes\\WinRegRsTestDeleteSubkeyWithFlags"; + RegKey::predef(HKEY_CURRENT_USER) + .create_subkey_with_flags(path, KEY_WOW64_32KEY) + .unwrap(); + assert!(RegKey::predef(HKEY_CURRENT_USER) + .delete_subkey_with_flags(path, KEY_WOW64_32KEY) + .is_ok()); +} + +#[test] +fn test_copy_tree() { + with_key!(key, "CopyTree" => { + let (sub_tree, _sub_tree_disp) = key.create_subkey("Src\\Sub\\Tree").unwrap(); + for v in &["one", "two", "three"] { + sub_tree.set_value(v, v).unwrap(); + } + let (dst, _dst_disp) = 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); + }); +} + +macro_rules! test_value_sz { + ($fname:ident, $kname:expr, $conv:expr => $tout:ty) => { + #[test] + fn $fname() { + with_key!(key, $kname => { + let name = "RustSzVal"; + let val1 = $conv("Test123 \n$%^&|+-*/\\()"); + key.set_value(name, &val1).unwrap(); + let val2: $tout = key.get_value(name).unwrap(); + assert_eq!(val1, val2); + }); + } + } +} + +test_value_sz!(test_string_value, "StringValue", str::to_owned => String); +test_value_sz!(test_str_value, "StrValue", |x|x => String); +test_value_sz!(test_os_string_value, "OsStringValue", OsString::from => OsString); +test_value_sz!(test_os_str_value, "OsStrValue", OsStr::new => OsString); + +#[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_long_os_string_value() { + with_key!(key, "LongOsStringValue" => { + let name = "RustLongOsStringVal"; + let val1 = rand::thread_rng().gen_ascii_chars().take(7000).collect::<String>(); + let val1 = OsStr::new(&val1); + key.set_value(name, &val1).unwrap(); + let val2: OsString = key.get_value(name).unwrap(); + assert_eq!(val1, val2); + }); +} + +macro_rules! test_value_multi_sz { + ($fname:ident, $kname:expr, $conv:expr => $tout:ty) => { + #[test] + fn $fname() { + with_key!(key, $kname => { + let name = "RustMultiSzVal"; + + let val1 = vec![ + $conv("lorem ipsum\ndolor"), + $conv("sit amet") + ]; + key.set_value(name, &val1).unwrap(); + let val2: Vec<$tout> = key.get_value(name).unwrap(); + + assert_eq!(val1, val2); + }); + } + } +} + +test_value_multi_sz!(test_vec_string_value, "StringVectorValue", str::to_owned => String); +test_value_multi_sz!(test_vec_str_value, "StrVectorValue", |x|x => String); +test_value_multi_sz!(test_vec_os_string_value, "OsStringVectorValue", OsString::from => OsString); +test_value_multi_sz!(test_vec_os_str_value, "OsStrVectorValue", OsStr::new => OsString); + +#[test] +fn test_u32_value() { + with_key!(key, "U32Value" => { + let name = "RustU32Val"; + let val1 = 1_234_567_890u32; + 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 = 1_234_567_891_011_121_314u64; + 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_unstable(); + 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_unstable(); + 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_map: HashMap<String, HashMap<String, u32>>, + t_i8: i8, + t_i16: i16, + t_i32: i32, + t_i64: i64, + t_isize: isize, + t_f64: f64, + t_f32: f32, + t_char: char, + } + + let mut k1 = HashMap::new(); + k1.insert("val1".to_owned(), 32); + k1.insert("val2".to_owned(), 64); + k1.insert("val3".to_owned(), 128); + + let mut k2 = HashMap::new(); + k2.insert("val1".to_owned(), 256); + k2.insert("val2".to_owned(), 512); + k2.insert("val3".to_owned(), 1024); + + let mut map = HashMap::new(); + map.insert("key1".to_owned(), k1); + map.insert("key2".to_owned(), k2); + + let v1 = Test { + t_bool: false, + t_u8: 127, + t_u16: 32768, + t_u32: 123_456_789, + t_u64: 123_456_789_101_112, + t_usize: 1_234_567_891, + t_struct: Rectangle { + x: 55, + y: 77, + w: 500, + h: 300, + }, + t_map: map, + t_string: "Test123 \n$%^&|+-*/\\()".to_owned(), + t_i8: -123, + t_i16: -2049, + t_i32: 20100, + t_i64: -12_345_678_910, + t_isize: -1_234_567_890, + t_f64: -0.01, + t_f32: 3.15, + t_char: 'a', + }; + + with_key!(key, "Serialization" => { + key.encode(&v1).unwrap(); + let v2: Test = key.decode().unwrap(); + assert_eq!(v1, v2); + }); +} |