├── .cargo └── config.toml ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Cross.toml ├── INPUT └── README.md ├── LICENSE ├── README.md ├── build.rs ├── docs ├── images │ ├── 01_octool_folder.png │ ├── 02_first_run.png │ ├── 03_navigation.png │ ├── 04_types.png │ ├── 05_edit_data.png │ ├── 06_edit_integer.png │ ├── 07_edit_string.png │ ├── 08_cut_copy_paste.png │ ├── 09_field_info.png │ ├── 10_resources.png │ ├── 11_resource_info.png │ ├── 12_oc_version.png │ ├── 13_res_version.png │ ├── 14_save.png │ ├── 15_merge_purge.png │ ├── 16_ordering.png │ └── 17_adding_kext.png └── index.md ├── src ├── build.rs ├── draw.rs ├── edit.rs ├── init.rs ├── main.rs ├── parse_tex.rs ├── res.rs └── snake.rs └── tool_config_files ├── config_differences.json ├── dyn_res_list.zip ├── octool_config.json ├── other.json └── resource_list.json /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | # Windows 64 bit programs 2 | [target.x86_64-pc-windows-msvc] 3 | rustflags = ["-C", "link-arg=libvcruntime.lib"] 4 | 5 | # Windows 32 bit programs 6 | [target.i686-pc-windows-msvc] 7 | rustflags = ["-C", "link-arg=libvcruntime.lib"] 8 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | release: 9 | types: [published] 10 | 11 | env: 12 | CARGO_TERM_COLOR: always 13 | 14 | jobs: 15 | build-mac-win: 16 | name: Build for ${{ matrix.os }} 17 | strategy: 18 | matrix: 19 | os: [x86_64-apple-darwin, x86_64-pc-windows-gnu] # x86_64-unknown-linux-gnu] 20 | 21 | runs-on: macos-latest 22 | 23 | steps: 24 | - uses: actions/checkout@v3 25 | 26 | - name: Add targets 27 | run: rustup target add ${{ matrix.os }} 28 | 29 | - name: Install x86_64-w64-mingw32-gcc 30 | run: brew install mingw-w64 31 | if: matrix.os == 'x86_64-pc-windows-gnu' 32 | - name: Build for ${{ matrix.os }} 33 | uses: actions-rs/cargo@v1 34 | with: 35 | command: build 36 | args: --target ${{ matrix.os }} --release 37 | 38 | - name: Move octool from target/${{ matrix.os }}/release/octool to . 39 | run: mv target/${{ matrix.os }}/release/octool* . 40 | 41 | - name: Create zip archive for ${{ matrix.os }} build 42 | run: zip ${{ matrix.os }}.zip octool octool.exe README.md LICENSE tool_config_files/octool_config.json 43 | 44 | - name: "Upload to artifacts" 45 | if: always() 46 | uses: actions/upload-artifact@v3 47 | with: 48 | name: "${{ matrix.os }}" 49 | path: "${{ matrix.os }}.zip" 50 | 51 | - name: Upload to Release 52 | if: github.event_name == 'release' 53 | uses: svenstaro/upload-release-action@133984371c30d34e38222a64855679a414cb7575 54 | with: 55 | repo_token: ${{ secrets.GITHUB_TOKEN }} 56 | file: ${{ matrix.os }}.zip 57 | tag: ${{ github.ref }} 58 | file_glob: true 59 | 60 | build-linux: 61 | name: Build for x86_64-unknown-linux-gnu 62 | runs-on: ubuntu-latest 63 | 64 | steps: 65 | - uses: actions/checkout@v3 66 | 67 | - name: Add targets 68 | run: rustup target add x86_64-unknown-linux-gnu 69 | 70 | - name: Build for x86_64-unknown-linux-gnu 71 | uses: actions-rs/cargo@v1 72 | with: 73 | command: build 74 | args: --target x86_64-unknown-linux-gnu --release 75 | 76 | - name: Move octool from target/x86_64-unknown-linux-gnu/release/octool to . 77 | run: mv target/x86_64-unknown-linux-gnu/release/octool . 78 | 79 | - name: Create zip archive for x86_64-unknown-linux-gnu build 80 | run: zip x86_64-unknown-linux-gnu.zip octool README.md LICENSE tool_config_files/octool_config.json 81 | 82 | - name: "Upload to artifacts" 83 | if: always() 84 | uses: actions/upload-artifact@v3 85 | with: 86 | name: "x86_64-unknown-linux-gnu" 87 | path: "x86_64-unknown-linux-gnu.zip" 88 | 89 | - name: Upload to Release 90 | if: github.event_name == 'release' 91 | uses: svenstaro/upload-release-action@133984371c30d34e38222a64855679a414cb7575 92 | with: 93 | repo_token: ${{ secrets.GITHUB_TOKEN }} 94 | file: x86_64-unknown-linux-gnu.zip 95 | tag: ${{ github.ref }} 96 | file_glob: true 97 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /resources 2 | /target 3 | .DS_Store 4 | tool_config_files/build-repo-builds 5 | INPUT/* 6 | !INPUT/README.md 7 | OUTPUT/ 8 | octool 9 | *INPUT*/ 10 | scripts/ 11 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "adler" 7 | version = "1.0.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 10 | 11 | [[package]] 12 | name = "aes" 13 | version = "0.7.5" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" 16 | dependencies = [ 17 | "cfg-if", 18 | "cipher", 19 | "cpufeatures", 20 | "opaque-debug", 21 | ] 22 | 23 | [[package]] 24 | name = "android_system_properties" 25 | version = "0.1.5" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 28 | dependencies = [ 29 | "libc", 30 | ] 31 | 32 | [[package]] 33 | name = "autocfg" 34 | version = "1.1.0" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 37 | 38 | [[package]] 39 | name = "base64" 40 | version = "0.13.1" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" 43 | 44 | [[package]] 45 | name = "base64ct" 46 | version = "1.5.3" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" 49 | 50 | [[package]] 51 | name = "bitflags" 52 | version = "1.3.2" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 55 | 56 | [[package]] 57 | name = "block-buffer" 58 | version = "0.10.3" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" 61 | dependencies = [ 62 | "generic-array", 63 | ] 64 | 65 | [[package]] 66 | name = "bumpalo" 67 | version = "3.12.0" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" 70 | 71 | [[package]] 72 | name = "byteorder" 73 | version = "1.4.3" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 76 | 77 | [[package]] 78 | name = "bzip2" 79 | version = "0.4.4" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" 82 | dependencies = [ 83 | "bzip2-sys", 84 | "libc", 85 | ] 86 | 87 | [[package]] 88 | name = "bzip2-sys" 89 | version = "0.1.11+1.0.8" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" 92 | dependencies = [ 93 | "cc", 94 | "libc", 95 | "pkg-config", 96 | ] 97 | 98 | [[package]] 99 | name = "cc" 100 | version = "1.0.79" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" 103 | dependencies = [ 104 | "jobserver", 105 | ] 106 | 107 | [[package]] 108 | name = "cfg-if" 109 | version = "1.0.0" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 112 | 113 | [[package]] 114 | name = "chrono" 115 | version = "0.4.23" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" 118 | dependencies = [ 119 | "iana-time-zone", 120 | "js-sys", 121 | "num-integer", 122 | "num-traits", 123 | "time 0.1.45", 124 | "wasm-bindgen", 125 | "winapi", 126 | ] 127 | 128 | [[package]] 129 | name = "cipher" 130 | version = "0.3.0" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" 133 | dependencies = [ 134 | "generic-array", 135 | ] 136 | 137 | [[package]] 138 | name = "codespan-reporting" 139 | version = "0.11.1" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" 142 | dependencies = [ 143 | "termcolor", 144 | "unicode-width", 145 | ] 146 | 147 | [[package]] 148 | name = "constant_time_eq" 149 | version = "0.1.5" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 152 | 153 | [[package]] 154 | name = "core-foundation-sys" 155 | version = "0.8.3" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 158 | 159 | [[package]] 160 | name = "cpufeatures" 161 | version = "0.2.5" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" 164 | dependencies = [ 165 | "libc", 166 | ] 167 | 168 | [[package]] 169 | name = "crc32fast" 170 | version = "1.3.2" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 173 | dependencies = [ 174 | "cfg-if", 175 | ] 176 | 177 | [[package]] 178 | name = "crossbeam-utils" 179 | version = "0.8.14" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" 182 | dependencies = [ 183 | "cfg-if", 184 | ] 185 | 186 | [[package]] 187 | name = "crossterm" 188 | version = "0.23.2" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "a2102ea4f781910f8a5b98dd061f4c2023f479ce7bb1236330099ceb5a93cf17" 191 | dependencies = [ 192 | "bitflags", 193 | "crossterm_winapi", 194 | "libc", 195 | "mio", 196 | "parking_lot", 197 | "signal-hook", 198 | "signal-hook-mio", 199 | "winapi", 200 | ] 201 | 202 | [[package]] 203 | name = "crossterm_winapi" 204 | version = "0.9.0" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" 207 | dependencies = [ 208 | "winapi", 209 | ] 210 | 211 | [[package]] 212 | name = "crypto-common" 213 | version = "0.1.6" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 216 | dependencies = [ 217 | "generic-array", 218 | "typenum", 219 | ] 220 | 221 | [[package]] 222 | name = "curl" 223 | version = "0.4.44" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" 226 | dependencies = [ 227 | "curl-sys", 228 | "libc", 229 | "openssl-probe", 230 | "openssl-sys", 231 | "schannel", 232 | "socket2", 233 | "winapi", 234 | ] 235 | 236 | [[package]] 237 | name = "curl-sys" 238 | version = "0.4.59+curl-7.86.0" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "6cfce34829f448b08f55b7db6d0009e23e2e86a34e8c2b366269bf5799b4a407" 241 | dependencies = [ 242 | "cc", 243 | "libc", 244 | "libz-sys", 245 | "openssl-sys", 246 | "pkg-config", 247 | "vcpkg", 248 | "winapi", 249 | ] 250 | 251 | [[package]] 252 | name = "cxx" 253 | version = "1.0.89" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9" 256 | dependencies = [ 257 | "cc", 258 | "cxxbridge-flags", 259 | "cxxbridge-macro", 260 | "link-cplusplus", 261 | ] 262 | 263 | [[package]] 264 | name = "cxx-build" 265 | version = "1.0.89" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d" 268 | dependencies = [ 269 | "cc", 270 | "codespan-reporting", 271 | "once_cell", 272 | "proc-macro2", 273 | "quote", 274 | "scratch", 275 | "syn", 276 | ] 277 | 278 | [[package]] 279 | name = "cxxbridge-flags" 280 | version = "1.0.89" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a" 283 | 284 | [[package]] 285 | name = "cxxbridge-macro" 286 | version = "1.0.89" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2" 289 | dependencies = [ 290 | "proc-macro2", 291 | "quote", 292 | "syn", 293 | ] 294 | 295 | [[package]] 296 | name = "digest" 297 | version = "0.10.6" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" 300 | dependencies = [ 301 | "block-buffer", 302 | "crypto-common", 303 | "subtle", 304 | ] 305 | 306 | [[package]] 307 | name = "flate2" 308 | version = "1.0.25" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" 311 | dependencies = [ 312 | "crc32fast", 313 | "miniz_oxide", 314 | ] 315 | 316 | [[package]] 317 | name = "fs_extra" 318 | version = "1.3.0" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" 321 | 322 | [[package]] 323 | name = "generic-array" 324 | version = "0.14.6" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" 327 | dependencies = [ 328 | "typenum", 329 | "version_check", 330 | ] 331 | 332 | [[package]] 333 | name = "getrandom" 334 | version = "0.2.8" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" 337 | dependencies = [ 338 | "cfg-if", 339 | "libc", 340 | "wasi 0.11.0+wasi-snapshot-preview1", 341 | ] 342 | 343 | [[package]] 344 | name = "hashbrown" 345 | version = "0.12.3" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 348 | 349 | [[package]] 350 | name = "hex" 351 | version = "0.4.3" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 354 | 355 | [[package]] 356 | name = "hmac" 357 | version = "0.12.1" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 360 | dependencies = [ 361 | "digest", 362 | ] 363 | 364 | [[package]] 365 | name = "iana-time-zone" 366 | version = "0.1.53" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" 369 | dependencies = [ 370 | "android_system_properties", 371 | "core-foundation-sys", 372 | "iana-time-zone-haiku", 373 | "js-sys", 374 | "wasm-bindgen", 375 | "winapi", 376 | ] 377 | 378 | [[package]] 379 | name = "iana-time-zone-haiku" 380 | version = "0.1.1" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" 383 | dependencies = [ 384 | "cxx", 385 | "cxx-build", 386 | ] 387 | 388 | [[package]] 389 | name = "indexmap" 390 | version = "1.9.2" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" 393 | dependencies = [ 394 | "autocfg", 395 | "hashbrown", 396 | ] 397 | 398 | [[package]] 399 | name = "itoa" 400 | version = "1.0.5" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" 403 | 404 | [[package]] 405 | name = "jobserver" 406 | version = "0.1.25" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" 409 | dependencies = [ 410 | "libc", 411 | ] 412 | 413 | [[package]] 414 | name = "js-sys" 415 | version = "0.3.61" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" 418 | dependencies = [ 419 | "wasm-bindgen", 420 | ] 421 | 422 | [[package]] 423 | name = "libc" 424 | version = "0.2.139" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" 427 | 428 | [[package]] 429 | name = "libz-sys" 430 | version = "1.1.8" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" 433 | dependencies = [ 434 | "cc", 435 | "libc", 436 | "pkg-config", 437 | "vcpkg", 438 | ] 439 | 440 | [[package]] 441 | name = "line-wrap" 442 | version = "0.1.1" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" 445 | dependencies = [ 446 | "safemem", 447 | ] 448 | 449 | [[package]] 450 | name = "link-cplusplus" 451 | version = "1.0.8" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" 454 | dependencies = [ 455 | "cc", 456 | ] 457 | 458 | [[package]] 459 | name = "lock_api" 460 | version = "0.4.9" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" 463 | dependencies = [ 464 | "autocfg", 465 | "scopeguard", 466 | ] 467 | 468 | [[package]] 469 | name = "log" 470 | version = "0.4.17" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 473 | dependencies = [ 474 | "cfg-if", 475 | ] 476 | 477 | [[package]] 478 | name = "memchr" 479 | version = "2.5.0" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 482 | 483 | [[package]] 484 | name = "miniz_oxide" 485 | version = "0.6.2" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" 488 | dependencies = [ 489 | "adler", 490 | ] 491 | 492 | [[package]] 493 | name = "mio" 494 | version = "0.8.5" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" 497 | dependencies = [ 498 | "libc", 499 | "log", 500 | "wasi 0.11.0+wasi-snapshot-preview1", 501 | "windows-sys 0.42.0", 502 | ] 503 | 504 | [[package]] 505 | name = "num-integer" 506 | version = "0.1.45" 507 | source = "registry+https://github.com/rust-lang/crates.io-index" 508 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 509 | dependencies = [ 510 | "autocfg", 511 | "num-traits", 512 | ] 513 | 514 | [[package]] 515 | name = "num-traits" 516 | version = "0.2.15" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 519 | dependencies = [ 520 | "autocfg", 521 | ] 522 | 523 | [[package]] 524 | name = "octool" 525 | version = "0.5.1" 526 | dependencies = [ 527 | "chrono", 528 | "crossterm", 529 | "curl", 530 | "fs_extra", 531 | "hex", 532 | "plist", 533 | "rand", 534 | "serde_json", 535 | "sha2", 536 | "walkdir", 537 | "zip", 538 | ] 539 | 540 | [[package]] 541 | name = "once_cell" 542 | version = "1.17.0" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" 545 | 546 | [[package]] 547 | name = "opaque-debug" 548 | version = "0.3.0" 549 | source = "registry+https://github.com/rust-lang/crates.io-index" 550 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 551 | 552 | [[package]] 553 | name = "openssl-probe" 554 | version = "0.1.5" 555 | source = "registry+https://github.com/rust-lang/crates.io-index" 556 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 557 | 558 | [[package]] 559 | name = "openssl-sys" 560 | version = "0.9.80" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" 563 | dependencies = [ 564 | "autocfg", 565 | "cc", 566 | "libc", 567 | "pkg-config", 568 | "vcpkg", 569 | ] 570 | 571 | [[package]] 572 | name = "parking_lot" 573 | version = "0.12.1" 574 | source = "registry+https://github.com/rust-lang/crates.io-index" 575 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 576 | dependencies = [ 577 | "lock_api", 578 | "parking_lot_core", 579 | ] 580 | 581 | [[package]] 582 | name = "parking_lot_core" 583 | version = "0.9.7" 584 | source = "registry+https://github.com/rust-lang/crates.io-index" 585 | checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" 586 | dependencies = [ 587 | "cfg-if", 588 | "libc", 589 | "redox_syscall", 590 | "smallvec", 591 | "windows-sys 0.45.0", 592 | ] 593 | 594 | [[package]] 595 | name = "password-hash" 596 | version = "0.4.2" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" 599 | dependencies = [ 600 | "base64ct", 601 | "rand_core", 602 | "subtle", 603 | ] 604 | 605 | [[package]] 606 | name = "pbkdf2" 607 | version = "0.11.0" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" 610 | dependencies = [ 611 | "digest", 612 | "hmac", 613 | "password-hash", 614 | "sha2", 615 | ] 616 | 617 | [[package]] 618 | name = "pkg-config" 619 | version = "0.3.26" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" 622 | 623 | [[package]] 624 | name = "plist" 625 | version = "1.4.0" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "5329b8f106a176ab0dce4aae5da86bfcb139bb74fb00882859e03745011f3635" 628 | dependencies = [ 629 | "base64", 630 | "indexmap", 631 | "line-wrap", 632 | "quick-xml", 633 | "serde", 634 | "time 0.3.17", 635 | ] 636 | 637 | [[package]] 638 | name = "ppv-lite86" 639 | version = "0.2.17" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 642 | 643 | [[package]] 644 | name = "proc-macro2" 645 | version = "1.0.51" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" 648 | dependencies = [ 649 | "unicode-ident", 650 | ] 651 | 652 | [[package]] 653 | name = "quick-xml" 654 | version = "0.26.0" 655 | source = "registry+https://github.com/rust-lang/crates.io-index" 656 | checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" 657 | dependencies = [ 658 | "memchr", 659 | ] 660 | 661 | [[package]] 662 | name = "quote" 663 | version = "1.0.23" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" 666 | dependencies = [ 667 | "proc-macro2", 668 | ] 669 | 670 | [[package]] 671 | name = "rand" 672 | version = "0.8.5" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 675 | dependencies = [ 676 | "libc", 677 | "rand_chacha", 678 | "rand_core", 679 | ] 680 | 681 | [[package]] 682 | name = "rand_chacha" 683 | version = "0.3.1" 684 | source = "registry+https://github.com/rust-lang/crates.io-index" 685 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 686 | dependencies = [ 687 | "ppv-lite86", 688 | "rand_core", 689 | ] 690 | 691 | [[package]] 692 | name = "rand_core" 693 | version = "0.6.4" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 696 | dependencies = [ 697 | "getrandom", 698 | ] 699 | 700 | [[package]] 701 | name = "redox_syscall" 702 | version = "0.2.16" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" 705 | dependencies = [ 706 | "bitflags", 707 | ] 708 | 709 | [[package]] 710 | name = "ryu" 711 | version = "1.0.12" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" 714 | 715 | [[package]] 716 | name = "safemem" 717 | version = "0.3.3" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" 720 | 721 | [[package]] 722 | name = "same-file" 723 | version = "1.0.6" 724 | source = "registry+https://github.com/rust-lang/crates.io-index" 725 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 726 | dependencies = [ 727 | "winapi-util", 728 | ] 729 | 730 | [[package]] 731 | name = "schannel" 732 | version = "0.1.21" 733 | source = "registry+https://github.com/rust-lang/crates.io-index" 734 | checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" 735 | dependencies = [ 736 | "windows-sys 0.42.0", 737 | ] 738 | 739 | [[package]] 740 | name = "scopeguard" 741 | version = "1.1.0" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 744 | 745 | [[package]] 746 | name = "scratch" 747 | version = "1.0.3" 748 | source = "registry+https://github.com/rust-lang/crates.io-index" 749 | checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" 750 | 751 | [[package]] 752 | name = "serde" 753 | version = "1.0.152" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" 756 | 757 | [[package]] 758 | name = "serde_json" 759 | version = "1.0.93" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" 762 | dependencies = [ 763 | "itoa", 764 | "ryu", 765 | "serde", 766 | ] 767 | 768 | [[package]] 769 | name = "sha1" 770 | version = "0.10.5" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" 773 | dependencies = [ 774 | "cfg-if", 775 | "cpufeatures", 776 | "digest", 777 | ] 778 | 779 | [[package]] 780 | name = "sha2" 781 | version = "0.10.6" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" 784 | dependencies = [ 785 | "cfg-if", 786 | "cpufeatures", 787 | "digest", 788 | ] 789 | 790 | [[package]] 791 | name = "signal-hook" 792 | version = "0.3.14" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" 795 | dependencies = [ 796 | "libc", 797 | "signal-hook-registry", 798 | ] 799 | 800 | [[package]] 801 | name = "signal-hook-mio" 802 | version = "0.2.3" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" 805 | dependencies = [ 806 | "libc", 807 | "mio", 808 | "signal-hook", 809 | ] 810 | 811 | [[package]] 812 | name = "signal-hook-registry" 813 | version = "1.4.0" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 816 | dependencies = [ 817 | "libc", 818 | ] 819 | 820 | [[package]] 821 | name = "smallvec" 822 | version = "1.10.0" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" 825 | 826 | [[package]] 827 | name = "socket2" 828 | version = "0.4.7" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" 831 | dependencies = [ 832 | "libc", 833 | "winapi", 834 | ] 835 | 836 | [[package]] 837 | name = "subtle" 838 | version = "2.4.1" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 841 | 842 | [[package]] 843 | name = "syn" 844 | version = "1.0.107" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" 847 | dependencies = [ 848 | "proc-macro2", 849 | "quote", 850 | "unicode-ident", 851 | ] 852 | 853 | [[package]] 854 | name = "termcolor" 855 | version = "1.2.0" 856 | source = "registry+https://github.com/rust-lang/crates.io-index" 857 | checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" 858 | dependencies = [ 859 | "winapi-util", 860 | ] 861 | 862 | [[package]] 863 | name = "time" 864 | version = "0.1.45" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" 867 | dependencies = [ 868 | "libc", 869 | "wasi 0.10.0+wasi-snapshot-preview1", 870 | "winapi", 871 | ] 872 | 873 | [[package]] 874 | name = "time" 875 | version = "0.3.17" 876 | source = "registry+https://github.com/rust-lang/crates.io-index" 877 | checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" 878 | dependencies = [ 879 | "itoa", 880 | "serde", 881 | "time-core", 882 | "time-macros", 883 | ] 884 | 885 | [[package]] 886 | name = "time-core" 887 | version = "0.1.0" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" 890 | 891 | [[package]] 892 | name = "time-macros" 893 | version = "0.2.6" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" 896 | dependencies = [ 897 | "time-core", 898 | ] 899 | 900 | [[package]] 901 | name = "typenum" 902 | version = "1.16.0" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 905 | 906 | [[package]] 907 | name = "unicode-ident" 908 | version = "1.0.6" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" 911 | 912 | [[package]] 913 | name = "unicode-width" 914 | version = "0.1.10" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" 917 | 918 | [[package]] 919 | name = "vcpkg" 920 | version = "0.2.15" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 923 | 924 | [[package]] 925 | name = "version_check" 926 | version = "0.9.4" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 929 | 930 | [[package]] 931 | name = "walkdir" 932 | version = "2.3.2" 933 | source = "registry+https://github.com/rust-lang/crates.io-index" 934 | checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" 935 | dependencies = [ 936 | "same-file", 937 | "winapi", 938 | "winapi-util", 939 | ] 940 | 941 | [[package]] 942 | name = "wasi" 943 | version = "0.10.0+wasi-snapshot-preview1" 944 | source = "registry+https://github.com/rust-lang/crates.io-index" 945 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 946 | 947 | [[package]] 948 | name = "wasi" 949 | version = "0.11.0+wasi-snapshot-preview1" 950 | source = "registry+https://github.com/rust-lang/crates.io-index" 951 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 952 | 953 | [[package]] 954 | name = "wasm-bindgen" 955 | version = "0.2.84" 956 | source = "registry+https://github.com/rust-lang/crates.io-index" 957 | checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" 958 | dependencies = [ 959 | "cfg-if", 960 | "wasm-bindgen-macro", 961 | ] 962 | 963 | [[package]] 964 | name = "wasm-bindgen-backend" 965 | version = "0.2.84" 966 | source = "registry+https://github.com/rust-lang/crates.io-index" 967 | checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" 968 | dependencies = [ 969 | "bumpalo", 970 | "log", 971 | "once_cell", 972 | "proc-macro2", 973 | "quote", 974 | "syn", 975 | "wasm-bindgen-shared", 976 | ] 977 | 978 | [[package]] 979 | name = "wasm-bindgen-macro" 980 | version = "0.2.84" 981 | source = "registry+https://github.com/rust-lang/crates.io-index" 982 | checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" 983 | dependencies = [ 984 | "quote", 985 | "wasm-bindgen-macro-support", 986 | ] 987 | 988 | [[package]] 989 | name = "wasm-bindgen-macro-support" 990 | version = "0.2.84" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" 993 | dependencies = [ 994 | "proc-macro2", 995 | "quote", 996 | "syn", 997 | "wasm-bindgen-backend", 998 | "wasm-bindgen-shared", 999 | ] 1000 | 1001 | [[package]] 1002 | name = "wasm-bindgen-shared" 1003 | version = "0.2.84" 1004 | source = "registry+https://github.com/rust-lang/crates.io-index" 1005 | checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" 1006 | 1007 | [[package]] 1008 | name = "winapi" 1009 | version = "0.3.9" 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" 1011 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1012 | dependencies = [ 1013 | "winapi-i686-pc-windows-gnu", 1014 | "winapi-x86_64-pc-windows-gnu", 1015 | ] 1016 | 1017 | [[package]] 1018 | name = "winapi-i686-pc-windows-gnu" 1019 | version = "0.4.0" 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" 1021 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1022 | 1023 | [[package]] 1024 | name = "winapi-util" 1025 | version = "0.1.5" 1026 | source = "registry+https://github.com/rust-lang/crates.io-index" 1027 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1028 | dependencies = [ 1029 | "winapi", 1030 | ] 1031 | 1032 | [[package]] 1033 | name = "winapi-x86_64-pc-windows-gnu" 1034 | version = "0.4.0" 1035 | source = "registry+https://github.com/rust-lang/crates.io-index" 1036 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1037 | 1038 | [[package]] 1039 | name = "windows-sys" 1040 | version = "0.42.0" 1041 | source = "registry+https://github.com/rust-lang/crates.io-index" 1042 | checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" 1043 | dependencies = [ 1044 | "windows_aarch64_gnullvm", 1045 | "windows_aarch64_msvc", 1046 | "windows_i686_gnu", 1047 | "windows_i686_msvc", 1048 | "windows_x86_64_gnu", 1049 | "windows_x86_64_gnullvm", 1050 | "windows_x86_64_msvc", 1051 | ] 1052 | 1053 | [[package]] 1054 | name = "windows-sys" 1055 | version = "0.45.0" 1056 | source = "registry+https://github.com/rust-lang/crates.io-index" 1057 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" 1058 | dependencies = [ 1059 | "windows-targets", 1060 | ] 1061 | 1062 | [[package]] 1063 | name = "windows-targets" 1064 | version = "0.42.1" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" 1067 | dependencies = [ 1068 | "windows_aarch64_gnullvm", 1069 | "windows_aarch64_msvc", 1070 | "windows_i686_gnu", 1071 | "windows_i686_msvc", 1072 | "windows_x86_64_gnu", 1073 | "windows_x86_64_gnullvm", 1074 | "windows_x86_64_msvc", 1075 | ] 1076 | 1077 | [[package]] 1078 | name = "windows_aarch64_gnullvm" 1079 | version = "0.42.1" 1080 | source = "registry+https://github.com/rust-lang/crates.io-index" 1081 | checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" 1082 | 1083 | [[package]] 1084 | name = "windows_aarch64_msvc" 1085 | version = "0.42.1" 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" 1087 | checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" 1088 | 1089 | [[package]] 1090 | name = "windows_i686_gnu" 1091 | version = "0.42.1" 1092 | source = "registry+https://github.com/rust-lang/crates.io-index" 1093 | checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" 1094 | 1095 | [[package]] 1096 | name = "windows_i686_msvc" 1097 | version = "0.42.1" 1098 | source = "registry+https://github.com/rust-lang/crates.io-index" 1099 | checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" 1100 | 1101 | [[package]] 1102 | name = "windows_x86_64_gnu" 1103 | version = "0.42.1" 1104 | source = "registry+https://github.com/rust-lang/crates.io-index" 1105 | checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" 1106 | 1107 | [[package]] 1108 | name = "windows_x86_64_gnullvm" 1109 | version = "0.42.1" 1110 | source = "registry+https://github.com/rust-lang/crates.io-index" 1111 | checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" 1112 | 1113 | [[package]] 1114 | name = "windows_x86_64_msvc" 1115 | version = "0.42.1" 1116 | source = "registry+https://github.com/rust-lang/crates.io-index" 1117 | checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" 1118 | 1119 | [[package]] 1120 | name = "zip" 1121 | version = "0.6.4" 1122 | source = "registry+https://github.com/rust-lang/crates.io-index" 1123 | checksum = "0445d0fbc924bb93539b4316c11afb121ea39296f99a3c4c9edad09e3658cdef" 1124 | dependencies = [ 1125 | "aes", 1126 | "byteorder", 1127 | "bzip2", 1128 | "constant_time_eq", 1129 | "crc32fast", 1130 | "crossbeam-utils", 1131 | "flate2", 1132 | "hmac", 1133 | "pbkdf2", 1134 | "sha1", 1135 | "time 0.3.17", 1136 | "zstd", 1137 | ] 1138 | 1139 | [[package]] 1140 | name = "zstd" 1141 | version = "0.11.2+zstd.1.5.2" 1142 | source = "registry+https://github.com/rust-lang/crates.io-index" 1143 | checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" 1144 | dependencies = [ 1145 | "zstd-safe", 1146 | ] 1147 | 1148 | [[package]] 1149 | name = "zstd-safe" 1150 | version = "5.0.2+zstd.1.5.2" 1151 | source = "registry+https://github.com/rust-lang/crates.io-index" 1152 | checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" 1153 | dependencies = [ 1154 | "libc", 1155 | "zstd-sys", 1156 | ] 1157 | 1158 | [[package]] 1159 | name = "zstd-sys" 1160 | version = "2.0.7+zstd.1.5.4" 1161 | source = "registry+https://github.com/rust-lang/crates.io-index" 1162 | checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" 1163 | dependencies = [ 1164 | "cc", 1165 | "libc", 1166 | "pkg-config", 1167 | ] 1168 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["rusty-bits "] 3 | edition = "2021" 4 | name = "octool" 5 | version = "0.5.1" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [build-dependencies] 10 | chrono = "0.4.22" 11 | 12 | [dependencies] 13 | crossterm = "0.23.2" 14 | curl = "0.4.43" 15 | fs_extra = "1.2.0" 16 | hex = "0.4.3" 17 | plist = "1.3.1" 18 | rand = "0.8.5" 19 | serde_json = "1.0.81" 20 | sha2 = "0.10.2" 21 | walkdir = "2.3.2" 22 | zip = "0.6.2" 23 | 24 | [profile.release] 25 | #codegen-units = 1 # re-enable for more efficient linking at the cost of compile time 26 | lto = true 27 | opt-level = "z" 28 | panic = "abort" 29 | strip = true 30 | -------------------------------------------------------------------------------- /Cross.toml: -------------------------------------------------------------------------------- 1 | [target.x86_64-unknown-linux-gnu] 2 | pre-build = ["apt-get update && apt-get install --assume-yes libssl-dev"] 3 | 4 | [target.x86_64-pc-windows-gnu] 5 | 6 | -------------------------------------------------------------------------------- /INPUT/README.md: -------------------------------------------------------------------------------- 1 | This is the `INPUT` folder 2 | 3 | Place your `config.plist` in here along with any custom files you want included in your `EFI` 4 | 5 | for example 6 | - `SSDT-XXX.aml` files specific to your build 7 | - `USBMap.kext` or similar if you have mapped your USB ports with the USBMap.command or USBToolBox 8 | - custom theme files for `OpenCanopy` 9 | - other custom drivers and kexts, e.g. things like `Solarflare10GbE.kext` that I need for my ethernet 10 | 11 | basically, any files that are not part of the Dortania builds or listed in the `tool_config_files/resource_list.json` 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 rusty-bits 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # octool 2 | 3 | [![license](https://img.shields.io/github/license/rusty-bits/octool.svg)](https://github.com/rusty-bits/octool/blob/main/LICENSE) 4 | [![downloads](https://img.shields.io/github/downloads/rusty-bits/octool/total)](https://github.com/rusty-bits/octool/releases) 5 | [![CI](https://github.com/rusty-bits/octool/actions/workflows/ci.yml/badge.svg)](https://github.com/rusty-bits/octool/actions/workflows/ci.yml) 6 | [![release](https://img.shields.io/github/v/release/rusty-bits/octool?display_name=tag)](https://github.com/rusty-bits/octool/releases) 7 | 8 | A small project to help me continue my learning of the Rust language. All suggestions and criticisms are welcome (but that doesn't mean I'll get to them in a timely manner, I can be lazy at times) 9 | You can build from the included source by running `cargo build --release` (if you have the Rust environment installed) or you can use the binary from [the Releases section on GitHub](https://github.com/rusty-bits/octool/releases). Unlike my older OC-tool, this tool does not auto update itself to the latest version, but it will let you know if there is an update. 10 | 11 | You can find a basic picture guide for the use of octool here [https://rusty-bits.github.io/octool/](https://rusty-bits.github.io/octool/) 12 | 13 | ## Command line options ## 14 | 15 | ./octool [options] [-V x.y.z] [INPUT_folder || config.plist] 16 | 17 | -d use `debug` versions for EFI instead of `release` versions 18 | 19 | -h print help/usage message then exit 20 | 21 | -v print octool version information and booted OpenCore version if the var is in NVRAM then exit 22 | 23 | -V x.y.z select OpenCore version number to use e.g. `-V 0.9.7` 24 | - without this option octool will make a quick guess as to which version to use based on the INPUT config.plist, if no INPUT config.plist is provided, octool will default to the latest OpenCore version 25 | 26 | octool takes a path to a folder whos name contains `INPUT` at any point. This folder contains a config.plist and additional files for a specific build which allows the user to have numerous differing configs. octool will also take a direct path to a specific `config.plist` to use if desired and will gather what is needed for that specific config in the generic `INPUT` folder 27 | If you run octool with no path provided `./octool` will look for `config.plist` in the generic `INPUT` folder, if it doesn't find it there it will use the `OpenCorePkg/Docs/Sample.plist` file. 28 | 29 | At startup, octool checks for a local copy of [the builds branch of the Dortania/build-repo](https://github.com/dortania/build-repo/tree/builds) so it will know the urls and hashes of the prebuilt binary resources. Thank you [dhinakg](https://github.com/dhinakg), [hieplpvip](https://github.com/hieplpvip), and [khronokernel](https://github.com/khronokernel). 30 | - It will update or download it to the `build-repo` into the `tool_config_files` folder as needed. 31 | 32 | Next, octool does the same thing for [the master branch of the Acidanthera OpenCorePkg source files](https://github.com/acidanthera/OpenCorePkg), thanks to the [people of Acidanthera](https://github.com/acidanthera), in order to have the corresponding Sample.plist and Configuration.tex files, etc. for the version of OpenCore that you are building. They will be placed into the `resources` folder along with the corresponding binaries from the Dortania builds. This will allow `octool` to use Acidanthera tools while building the EFI, such as the ocvalitate and CreateVault tools. Thanks, again [dhinakg](https://github.com/dhinakg). 33 | 34 | Lastly, octool will run the input config.plist through ocvalitade and give you the option to quit or continue. 35 | If you continue you then enter the 36 | 37 | ## config.plist editor... ## 38 | ``` 39 | Navigation: arrow keys or some standard vi keys 40 | 'up'/'k' jump to top of section 41 | ^ 't' 42 | | ^ 43 | 'left'/'h' <-- --> 'right'/'l' | 44 | | v 45 | v 'b' 46 | 'down'/'j' jump to bottom of section 47 | ``` 48 | Usage: 49 | 'ENTER' will switch to edit mode for string, integer, or data fields. When editing a data field 'TAB' will toggle between editing the data as hex or as a string. 50 | - 'ENTER' will save any changes made 51 | - 'ESC' will discard and changes 52 | - if the field being edited has values listed in the `Configuration.tex` file, octool will display a list of them 53 | 54 | 'SPACE' will toggles boolean value between true/false 55 | - 'SPACE' will also toggle the Enabled status of kexts, drivers, tools, and amls when they are highlighted in the section list 56 | - and will toggle binary values for fields that have bit values listed in the `Configuration.tex` file 57 | 58 | 'a' `add` - if in a resource section there is option to select from a list of known resources, or add a blank resource template to the working `plist` from the `Sample.plist` 59 | - if in another section you can select a type and key name to add to the working plist 60 | 61 | 'ctrl-c' `copy` - copy the highlighted field or section 62 | 63 | 'd' `delete` - will delete the highlighted field or section after confirmation (`dd` command). The deleted data can be replaced by using the 'p' paste command 64 | 65 | 'f' `find` - find all occurances of a string in the plist 66 | - if there is only one occurance, it will jump to the location 67 | - if there is more than one occurance, it will present a list to select from 68 | - 'n' can be used to go to the next item without needing to do another find command 69 | 70 | 'G' `go` (capital G) - make an OUTPUT/EFI/OC folder from the config.plist 71 | - if `OpenCanopy.efi` is enabled it will copy the OcBinaryData Resources to `OUTPUT/EFI/OC/Resources` 72 | - if `Misc > Security > Vault` is set to `Basic` or `Secure`, octool will compute the required files and sign the `OpenCore.efi` if needed 73 | - octool will ignore resources that it doesn't know unless they are placed in the INPUT folder, it will print out a warning, but it will not make a change to the config.plist for the unknown resource 74 | - any file placed in the `INPUT` folder will take priority and will be used for the `OUTPUT/EFI`, even if a more recent version of that resource is available elsewhere. This is good for using a specific version of a kext, for example, or for using a specific SSDT or USBMap 75 | - lastly, it will again validate the `OUTPUT/EFI/OC/config.plist` file with ocvalidate 76 | 77 | 'i' show `info` of highlighted item. 78 | - If item is resource such as a kext or driver, octool will show the source of the file it will place in the `OUTPUT/EFI` folder. 79 | - Otherwise, octool will show the description and info from the corresponding [Acidanthera](https://github.com/acidanthera) `Configuration.tex` file. 80 | 81 | 'I' - Capital I - `Insert` - enter the path to a plist file, or drop it on the window, and octool will add the fields from that plist 82 | - useful to add a plist that just contains Patches, for example the `patches_OC.plist` file created by [CorpNewt's](https://github.com/corpnewt) SSDTTime tool 83 | 84 | 'K' `Key` - capital K - edit the name of the highlighted key 85 | 86 | 'M' `merge` - capital M - will add missing fields to the `config.plist` from the `Sample.plist` without changing any existing fields. 87 | - this command, coupled with its companion Purge command (capital P) will update a config.plist when OpenCore plist format changes occur 88 | 89 | 'n' `next` - jump to the next found item if more than one occurance was found 90 | 91 | 'O' `order` - Capital O - if currently in the Kernel > Add section the 'O' command will check the order and dependencies of kexts. 92 | - If a kext is in the wrong order based on a dependency then octool will reorder them. 93 | - If a required dependency is missing then octool will add and enable the required dependency. 94 | - If there are any duplicate enabled kexts then octool will disable the duplicates. 95 | 96 | 'P' `purge` - Capital P - removes fields from the `config.plist` that are not in the `Sample.plist` 97 | - this command, coupled with it's companion merge command (capital M) will update a config.plist when OpenCore plst format changes occur 98 | 99 | 'p' `paste` - places the last deleted or modified etc. item into the plist (for those familiar with vi commands) 100 | - if pasting into a dictionary, `octool` will append `-copy` to the pasted item 101 | 102 | 'q' `quit` - if unsaved changes were made to the `config.plist` octool will show a warning so changes can be saved 103 | 104 | 'r' `reset` - if a single item is selected, reset its value to the same as the `Sample.plist` value 105 | - if a section is highlighted, reset the whole section to the same as the section in the `Sample.plist` 106 | 107 | 's' `save` a copy of the `config.plist` as `INPUT/modified_config.plist` 108 | - `modified_` will be added to the begining of the saved file unless you are already working on a `modified_` file 109 | - the saved file will be checked with `ocvalidate` for any errors 110 | 111 | 'V' `Version` - Capital V - change the version of OpenCore that will be checked against and used in the `OUTPUT` EFI 112 | - or, if 'V' is used while a resource is highlighted, you can change the version of that specific resource 113 | 114 | 'ctrl-x' `cut` - remove the highlighted field or section from the plist 115 | 116 | 'y' `yank` - copy the highlighted field or section (included for those vim users used to 'y' for copying) 117 | 118 | 'ctrl-v' `paste` - place the last cut, copied, etc. item into the plist 119 | 120 | ## File and Folder Descriptions ## 121 | `tool_config_files` folder - contains various json formatted files 122 | - `octool_config.json` - settings for octool itself, octool will create this if it doesn't exist 123 | - `resource_list.json` - list of resources by full name e.g. `Lilu.kext` and their parent resource, octool will create this if it doesn't exist 124 | - `build-repo` folder - contains the `config.json` file from the Dortania builds repo with url, version, hash, date created, etc. info for the parent resources. octool will download this from Dortania if it doesn't exist 125 | - `other.json` - contains a list of additional parent resources not included in the Dortania `build--repo`, octool will create this if it doesn't exist 126 | 127 | `INPUT` folder - place your `config.plist` here along with other files to be included in the `OUTPUT/EFI`, such as custom SSDT files, custom Drivers, custom OpenCanopy themes, etc. 128 | - `octool` will not overwrite the input config.plist on save, instead it will save a version called `modified_config.plist` in this folder so the original `config.plist` can still be used if needed 129 | - `octool` will also automatically save a config.plist titled `last_built_config.plist` when the build command is run for easy reference to a copy of the config.plist that is in the OUTPUT/EFI folder 130 | 131 | `OUTPUT` folder - location where `octool` will put the created `EFI` folder 132 | 133 | `resources` folder - location where `octool` places the resources needed to create the `OUTPUT/EFI` folder. Can be deleted if desired, octool will gather any resources it needs when run 134 | 135 | ## To Do: ## 136 | - change tool configuration from inside tool, the configuration file `tool_config_files/octool_config.json` contains vars to set up octool, for example the language versions of the audio files for OpenCanopy for e.g. `en` 137 | - keep the highlighted item on screen while reading long info from the Configuration.tex so the user can edit the field while also reading the info 138 | - fix some style formatting of the info screens so underline, bold, etc. looks better when it crosses multiple lines 139 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::{env, fs, io::Write}; 2 | 3 | use chrono::Datelike; 4 | 5 | fn main() { 6 | let outdir = env::var("OUT_DIR").unwrap(); 7 | let outfile = format!("{}/version.txt", outdir); 8 | 9 | let mut fh = fs::File::create(&outfile).unwrap(); 10 | 11 | let now = chrono::Local::now(); 12 | write!( 13 | fh, 14 | r#""v{} {}-{:02}-{:02}""#, 15 | env!("CARGO_PKG_VERSION"), 16 | now.year(), 17 | now.month(), 18 | now.day() 19 | ) 20 | .ok(); 21 | } 22 | -------------------------------------------------------------------------------- /docs/images/01_octool_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/01_octool_folder.png -------------------------------------------------------------------------------- /docs/images/02_first_run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/02_first_run.png -------------------------------------------------------------------------------- /docs/images/03_navigation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/03_navigation.png -------------------------------------------------------------------------------- /docs/images/04_types.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/04_types.png -------------------------------------------------------------------------------- /docs/images/05_edit_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/05_edit_data.png -------------------------------------------------------------------------------- /docs/images/06_edit_integer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/06_edit_integer.png -------------------------------------------------------------------------------- /docs/images/07_edit_string.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/07_edit_string.png -------------------------------------------------------------------------------- /docs/images/08_cut_copy_paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/08_cut_copy_paste.png -------------------------------------------------------------------------------- /docs/images/09_field_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/09_field_info.png -------------------------------------------------------------------------------- /docs/images/10_resources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/10_resources.png -------------------------------------------------------------------------------- /docs/images/11_resource_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/11_resource_info.png -------------------------------------------------------------------------------- /docs/images/12_oc_version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/12_oc_version.png -------------------------------------------------------------------------------- /docs/images/13_res_version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/13_res_version.png -------------------------------------------------------------------------------- /docs/images/14_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/14_save.png -------------------------------------------------------------------------------- /docs/images/15_merge_purge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/15_merge_purge.png -------------------------------------------------------------------------------- /docs/images/16_ordering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/16_ordering.png -------------------------------------------------------------------------------- /docs/images/17_adding_kext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/docs/images/17_adding_kext.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | Simple picture guide showing common usage of octool 2 | 3 | *** 4 | ## when downloaded the octool folder will contain these items 5 | *** 6 | ![](images/01_octool_folder.png) 7 | 8 | *** 9 | ## on first run you will see something similar to this 10 | *** 11 | ![](images/02_first_run.png) 12 | 13 | *** 14 | ## summary of basic navigation and commands of the plist viewer/editor 15 | *** 16 | ![](images/03_navigation.png) 17 | 18 | *** 19 | ## how different data types are represented in the plist editor 20 | *** 21 | ![](images/04_types.png) 22 | 23 | *** 24 | ## editing a data type in hexidecimal or string format 25 | *** 26 | ![](images/05_edit_data.png) 27 | 28 | *** 29 | ## editing an integer type directly or bit by bit 30 | *** 31 | ![](images/06_edit_integer.png) 32 | 33 | *** 34 | ## editing a string type directly or selecting from available options 35 | *** 36 | ![](images/07_edit_string.png) 37 | 38 | *** 39 | ## the cut, copy and paste commands 40 | *** 41 | ![](images/08_cut_copy_paste.png) 42 | 43 | *** 44 | ## displaying Configuration.pdf information for the highlighted field 45 | *** 46 | ![](images/09_field_info.png) 47 | 48 | *** 49 | ## typical display of a resource section in the config.plist 50 | *** 51 | ![](images/10_resources.png) 52 | 53 | *** 54 | ## displaying information of the selected resource 55 | *** 56 | ![](images/11_resource_info.png) 57 | 58 | *** 59 | ## changing the version of OpenCore being used 60 | *** 61 | ![](images/12_oc_version.png) 62 | 63 | *** 64 | ## changing the version used of a single resource 65 | *** 66 | ![](images/13_res_version.png) 67 | 68 | *** 69 | ## typical save output showing errors in config.plist 70 | *** 71 | ![](images/14_save.png) 72 | 73 | *** 74 | ## the merge and purge commands for updating the config.plist 75 | *** 76 | ![](images/15_merge_purge.png) 77 | 78 | *** 79 | ## the ordering command for checking kext requirements and load order 80 | *** 81 | ![](images/16_ordering.png) 82 | 83 | *** 84 | ## adding a kext to the Kernel>Add section 85 | *** 86 | ![](images/17_adding_kext.png) 87 | -------------------------------------------------------------------------------- /src/build.rs: -------------------------------------------------------------------------------- 1 | use crate::init::Settings; 2 | use crate::res::{self, get_res_path, res_version, status, Resources}; 3 | 4 | use fs_extra::dir::{self, CopyOptions}; 5 | use std::error::Error; 6 | use std::fs; 7 | use std::io::{Stdout, Write}; 8 | use std::path::{Path, PathBuf}; 9 | 10 | /// Create the OUTPUT/EFI from the loaded config.plist 11 | /// If octool is being run from a different directory then also copy the 12 | /// completed EFI to that location if it had no errors 13 | pub fn build_output( 14 | settings: &mut Settings, 15 | resources: &Resources, 16 | stdout: &mut Stdout, 17 | ) -> Result> { 18 | dir::remove("OUTPUT")?; 19 | fs::create_dir_all("OUTPUT/EFI")?; 20 | let mut has_open_canopy = false; 21 | let mut build_okay = true; 22 | let mut missing_files: Vec<&str> = vec![]; 23 | 24 | let mut options = CopyOptions::new(); 25 | options.overwrite = true; 26 | let mut in_path = resources.octool_config["build_architecture"] 27 | .as_str() 28 | .unwrap_or("X64") 29 | .to_string(); 30 | in_path.push_str("/EFI"); 31 | if !resources.open_core_binaries_path.join(&in_path).exists() { 32 | in_path = "EFI".to_string(); // older OpenCorePkg versions 33 | } 34 | dir::copy( 35 | &resources.open_core_binaries_path.join(in_path), 36 | "OUTPUT", 37 | &options, 38 | )?; 39 | dir::remove("OUTPUT/EFI/OC/Drivers")?; // cheap hack way of removing all drivers 40 | dir::remove("OUTPUT/EFI/OC/Tools")?; // and tools from OUTPUT/EFI 41 | fs::create_dir_all("OUTPUT/EFI/OC/Drivers")?; // now we need to put an empty dir back 42 | fs::create_dir_all("OUTPUT/EFI/OC/Tools")?; // and again 43 | resources 44 | .config_plist 45 | .to_file_xml("OUTPUT/EFI/OC/config.plist")?; 46 | 47 | let res_config: Vec<(String, String, String, String)> = 48 | serde_json::from_value(resources.octool_config["resource_sections"].clone()).unwrap(); 49 | for (sec, sub, pth, out_pth) in res_config { 50 | write!( 51 | stdout, 52 | "\x1B[0J\r\n\x1B[32mCopying\x1B[0m enabled {} files ...\r\n", 53 | &sec 54 | )?; 55 | stdout.flush()?; 56 | let mut from_paths = Vec::new(); 57 | let enabled_resources = resources.config_plist.as_dictionary().unwrap()[&sec] 58 | .as_dictionary() 59 | .unwrap()[&sub] 60 | .as_array() 61 | .unwrap(); 62 | let mut res; 63 | for val in enabled_resources { 64 | match val { 65 | // oc 0.7.3 and above 66 | plist::Value::Dictionary(d) => { 67 | if d.contains_key("Enabled") { 68 | if d["Enabled"].as_boolean().unwrap() { 69 | res = d[&pth].as_string().unwrap().split('/').next().unwrap(); 70 | } else { 71 | continue; 72 | } 73 | } else if d.contains_key("Load") { 74 | if d["Load"].as_string().unwrap() != "Disabled" { 75 | res = d[&pth].as_string().unwrap().split('/').next().unwrap(); 76 | } else { 77 | continue; 78 | } 79 | } else { 80 | continue; 81 | } 82 | } 83 | //oc 0.7.2 and below 84 | plist::Value::String(s) => { 85 | if !s.to_string().starts_with('#') { 86 | res = s.as_str(); 87 | } else { 88 | continue; 89 | } 90 | } 91 | _ => continue, 92 | } 93 | if &sub == "Drivers" && res == "OpenCanopy.efi" { 94 | has_open_canopy = true; 95 | } 96 | res_version(settings, &resources, &res); 97 | match get_res_path(&settings, &resources, &res, &sec, stdout, false) { 98 | Some(res) => { 99 | from_paths.push(res); 100 | } 101 | None => { 102 | build_okay = false; 103 | missing_files.push(&res); 104 | write!( 105 | stdout, 106 | "\x1B[31mERROR: {} not found, skipping\x1B[0m\r\n", 107 | res 108 | )?; 109 | } 110 | } 111 | } 112 | from_paths.sort(); 113 | from_paths.dedup(); 114 | let mut to_path = "OUTPUT/EFI/OC/".to_string(); 115 | to_path.push_str(&out_pth); 116 | fs_extra::copy_items(&from_paths, &to_path, &options)?; 117 | let mut s = ""; 118 | if from_paths.len() > 1 { 119 | s = "s"; 120 | }; 121 | if from_paths.len() == 0 { 122 | write!(stdout, "No files to copy\r\n\n")?; 123 | } else { 124 | write!( 125 | stdout, 126 | "\x1B[32mDone\x1B[0m with {} file{}\r\n\n", 127 | from_paths.len(), 128 | s 129 | )?; 130 | } 131 | } 132 | 133 | if has_open_canopy { 134 | write!( 135 | stdout, 136 | "\x1B[32mFound\x1B[0m OpenCanopy.efi Enabled in UEFI->Drivers\r\n" 137 | )?; 138 | res::get_or_update_local_parent( 139 | "OcBinaryData", 140 | &resources.other, 141 | "release", 142 | &0, 143 | true, 144 | true, 145 | stdout, 146 | false, 147 | )?; 148 | let canopy_language = resources.octool_config["canopy_language"] 149 | .as_str() 150 | .unwrap_or("en"); 151 | let mut lang = "_".to_string(); 152 | lang.push_str(&canopy_language); 153 | lang.push('_'); 154 | let input_resources = 155 | Path::new(resources.input_dir_path.file_name().unwrap()).join("Resources"); 156 | let in_path = Path::new("resources/OcBinaryData/Resources"); 157 | let out_path = Path::new("OUTPUT/EFI/OC/Resources"); 158 | for res in &["Audio", "Font", "Image", "Label"] { 159 | let mut entries: Vec = Default::default(); 160 | let mut res_source = "".to_owned(); 161 | if input_resources.join(&res).exists() { 162 | for r in fs::read_dir(input_resources.join(res))? { 163 | entries.push(r?.path()); 164 | } 165 | res_source = format!( 166 | "\x1b[33m{}/Resources\x1b[0m", 167 | resources 168 | .input_dir_path 169 | .file_name() 170 | .unwrap() 171 | .to_str() 172 | .unwrap() 173 | ); 174 | } 175 | if entries.len() == 0 { 176 | for r in fs::read_dir(in_path.join(res))? { 177 | entries.push(r?.path()); 178 | } 179 | res_source = "OcBinaryData".to_owned(); 180 | } 181 | // only use selected language if using OcBinaryData as input source, otherwise do not 182 | // modify the source list at all 183 | if res == &"Audio" && res_source == "OcBinaryData" { 184 | entries.retain(|p| p.to_str().unwrap().contains(&lang)); 185 | let f = Path::new("resources/OcBinaryData/Resources/Audio"); 186 | for file in resources.octool_config["global_audio_files"] 187 | .as_array() 188 | .unwrap() 189 | { 190 | entries.push(f.join(file.as_str().unwrap())); 191 | } 192 | } 193 | let mut s = ""; 194 | if entries.len() > 1 { 195 | s = "s"; 196 | }; 197 | write!( 198 | stdout, 199 | "\x1B[32mCopying\x1B[0m {} {} resource{} from {} ... ", 200 | entries.len(), 201 | res, 202 | s, 203 | res_source 204 | )?; 205 | stdout.flush()?; 206 | fs_extra::copy_items(&entries, out_path.join(res), &options)?; 207 | write!(stdout, "\x1B[32mDone\x1B[0m\r\n")?; 208 | stdout.flush()?; 209 | } 210 | write!(stdout, "\r\n")?; 211 | stdout.flush()?; 212 | } 213 | 214 | match resources.config_plist.as_dictionary().unwrap()["Misc"] 215 | .as_dictionary() 216 | .unwrap()["Security"] 217 | .as_dictionary() 218 | .unwrap()["Vault"] 219 | .as_string() 220 | .unwrap() 221 | { 222 | "Basic" => { 223 | write!( 224 | stdout, 225 | "\x1B[32mFound\x1B[0m Misc->Security->Vault set to Basic\r\n" 226 | )?; 227 | if std::env::consts::OS == "macos" { 228 | compute_vault_plist(resources, stdout)?; 229 | } else { 230 | write!(stdout, "\x1b[33mWARNING:\tcan only build vault files on macOS at this time\r\n\ 231 | \trun octool on macOS to build vault files, or set Vault to \x1b[4mOptional\x1b[0;33m \ 232 | for now.\x1b[0m\r\n")?; 233 | build_okay = false; 234 | } 235 | } 236 | "Secure" => { 237 | write!( 238 | stdout, 239 | "\x1B[32mFound\x1B[0m Misc->Security->Vault set to Secure\r\n" 240 | )?; 241 | if std::env::consts::OS == "macos" { 242 | compute_vault_plist(resources, stdout)?; 243 | write!(stdout, "\x1b[32mSigning\x1B[0m OpenCore.efi ... ")?; 244 | stdout.flush()?; 245 | let out = status("strings", &["-a", "-t", "d", "OUTPUT/EFI/OC/OpenCore.efi"])?; 246 | let mut offset = 0; 247 | for line in String::from_utf8(out.stdout).unwrap().lines() { 248 | let (off, s) = line.split_once(' ').unwrap(); 249 | if s == "=BEGIN OC VAULT=" { 250 | offset = off.parse::().unwrap() + 16; 251 | } 252 | } 253 | let mut seek = "seek=".to_string(); 254 | seek.push_str(&offset.to_string()); 255 | let _ = status( 256 | "dd", 257 | &[ 258 | "of=OUTPUT/EFI/OC/OpenCore.efi", 259 | "if=OUTPUT/EFI/OC/vault.pub", 260 | "bs=1", 261 | &seek, 262 | "count=528", 263 | "conv=notrunc", 264 | ], 265 | ); 266 | std::fs::remove_file("OUTPUT/EFI/OC/vault.pub")?; 267 | write!(stdout, "\x1B[32mDone\x1B[0m\r\n\n")?; 268 | } else { 269 | write!(stdout, "\x1b[33mWARNING:\tcan only build vault files on macOS at this time\r\n\ 270 | \trun octool on macOS to build vault files, or set Vault to \x1b[4mOptional\x1b[0;33m \ 271 | for now.\x1b[0m\r\n")?; 272 | build_okay = false; 273 | } 274 | stdout.flush()?; 275 | } 276 | _ => (), 277 | } 278 | 279 | if missing_files.len() > 0 { 280 | write!( 281 | stdout, 282 | "\x1B[31;7mWARNING:\x1B[0m the following file(s) are missing or unknown by octool\x1B[33m\r\n" 283 | )?; 284 | for f in missing_files.iter() { 285 | write!(stdout, "{}\x1B[0K\r\n", f)?; 286 | } 287 | write!( 288 | stdout, 289 | "\x1B[31mIf you want octool to include them automatically,\r\n\ 290 | they need to be placed in the \x1B[32m{}\x1B[31m folder before building.\r\n\ 291 | If you feel octool should know this file, then there may be an issue with the\r\n\ 292 | resources folder. You can delete that folder and try running octool again.\r\n\ 293 | Otherwise, they will need to be placed into your EFI manually\x1B[0m\r\n\n", 294 | resources 295 | .input_dir_path 296 | .file_name() 297 | .unwrap() 298 | .to_str() 299 | .unwrap() 300 | )?; 301 | stdout.flush()?; 302 | } 303 | Ok(build_okay) 304 | } 305 | 306 | fn compute_vault_plist(resources: &Resources, stdout: &mut Stdout) -> Result<(), Box> { 307 | write!(stdout, "\x1B[32mComputing\x1B[0m vault.plist ... ")?; 308 | stdout.flush()?; 309 | let _ = status( 310 | &resources 311 | .open_core_binaries_path 312 | .join("Utilities/CreateVault/create_vault.sh") 313 | .to_str() 314 | .unwrap(), 315 | &["OUTPUT/EFI/OC/."], 316 | ); 317 | let _ = status( 318 | &resources 319 | .open_core_binaries_path 320 | .join("Utilities/CreateVault/RsaTool") 321 | .to_str() 322 | .unwrap(), 323 | &[ 324 | "-sign", 325 | "OUTPUT/EFI/OC/vault.plist", 326 | "OUTPUT/EFI/OC/vault.sig", 327 | "OUTPUT/EFI/OC/vault.pub", 328 | ], 329 | ); 330 | write!(stdout, "\x1B[32mDone\x1B[0m\r\n")?; 331 | stdout.flush()?; 332 | Ok(()) 333 | } 334 | -------------------------------------------------------------------------------- /src/draw.rs: -------------------------------------------------------------------------------- 1 | use plist::Value; 2 | 3 | use std::error::Error; 4 | use std::io::{Stdout, Write}; 5 | 6 | use crate::edit::read_key; 7 | use crate::init::Settings; 8 | use crate::parse_tex; 9 | use crate::res::{self, Resources}; 10 | 11 | use crossterm::cursor::position; 12 | use crossterm::event::KeyCode; 13 | use crossterm::terminal::size; 14 | 15 | /// Redraws the plist on the screen 16 | /// Draws the Footer first, in case it needs to be overwritten 17 | /// Draws the plist next with current selection expanded 18 | /// This allows the currently highlighted item info to be obtained 19 | /// so any special comments can be included in the Header 20 | /// which is drawn last 21 | pub fn update_screen( 22 | settings: &mut Settings, 23 | resources: &Resources, 24 | stdout: &mut Stdout, 25 | ) -> Result<(), Box> { 26 | let plist = &resources.config_plist; 27 | let screen_rows: i32 = size().unwrap().1.into(); 28 | settings.can_expand = false; 29 | // let bgc = &settings.bg_col.clone(); 30 | let bgc = "\x1b[0m"; 31 | 32 | // draw footer first, in case we need to write over it 33 | write!(stdout, "\x1B[{}H", screen_rows - 1)?; 34 | write!( 35 | stdout, 36 | " {inv}D{res}/{inv}^x{res}cut {inv}^c{res}op{inv}y{res} {inv}^v{res}/{inv}p{res}aste {inv}f{res}ind {inv}n{res}ext \ 37 | {inv}a{res}dd {inv}d{res}el {inv}M{res}erge {inv}P{res}urge {inv}r{res}eset {inv}O{res}rder(Kernel>Add)\x1B[0K\r\n {inv}s{res}ave\ 38 | +validate {inv}q{res}uit {inv}G{res}o build EFI {inv}K{res}ey {inv}I{res}nsert {inv}{red} {grn} {res}boolean {inv}{mag} {res}data {inv}{blu} \ 39 | {res}integer {inv} {res}string\x1B[0K", 40 | inv = "\x1b[7m", 41 | // res = &settings.bg_col, 42 | res = "\x1b[0m", 43 | grn = "\x1b[32m", 44 | red = "\x1b[31m", 45 | mag = "\x1b[35m", 46 | blu = "\x1b[34m", 47 | )?; 48 | 49 | // jump under header, draw plist 50 | write!(stdout, "\x1B[3H")?; 51 | let mut row_being_drawn = 4; 52 | let list = plist.as_dictionary().unwrap(); 53 | let keys: Vec = list.keys().map(|s| s.to_string()).collect(); 54 | for (i, k) in keys.iter().enumerate() { 55 | if row_being_drawn < screen_rows { 56 | row_being_drawn += display_value( 57 | k, 58 | k, 59 | None, 60 | settings, 61 | resources, 62 | list.get(k).unwrap(), 63 | stdout, 64 | i, 65 | 0, 66 | false, 67 | ) 68 | .unwrap(); 69 | } 70 | } 71 | 72 | #[cfg(debug_assertions)] 73 | write!( 74 | stdout, 75 | "debug-> {:?} {} {:?} array? {} {:?} {:?}", 76 | settings.sec_length, 77 | settings.depth, 78 | settings.sec_num, 79 | settings.inside_an_array, 80 | settings.sec_key, 81 | settings.raw_sec_key, 82 | )?; 83 | 84 | let mut blanks = screen_rows - row_being_drawn - 1; 85 | if blanks < 0 { 86 | blanks = 0; 87 | } 88 | 89 | // clear rows up to footer 90 | write!(stdout, "{}", "\r\n\x1B[0K".repeat(blanks as usize))?; 91 | 92 | // lastly draw the header 93 | let mut info = String::new(); 94 | settings.res_name(&mut info); 95 | if info.len() > 20 { 96 | info = info[0..17].to_string(); 97 | info.push_str("..."); 98 | } 99 | info = highlight_non_print("\x1b[4m", &info, true); 100 | write!( 101 | stdout, 102 | "\x1b[1;{}H\x1b[2KOC \x1b[7mV{}ersion {}", 103 | (size().unwrap().0 - 16).to_string(), 104 | // &settings.bg_col, 105 | "\x1b[0m", 106 | settings.oc_build_version, 107 | ) 108 | .unwrap(); 109 | write!( 110 | stdout, 111 | "\x1B[H{}{} \x1B[0;7mi{}nfo for {}{}\r\n\x1B[0K", 112 | "\x1b[32m", &settings.config_file_name, bgc, &info, bgc, 113 | ) 114 | .unwrap(); 115 | if settings.depth > 0 { 116 | write!(stdout, " \x1B[7mleft{} collapse", bgc).unwrap(); 117 | } 118 | write!(stdout, "{}", settings.item_instructions,).unwrap(); 119 | if settings.depth == 2 { 120 | if settings.is_resource() { 121 | write!(stdout, " \x1B[7mspace{} toggle", bgc).unwrap(); 122 | } 123 | } 124 | if settings.find_string.len() > 0 { 125 | write!( 126 | stdout, 127 | " \x1B[7mn{} jump to next {}{}{}", 128 | bgc, "\x1b[4m", settings.find_string, bgc, 129 | ) 130 | .unwrap(); 131 | } 132 | if settings.held_key.len() > 0 { 133 | write!( 134 | stdout, 135 | " {}p{}aste {}{}{}", 136 | "\x1b[7m", bgc, "\x1b[4m", settings.held_key, bgc, 137 | ) 138 | .unwrap(); 139 | } 140 | write!(stdout, "\r\n\x1B[2K\x1B8",).unwrap(); 141 | Ok(()) 142 | } 143 | 144 | fn display_value( 145 | key: &String, 146 | raw_key: &String, 147 | key_color: Option, 148 | settings: &mut Settings, 149 | resources: &Resources, 150 | plist_value: &Value, 151 | stdout: &mut Stdout, 152 | item_num: usize, 153 | display_depth: usize, 154 | is_array_key: bool, 155 | ) -> Result> { 156 | let mut live_item = false; 157 | let mut selected_item = false; 158 | let mut save_curs_pos = String::new(); 159 | let mut key_style = String::new(); 160 | let mut pre_key = '>'; 161 | let mut row = 1; 162 | // let bgc = &settings.bg_col.clone(); 163 | let bgc = "\x1b[0m"; 164 | write!(stdout, "\r\n{}\x1B[0K", " ".repeat(display_depth))?; // indent to section and clear rest of line 165 | if settings.sec_num[display_depth] == item_num { 166 | selected_item = true; 167 | settings.sec_key[display_depth] = key.to_string(); 168 | settings.raw_sec_key[display_depth] = raw_key.to_string(); 169 | key_style.push_str("\x1B[7m"); 170 | // is current live item 171 | if display_depth == settings.depth { 172 | live_item = true; 173 | settings.item_instructions = match plist_value { 174 | Value::Array(_) | Value::Dictionary(_) => " \x1B[7mright\x1B[0m expand", 175 | Value::Integer(_) | Value::String(_) | Value::Data(_) => { 176 | " \x1B[7menter\x1B[0m edit" 177 | } 178 | Value::Boolean(_) => " \x1B[7mspace\x1B[0m toggle", 179 | _ => " XXXunknownXXX", 180 | } 181 | .to_string(); 182 | save_curs_pos = "\x1B7".to_string(); // save cursor position for editing and info display 183 | } 184 | } 185 | match plist_value { 186 | Value::Array(v) => { 187 | if selected_item { 188 | settings.sec_length[display_depth + 1] = v.len(); 189 | } 190 | if live_item { 191 | settings.can_expand = true; 192 | settings.live_value.clear(); 193 | } 194 | if settings.depth > display_depth && settings.sec_num[display_depth] == item_num { 195 | // we have an open array 196 | pre_key = 'v'; 197 | if settings.depth == display_depth + 1 { 198 | // we are in the first level of an array 199 | settings.inside_an_array = true; 200 | } 201 | } 202 | write!( 203 | stdout, 204 | "{} {}\x1B[0m [{}]{} ", 205 | pre_key, 206 | highlight_non_print(&key_style, key, is_array_key), 207 | v.len(), 208 | save_curs_pos 209 | )?; 210 | if settings.depth > display_depth && settings.sec_num[display_depth] == item_num { 211 | if v.len() == 0 { 212 | write!( 213 | stdout, 214 | "\r\n\x1B[0K{}\x1B[7mempty{}{}", 215 | " ".repeat(display_depth + 1), 216 | bgc, 217 | save_curs_pos 218 | ) 219 | .unwrap(); 220 | row += 1; 221 | } else { 222 | let mut key = String::new(); 223 | let mut raw_key = String::new(); 224 | for i in 0..v.len() { 225 | let color = get_array_key(&mut key, &mut raw_key, &v[i], i); 226 | row += display_value( 227 | &key, 228 | &raw_key, 229 | color, 230 | settings, 231 | resources, 232 | &v[i], 233 | stdout, 234 | i, 235 | display_depth + 1, 236 | true, 237 | )?; 238 | } 239 | } 240 | } 241 | } 242 | Value::Boolean(v) => { 243 | match v { 244 | true => key_style.push_str("\x1b[32m"), 245 | false => key_style.push_str("\x1b[31m"), 246 | }; 247 | write!( 248 | stdout, 249 | "{}{}: {}{}", 250 | highlight_non_print(&key_style, key, is_array_key), 251 | bgc, 252 | save_curs_pos, 253 | v 254 | ) 255 | .unwrap(); 256 | /* true => write!( 257 | stdout, 258 | "{}\x1b[32m{}{}: {}{}", 259 | key_style, safe_key(&key_style, key), bgc, save_curs_pos, v 260 | ) 261 | .unwrap(), 262 | false => write!( 263 | stdout, 264 | "{}\x1b[31m{}{}: {}{}", 265 | key_style, safe_key(&key_style, key), bgc, save_curs_pos, v 266 | ) 267 | .unwrap(), 268 | };*/ 269 | if live_item { 270 | settings.live_value = v.to_string(); 271 | } 272 | } 273 | Value::Data(v) => { 274 | key_style.push_str("\x1b[35m"); 275 | write!( 276 | stdout, 277 | "{}{}: <{}{}> | \"{}\"\x1B[0K", 278 | highlight_non_print(&key_style, key, is_array_key), 279 | bgc, 280 | save_curs_pos, 281 | hex_str_with_style(hex::encode(&*v)), 282 | get_lossy_string(v), 283 | )?; 284 | if live_item { 285 | settings.live_value = hex::encode(&*v).to_string(); 286 | } 287 | } 288 | Value::Dictionary(v) => { 289 | if selected_item { 290 | settings.sec_length[display_depth + 1] = v.keys().len(); 291 | } 292 | if live_item { 293 | settings.can_expand = true; 294 | settings.live_value.clear(); 295 | } 296 | if settings.depth > display_depth && settings.sec_num[display_depth] == item_num { 297 | pre_key = 'v'; 298 | } 299 | match key_color { 300 | Some(true) => key_style.push_str("\x1b[32m"), 301 | Some(false) => key_style.push_str("\x1b[31m"), 302 | None => (), 303 | }; 304 | write!( 305 | stdout, 306 | "{} {}{} {} [{}]{} ", 307 | pre_key, 308 | highlight_non_print(&key_style, key, is_array_key), 309 | bgc, 310 | if display_depth == 2 { 311 | let mut sec_sub = settings.sec_key[0].clone(); 312 | sec_sub.push_str(&settings.sec_key[1]); 313 | if settings.resource_sections.contains(&sec_sub) { 314 | match res::res_version(settings, &resources, &key) { 315 | Some(s) => s, 316 | None => " \x1b[33m∆\x1b[0m ".to_string(), 317 | } 318 | } else { 319 | "".to_string() 320 | } 321 | } else { 322 | "".to_string() 323 | }, 324 | v.len(), 325 | save_curs_pos 326 | ) 327 | .unwrap(); 328 | if settings.depth > display_depth && settings.sec_num[display_depth] == item_num { 329 | if v.keys().len() == 0 { 330 | write!( 331 | stdout, 332 | "\r\n\x1B[0K{}\x1B[7mempty{}{}", 333 | " ".repeat(display_depth + 1), 334 | bgc, 335 | save_curs_pos 336 | ) 337 | .unwrap(); 338 | row += 1; 339 | } else { 340 | let keys: Vec = v.keys().map(|s| s.to_string()).collect(); 341 | for (i, k) in keys.iter().enumerate() { 342 | row += display_value( 343 | &k, 344 | &k, 345 | None, 346 | settings, 347 | resources, 348 | v.get(&k).unwrap(), 349 | stdout, 350 | i, 351 | display_depth + 1, 352 | false, 353 | )?; 354 | } 355 | } 356 | } 357 | } 358 | Value::Integer(v) => { 359 | key_style.push_str("\x1b[34m"); 360 | write!( 361 | stdout, 362 | "{}{}: {}{}", 363 | highlight_non_print(&key_style, key, is_array_key), 364 | bgc, 365 | save_curs_pos, 366 | v 367 | )?; 368 | if live_item { 369 | settings.live_value = v.to_string(); 370 | } 371 | } 372 | Value::String(v) => { 373 | write!( 374 | stdout, 375 | "{:>2}{}: {}{}", 376 | highlight_non_print(&key_style, key, is_array_key), 377 | bgc, 378 | save_curs_pos, 379 | highlight_non_print("", v, true), 380 | )?; 381 | if live_item { 382 | settings.live_value = v.to_string(); 383 | } 384 | } 385 | _ => panic!("Can't handle this type"), 386 | } 387 | Ok(row) 388 | } 389 | 390 | pub fn get_lossy_string(v: &Vec) -> String { 391 | let mut tmp = String::new(); 392 | for c in v { 393 | if c < &32 || c > &126 { 394 | tmp.push('\u{fffd}'); 395 | } else { 396 | tmp.push(*c as char); 397 | } 398 | } 399 | tmp 400 | } 401 | 402 | fn get_array_key( 403 | key: &mut String, 404 | raw_key: &mut String, 405 | v: &plist::Value, 406 | i: usize, 407 | ) -> Option { 408 | match v { 409 | Value::Dictionary(d) => { 410 | *key = i.to_string(); 411 | *raw_key = i.to_string(); 412 | 413 | for k in ["Path", "BundlePath", "Name", "Comment"] { 414 | if d.contains_key(k) { 415 | *key = d.get(k).unwrap().clone().into_string().unwrap(); 416 | break; // stop after first match 417 | } 418 | // } else { 419 | // *key = "".to_string(); 420 | // } 421 | } 422 | 423 | // if key.len() == 0 { 424 | // *key = i.to_string(); 425 | // } 426 | match d.get("Enabled") { 427 | Some(Value::Boolean(b)) => { 428 | return Some(*b); 429 | } 430 | _ => (), 431 | } 432 | 433 | match d.get("Load") { 434 | Some(Value::String(s)) => { 435 | if *s == "Disabled" { 436 | return Some(false); 437 | } else { 438 | return Some(true); 439 | } 440 | } 441 | _ => (), 442 | } 443 | } 444 | _ => *key = i.to_string(), 445 | } 446 | None 447 | } 448 | 449 | pub fn hex_str_with_style(v: String) -> String { 450 | let mut hex_u = String::new(); 451 | let mut col = v.len() % 2; 452 | for c in v.chars() { 453 | if col > 1 { 454 | hex_u.push_str("\x1b[100;97m"); 455 | // hex_u.push_str("\x1b[35m"); 456 | hex_u.push(c); 457 | hex_u.push_str("\x1b[0m"); 458 | } else { 459 | hex_u.push(c); 460 | } 461 | col += 1; 462 | if col > 3 { 463 | col = 0; 464 | }; 465 | } 466 | hex_u 467 | } 468 | 469 | pub fn highlight_non_print(key_style: &str, key: &str, mut allow_space: bool) -> String { 470 | if key.chars().nth(0) == Some('#') { 471 | allow_space = true; 472 | } 473 | let mut ret_key = String::new(); 474 | ret_key.push_str(key_style); 475 | for c in key.chars() { 476 | match c { 477 | ' ' => { 478 | if allow_space { 479 | ret_key.push(' '); 480 | } else { 481 | ret_key.push_str("\x1b[7m\x1b[33m \x1b[0m"); 482 | ret_key.push_str(key_style); 483 | } 484 | } 485 | c if c.is_ascii_graphic() => ret_key.push(c), 486 | // c if c.is_alphanumeric() => ret_key.push(c), 487 | _ => { 488 | ret_key.push_str("\x1b[7m\x1b[33m"); 489 | ret_key.push('\u{fffd}'); 490 | ret_key.push_str("\x1b[0m"); 491 | ret_key.push_str(key_style); 492 | } 493 | } 494 | } 495 | ret_key 496 | } 497 | 498 | /// Read through the Configuration.tex and display the info for the highlighted plist item 499 | /// 500 | /// TODO: keep highlighted item on screen so it can be edited while looking at definition 501 | pub fn show_info( 502 | resources: &Resources, 503 | settings: &Settings, 504 | gather_valid: bool, 505 | stdout: &mut Stdout, 506 | ) -> Result> { 507 | let mut showing_info = true; 508 | let rows = size()?.1; 509 | let mut row = 0; 510 | 511 | let tex_path = &resources 512 | .open_core_source_path 513 | .join("Docs/Configuration.tex"); 514 | let mut hit_bottom = false; 515 | 516 | let mut search_str = vec![]; 517 | for a in 0..=settings.depth { 518 | search_str.push(settings.raw_sec_key[a].to_owned()); 519 | // search_str.push(settings.sec_key[a].to_owned()); 520 | } 521 | let width = size().unwrap().0 as i32; 522 | let result = parse_tex::parse_configuration( 523 | tex_path, 524 | search_str, 525 | width, 526 | gather_valid, 527 | settings.show_info_url, 528 | ); 529 | 530 | write!( 531 | stdout, 532 | "{}\x1b[4m{}\x1b8\r\x1b[4m{}\r\n\x1b[0m", 533 | &settings.live_value, 534 | " ".repeat(size()?.0.into()), 535 | " ".repeat(settings.depth), 536 | )?; 537 | row += 1; 538 | 539 | let mut start = 0; 540 | loop { 541 | for i in start..result.len() { 542 | write!(stdout, "\x1b[0K{}", result[i])?; 543 | row += 1; 544 | if row == rows { 545 | if row == result.len() as u16 + 1 { 546 | break; 547 | } else { 548 | hit_bottom = true; 549 | } 550 | if i == result.len() - 1 { 551 | write!( 552 | stdout, 553 | "{}END{} ... 'q' to quit\x1B[G", 554 | "\x1b[7m", &settings.bg_col_info, 555 | )?; 556 | } else { 557 | write!(stdout, "\x1b[7mmore{} ...\x1B[G", &settings.bg_col_info)?; 558 | } 559 | stdout.flush()?; 560 | match read_key().unwrap().0 { 561 | KeyCode::Char('q') | KeyCode::Char('i') | KeyCode::Esc => { 562 | hit_bottom = false; 563 | showing_info = false; 564 | break; 565 | } 566 | KeyCode::Down => { 567 | if i < result.len() - 1 { 568 | row -= 1; 569 | start += 1; 570 | if start > result.len() - rows as usize { 571 | start = result.len() - rows as usize; 572 | } 573 | } else { 574 | row = 0; 575 | } 576 | } 577 | KeyCode::Up => { 578 | row = 0; 579 | if start > 0 { 580 | start -= 1; 581 | } 582 | write!(stdout, "\x1B[1H")?; 583 | break; 584 | } 585 | KeyCode::Char('b') => { 586 | if start > rows as usize { 587 | start -= rows as usize; 588 | } else { 589 | start = 0; 590 | } 591 | row = 0; 592 | write!(stdout, "\x1B[1H")?; 593 | break; 594 | } 595 | _ => { 596 | row = 0; 597 | if i < result.len() - 1 { 598 | start += rows as usize; 599 | if start > result.len() - rows as usize { 600 | start = result.len() - rows as usize; 601 | } 602 | } 603 | break; 604 | } 605 | } 606 | } 607 | } 608 | if !hit_bottom { 609 | break; 610 | } 611 | } 612 | // } 613 | write!(stdout, "\x1b[4m{}\x1B[0K", " ".repeat(size()?.0.into()))?; 614 | write!(stdout, "\x1B8")?; 615 | stdout.flush()?; 616 | let bump_position = row + position()?.1 + 1; 617 | if bump_position > rows { 618 | write!( 619 | stdout, 620 | "\x1B8{}\x1B7", 621 | "\x1B[A".repeat(bump_position as usize - rows as usize) 622 | )?; 623 | } 624 | stdout.flush()?; 625 | Ok(showing_info) 626 | } 627 | -------------------------------------------------------------------------------- /src/edit.rs: -------------------------------------------------------------------------------- 1 | use crate::draw; 2 | use crate::edit; 3 | use crate::init::Settings; 4 | use crate::res::Resources; 5 | 6 | use crossterm::event::KeyModifiers; 7 | use plist::{Integer, Value}; 8 | 9 | use std::{ 10 | error::Error, 11 | i64, 12 | io::{Stdout, Write}, 13 | }; 14 | 15 | use crossterm::{ 16 | cursor, 17 | event::{self, Event, KeyCode}, 18 | style, 19 | }; 20 | 21 | #[derive(Debug)] 22 | pub struct Found { 23 | pub level: usize, 24 | pub section: [usize; 5], 25 | pub keys: Vec, 26 | } 27 | 28 | impl Found { 29 | pub fn new() -> Found { 30 | Found { 31 | level: 0, 32 | section: [0; 5], 33 | keys: vec![], 34 | } 35 | } 36 | } 37 | 38 | pub fn read_key() -> crossterm::Result<(KeyCode, KeyModifiers)> { 39 | loop { 40 | if let Event::Key(key) = event::read()? { 41 | return Ok((key.code, key.modifiers)); 42 | } 43 | } 44 | } 45 | 46 | /// find the current highlighted item in the given 'plist_val' plist 47 | /// and place it into the settings. held_item and held_key 48 | /// if 'first' is true get the first key of a dict or item 0 of an array 49 | /// if 'preserve' is true do not clear the held values to their defaults 50 | pub fn extract_value( 51 | settings: &mut Settings, 52 | mut plist_val: &Value, 53 | first: bool, 54 | preserve: bool, 55 | ) -> bool { 56 | let mut extracted = true; 57 | for i in 0..settings.depth { 58 | match plist_val { 59 | Value::Dictionary(d) => { 60 | plist_val = match d.get(&settings.sec_key[i]) { 61 | Some(k) => k, 62 | None => return false, 63 | } 64 | } 65 | Value::Array(a) => { 66 | plist_val = a.get(0).expect("No 0 element in Sample.plist"); 67 | } 68 | _ => (), 69 | } 70 | } 71 | match plist_val { 72 | Value::Dictionary(d) => { 73 | let key = if first { 74 | d.keys().next().expect("Didn't get first key").clone() 75 | } else { 76 | settings.sec_key[settings.depth].clone() 77 | }; 78 | match d.get(&key) { 79 | Some(v) => { 80 | settings.held_item = Some(v.to_owned()); 81 | settings.held_key = key.to_owned(); 82 | } 83 | None => extracted = false, 84 | }; 85 | } 86 | Value::Array(a) => { 87 | let num = if first { 88 | 0 89 | } else { 90 | settings.sec_num[settings.depth] 91 | }; 92 | if num < a.len() { 93 | let mut ex_item = a.get(num).unwrap().to_owned(); 94 | match ex_item.as_dictionary_mut() { 95 | Some(d) => { 96 | if !preserve { 97 | for val in d.values_mut() { 98 | match val { 99 | Value::String(_) => *val = Value::String("".to_string()), 100 | Value::Boolean(_) => *val = Value::Boolean(false), 101 | Value::Integer(_) => { 102 | *val = Value::Integer(plist::Integer::from(0)) 103 | } 104 | Value::Data(_) => *val = Value::Data(Default::default()), 105 | _ => (), 106 | } 107 | } 108 | } 109 | settings.held_item = Some(ex_item); 110 | settings.held_key = settings.sec_key[settings.depth].clone(); 111 | } 112 | None => settings.held_item = Some(ex_item), // not a dict in an array, return element "num" 113 | } 114 | } else { 115 | extracted = false; 116 | } 117 | } 118 | _ => extracted = false, // not a dict or array 119 | } 120 | extracted 121 | } 122 | 123 | /// if 'add' is true, 124 | /// place the settings.held_item into the given 'plist_val' plist at the highlighted location 125 | /// if 'add' is false 126 | /// delete the highlighted value from the given 'plist_val' plist and place it in the settings.held_item 127 | /// 128 | pub fn add_delete_value(settings: &mut Settings, mut plist_val: &mut Value, add: bool) -> bool { 129 | let mut changed = false; 130 | for i in 0..settings.depth { 131 | match plist_val { 132 | Value::Dictionary(d) => { 133 | plist_val = match d.get_mut(&settings.sec_key[i]) { 134 | Some(k) => k, 135 | None => return false, 136 | } 137 | } 138 | Value::Array(a) => { 139 | plist_val = a.get_mut(settings.sec_num[i]).unwrap(); 140 | } 141 | _ => (), 142 | } 143 | } 144 | match plist_val { 145 | Value::Dictionary(d) => { 146 | if add { 147 | if d.contains_key(&settings.held_key) { 148 | settings 149 | .held_key 150 | .insert_str(settings.held_key.len(), "-copy"); 151 | } 152 | match settings.held_item.clone() { 153 | Some(item) => { 154 | if d.insert(settings.held_key.to_owned(), item) == None { 155 | changed = true; 156 | } 157 | } 158 | None => (), 159 | } 160 | } else { 161 | settings.held_item = Some(d.remove(&settings.sec_key[settings.depth]).unwrap()); 162 | settings.held_key = settings.sec_key[settings.depth].to_owned(); 163 | changed = true; 164 | } 165 | d.sort_keys(); 166 | if changed { 167 | settings.sec_num[settings.depth] = 168 | d.keys().position(|k| k == &settings.held_key).unwrap_or(0); 169 | }; 170 | } 171 | Value::Array(a) => { 172 | if add { 173 | match settings.held_item.clone() { 174 | Some(item) => { 175 | a.insert(settings.sec_num[settings.depth], item); 176 | changed = true; 177 | } 178 | None => (), 179 | } 180 | } else { 181 | settings.held_item = Some(a.remove(settings.sec_num[settings.depth])); 182 | settings.held_key = settings.sec_key[settings.depth].to_owned(); 183 | changed = true; 184 | } 185 | } 186 | _ => (), 187 | } 188 | changed 189 | } 190 | 191 | /// ask for a search string and give a scrollable list of locations to jump to in 'found' 192 | /// if only 1 result is found, jump immediately 193 | pub fn find(find_string: &str, resource: &plist::Value, found: &mut Vec) { 194 | if find_string.len() > 0 { 195 | let search = find_string.to_lowercase(); 196 | let resource = resource.as_dictionary().unwrap(); 197 | for (i, key) in resource.keys().enumerate() { 198 | let low_key = key.to_lowercase(); 199 | if low_key.contains(&search) { 200 | found.push(Found { 201 | level: 0, 202 | section: [i, 0, 0, 0, 0], 203 | keys: vec![key.to_owned()], 204 | }); 205 | } 206 | match resource.get(key).unwrap().as_dictionary() { 207 | Some(sub) => { 208 | for (j, s_key) in sub.keys().enumerate() { 209 | let low_key = s_key.to_lowercase(); 210 | if low_key.contains(&search) { 211 | found.push(Found { 212 | level: 1, 213 | section: [i, j, 0, 0, 0], 214 | keys: vec![key.to_owned(), s_key.to_owned()], 215 | }); 216 | } 217 | let sub_sub = sub.get(s_key).unwrap(); 218 | match sub_sub { 219 | plist::Value::Dictionary(d) => { 220 | for (k, s_s_key) in d.keys().enumerate() { 221 | let low_key = s_s_key.to_lowercase(); 222 | if low_key.contains(&search) { 223 | found.push(Found { 224 | level: 2, 225 | section: [i, j, k, 0, 0], 226 | keys: vec![ 227 | key.to_owned(), 228 | s_key.to_owned(), 229 | s_s_key.to_owned(), 230 | ], 231 | }); 232 | } 233 | match d.get(s_s_key).unwrap() { 234 | plist::Value::Dictionary(sub_d) => { 235 | for (l, sub_d_key) in sub_d.keys().enumerate() { 236 | let low_key = sub_d_key.to_lowercase(); 237 | if low_key.contains(&search) { 238 | found.push(Found { 239 | level: 3, 240 | section: [i, j, k, l, 0], 241 | keys: vec![ 242 | key.to_owned(), 243 | s_key.to_owned(), 244 | s_s_key.to_owned(), 245 | sub_d_key.to_owned(), 246 | ], 247 | }); 248 | } 249 | } 250 | } 251 | _ => (), 252 | } // end match d 253 | } 254 | } 255 | plist::Value::Array(a) => { 256 | for (k, v) in a.iter().enumerate() { 257 | match v { 258 | plist::Value::Dictionary(d) => { 259 | for (l, s_s_key) in d.keys().enumerate() { 260 | let low_key = s_s_key.to_lowercase(); 261 | if low_key.contains(&search) { 262 | found.push(Found { 263 | level: 3, 264 | section: [i, j, k, l, 0], 265 | keys: vec![ 266 | key.to_owned(), 267 | s_key.to_owned(), 268 | k.to_string(), 269 | s_s_key.to_owned(), 270 | ], 271 | }); 272 | } 273 | } 274 | } 275 | _ => (), 276 | } // end match v 277 | } 278 | } 279 | 280 | _ => (), 281 | } // end match sub_sub 282 | } 283 | } 284 | _ => (), 285 | } // end match resource 286 | } 287 | } 288 | } 289 | 290 | /// add an item of a user selected type to the loaded config.plist as the highlighted 291 | /// location. If the highlighted location is inside a section that holds resources 292 | /// e.g. Kexts, Drivers, etc. then give an option to insert a blank template made from 293 | /// the format in the corresponding Sample.plist 294 | /// setting auto_add to a resource name will automatically add that resource then return 295 | pub fn add_item( 296 | mut settings: &mut Settings, 297 | resources: &mut Resources, 298 | auto_add: &str, 299 | stdout: &mut Stdout, 300 | ) { 301 | settings.modified = true; 302 | let mut selection = 1; 303 | let mut selection_adjust = 0; 304 | let mut item_types = Vec::::new(); 305 | let mut res_list = vec![]; 306 | let mut res_type = ""; 307 | let mut res_ext = ""; 308 | if settings.is_resource() { 309 | match settings.sec_key[0].as_str() { 310 | "ACPI" => { 311 | res_ext = ".aml"; 312 | res_type = "acpi"; 313 | } 314 | "Kernel" => { 315 | res_ext = ".kext"; 316 | res_type = "kext"; 317 | } 318 | "Misc" => { 319 | res_ext = ".efi"; 320 | res_type = "tool"; 321 | } 322 | "UEFI" => { 323 | res_ext = ".efi"; 324 | res_type = "driver"; 325 | } 326 | _ => (), 327 | }; 328 | for res in resources.resource_list.as_object().unwrap() { 329 | if res.0.contains(res_ext) { 330 | if res_ext == ".efi" { 331 | if res.1["res_type"] == res_type { 332 | res_list.push(res.0.clone()); 333 | } 334 | } else { 335 | res_list.push(res.0.clone()); 336 | } 337 | } 338 | } 339 | res_list.sort(); 340 | let msg = format!("Select new {} from a list", res_type,); 341 | item_types.push(msg); 342 | selection_adjust += 1; 343 | } 344 | if settings.inside_an_array && settings.depth == 2 { 345 | let msg = format!( 346 | "New {} > {} template from Sample.plist", 347 | settings.sec_key[0], settings.sec_key[1] 348 | ); 349 | selection_adjust += 1; 350 | item_types.push(msg); 351 | } 352 | for s in [ 353 | "plist array", 354 | "plist boolean", 355 | "plist data", 356 | "plist dict", 357 | "plist integer", 358 | "plist string", 359 | ] { 360 | item_types.push(s.to_owned()); 361 | } 362 | if auto_add.len() == 0 { 363 | write!( 364 | stdout, 365 | "\r\n\x1b[32mSelect type of item to add to plist:\x1b[0m\x1B[0K\r\n\x1b[0K\r\n{}", 366 | cursor::SavePosition, 367 | ) 368 | .unwrap(); 369 | loop { 370 | write!(stdout, "\x1B8").unwrap(); 371 | for (i, item_type) in item_types.iter().enumerate() { 372 | if i == selection - 1 { 373 | write!(stdout, "\x1B[7m").unwrap(); 374 | } 375 | write!(stdout, "{}\x1B[0m\x1B[0K\r\n", item_type).unwrap(); 376 | } 377 | write!(stdout, "\x1B[2K").unwrap(); 378 | stdout.flush().unwrap(); 379 | match read_key().unwrap().0 { 380 | KeyCode::Up => { 381 | if selection > 1 { 382 | selection -= 1; 383 | } 384 | } 385 | KeyCode::Down => { 386 | if selection < item_types.len() { 387 | selection += 1; 388 | } 389 | } 390 | KeyCode::Enter => break, 391 | KeyCode::Esc => { 392 | selection = 0; 393 | break; 394 | } 395 | _ => (), 396 | } 397 | } 398 | if selection == 0 { 399 | return; 400 | }; 401 | } else { 402 | selection = 1; 403 | selection_adjust = 2; 404 | } 405 | // if selection_adjust > 1 && selection < 3 { 406 | if selection <= selection_adjust { 407 | if selection == 1 && selection_adjust == 2 { 408 | let new_val_set; 409 | let mut selected_res = res_list[0].clone(); 410 | if auto_add.len() == 0 { 411 | write!( 412 | stdout, 413 | "{}{}\r\x1B[2KSelect or edit {} to insert: {}\r\n\x1B[2K\x1B8", 414 | cursor::RestorePosition, 415 | cursor::Show, 416 | res_type, 417 | cursor::SavePosition, 418 | ) 419 | .unwrap(); 420 | new_val_set = 421 | edit::edit_string(&mut selected_res, Some(&res_list), stdout).unwrap(); 422 | write!(stdout, "{}", cursor::Hide).unwrap(); 423 | } else { 424 | new_val_set = true; 425 | selected_res = auto_add.to_owned(); 426 | } 427 | if !new_val_set { 428 | return; 429 | } 430 | if !extract_value(&mut settings, &resources.sample_plist, true, false) { 431 | return; 432 | } 433 | let item = settings.held_item.as_mut().unwrap(); 434 | match res_type { 435 | "acpi" => { 436 | item.as_dictionary_mut() 437 | .unwrap() 438 | .insert("Path".to_string(), plist::Value::String(selected_res)); 439 | item.as_dictionary_mut() 440 | .unwrap() 441 | .insert("Enabled".to_string(), plist::Value::Boolean(true)); 442 | } 443 | "driver" => { 444 | if settings.oc_build_version > "0.7.2".to_string() { 445 | item.as_dictionary_mut() 446 | .unwrap() 447 | .insert("Path".to_string(), plist::Value::String(selected_res)); 448 | item.as_dictionary_mut() 449 | .unwrap() 450 | .insert("Enabled".to_string(), plist::Value::Boolean(true)); 451 | } else { 452 | settings.held_item = Some(plist::Value::String(selected_res)); 453 | } 454 | } 455 | "kext" => { 456 | let item = item.as_dictionary_mut().unwrap(); 457 | item.insert("Arch".to_string(), plist::Value::String("Any".to_string())); 458 | item.insert( 459 | "BundlePath".to_string(), 460 | plist::Value::String(selected_res.clone()), 461 | ); 462 | let mut ex_path = "Contents/MacOS/".to_string(); 463 | ex_path.push_str(selected_res.split('.').next().unwrap()); 464 | item.insert("ExecutablePath".to_string(), plist::Value::String(ex_path)); 465 | item.insert( 466 | "PlistPath".to_string(), 467 | plist::Value::String("Contents/Info.plist".to_string()), 468 | ); 469 | item.insert("Enabled".to_string(), plist::Value::Boolean(true)); 470 | } 471 | "tool" => { 472 | let item = item.as_dictionary_mut().unwrap(); 473 | item.insert("Path".to_string(), plist::Value::String(selected_res)); 474 | item.insert( 475 | "Flavour".to_string(), 476 | plist::Value::String("Auto".to_string()), 477 | ); 478 | item.insert("Enabled".to_string(), plist::Value::Boolean(true)); 479 | } 480 | _ => (), 481 | }; 482 | } else { 483 | if !extract_value(&mut settings, &resources.sample_plist, true, false) { 484 | return; 485 | } 486 | } 487 | } else { 488 | write!( 489 | stdout, 490 | "Enter key for new {} item: {}{}\x1B[0K\r\n\x1B[2K", 491 | item_types[selection - 1], 492 | cursor::SavePosition, 493 | cursor::Show 494 | ) 495 | .unwrap(); 496 | stdout.flush().unwrap(); 497 | let mut key = String::new(); 498 | edit_string(&mut key, None, stdout).unwrap(); 499 | settings.held_key = String::from(key.trim()); 500 | settings.held_item = Some(match selection - selection_adjust { 501 | 1 => plist::Value::Array(vec![]), 502 | 2 => false.into(), 503 | 3 => plist::Value::Data(vec![]), 504 | 4 => plist::Value::Dictionary(plist::Dictionary::default()), 505 | 5 => 0.into(), 506 | 6 => plist::Value::String("".to_string()), 507 | _ => panic!("How did you select this?"), 508 | }); 509 | write!(stdout, "{}", cursor::Hide).unwrap(); 510 | } 511 | if add_delete_value(settings, &mut resources.config_plist, true) { 512 | settings.add(); 513 | } 514 | } 515 | 516 | /// edit the highlighted value in the loaded config.plist 517 | /// 518 | /// ``` 519 | /// space_pressed: bool // was space pressed to get here, if so, toggle value 520 | /// edit_key: bool // edit the key name of the field, not the value in the field 521 | /// 522 | /// ``` 523 | pub fn edit_value( 524 | settings: &mut Settings, 525 | mut val: &mut Value, 526 | valid_values: Option<&Vec>, 527 | stdout: &mut Stdout, 528 | space_pressed: bool, 529 | edit_key: bool, 530 | ) -> Result<(), Box> { 531 | write!( 532 | stdout, 533 | "{}\x1B[H\x1B[0K\r\n\x1B[0K {inv}enter{res} save changes {inv}esc{res} cancel changes\x1b[H", 534 | cursor::Show, 535 | inv = style::Attribute::Reverse, 536 | res = style::Attribute::Reset, 537 | )?; 538 | let mut search_depth = settings.depth + 1; 539 | if edit_key { 540 | search_depth -= 1; 541 | } 542 | for i in 0..search_depth { 543 | match val { 544 | Value::Dictionary(d) => { 545 | let key = d.keys().map(|s| s.to_string()).collect::>() 546 | [settings.sec_num[i]] 547 | .clone(); 548 | val = match d.get_mut(&key) { 549 | Some(k) => k, 550 | None => panic!("failure to get Value from Dict"), 551 | }; 552 | } 553 | Value::Array(a) => { 554 | val = a.get_mut(settings.sec_num[i]).unwrap(); 555 | } 556 | _ => (), 557 | } 558 | } 559 | 560 | if space_pressed { 561 | match val { 562 | Value::Boolean(b) => *b = !*b, 563 | Value::Dictionary(d) => match d.get_mut("Enabled") { 564 | Some(Value::Boolean(b)) => *b = !*b, 565 | _ => (), 566 | }, 567 | Value::String(s) => { 568 | if settings.is_resource() { 569 | if s.chars().next() == Some('#') { 570 | s.remove(0); 571 | } else { 572 | s.insert(0, '#'); 573 | } 574 | } 575 | } 576 | _ => (), 577 | } 578 | } else if edit_key { 579 | match val { 580 | Value::Dictionary(d) => { 581 | let mut key = settings.sec_key[search_depth].to_owned(); 582 | let hold = d.remove(&key); 583 | match hold { 584 | Some(v) => { 585 | write!(stdout, "\x1B8\r{}| \x1B7", " ".repeat(settings.depth))?; 586 | edit_string(&mut key, valid_values, stdout)?; 587 | d.insert(key.clone(), v); 588 | d.sort_keys(); 589 | settings.sec_num[settings.depth] = 590 | d.keys().position(|k| k == &key).unwrap_or(0); 591 | } 592 | None => (), 593 | } 594 | } 595 | _ => (), 596 | } 597 | } else { 598 | match val { 599 | Value::Integer(i) => { 600 | edit_int(i, valid_values, stdout); 601 | } 602 | Value::String(s) => { 603 | edit_string(s, valid_values, stdout)?; 604 | } 605 | Value::Data(d) => { 606 | edit_data(d, stdout)?; 607 | } 608 | _ => (), 609 | } 610 | } 611 | 612 | write!(stdout, "{}", cursor::Hide)?; 613 | settings.modified = true; 614 | Ok(()) 615 | } 616 | 617 | fn edit_data(val: &mut Vec, stdout: &mut Stdout) -> Result<(), Box> { 618 | let mut edit_hex = hex::encode(val.clone()); 619 | let mut pos = edit_hex.len(); 620 | let mut hexedit = true; 621 | write!( 622 | stdout, 623 | "edit {und}plist data{res} {inv}tab{res} switch between editing by hex or string", 624 | und = style::Attribute::Underlined, 625 | inv = style::Attribute::Reverse, 626 | res = style::Attribute::Reset, 627 | ) 628 | .unwrap(); 629 | // let mut keys = std::io::stdin().keys(); 630 | loop { 631 | let mut tmp_val = edit_hex.clone(); 632 | if tmp_val.len() % 2 == 1 { 633 | tmp_val.insert(0, '0'); 634 | } 635 | let tmp_val = hex::decode(tmp_val).unwrap(); 636 | write!( 637 | stdout, 638 | "\x1B8\x1B[G{mag}as hex{res}\x1B8{}\x1B[0K\x1B[E{mag}as string\x1B[0K\x1B8\x1B[B\x1B[4m{}\x1B8", 639 | draw::hex_str_with_style(edit_hex.clone()), 640 | draw::get_lossy_string(&tmp_val), 641 | mag = "\x1b[35m", 642 | res = style::Attribute::Reset, 643 | )?; 644 | if hexedit { 645 | write!( 646 | stdout, 647 | "\x1B[G{}{}as hex{}\x1B8{}", 648 | "\x1b[7m", 649 | "\x1b[35m", 650 | "\x1b[0m", 651 | "\x1B[C".repeat(pos) 652 | )?; 653 | } else { 654 | write!( 655 | stdout, 656 | "\x1B[E{}{}as string{}\x1B8\x1B[B{}", 657 | "\x1b[7m", 658 | "\x1b[35m", 659 | "\x1b[0m", 660 | "\x1B[C".repeat(pos / 2) 661 | )?; 662 | } 663 | stdout.flush()?; 664 | match read_key().unwrap().0 { 665 | KeyCode::Enter => { 666 | *val = tmp_val; 667 | break; 668 | } 669 | KeyCode::Backspace => { 670 | if edit_hex.len() > 0 { 671 | if pos > 0 { 672 | let _ = edit_hex.remove(pos - 1); 673 | pos -= 1; 674 | if !hexedit { 675 | let _ = edit_hex.remove(pos - 1); 676 | pos -= 1; 677 | } 678 | } 679 | } 680 | } 681 | KeyCode::Tab | KeyCode::Up | KeyCode::Down => { 682 | if hexedit { 683 | if edit_hex.len() % 2 == 1 { 684 | edit_hex.insert(0, '0'); 685 | } 686 | if pos % 2 == 1 { 687 | pos += 1; 688 | } 689 | } 690 | hexedit = !hexedit; 691 | } 692 | KeyCode::Delete => { 693 | if edit_hex.len() > 0 { 694 | if pos < edit_hex.len() { 695 | let _ = edit_hex.remove(pos); 696 | if !hexedit { 697 | let _ = edit_hex.remove(pos); 698 | } 699 | } 700 | } 701 | } 702 | KeyCode::Left => { 703 | if pos > 0 { 704 | pos -= 1; 705 | if !hexedit { 706 | pos -= 1; 707 | } 708 | } 709 | } 710 | KeyCode::Right => { 711 | if pos < edit_hex.len() { 712 | pos += 1; 713 | if !hexedit { 714 | pos += 1; 715 | } 716 | } 717 | } 718 | KeyCode::Char(c) => { 719 | if hexedit { 720 | if c.is_ascii_hexdigit() { 721 | edit_hex.insert(pos, c); 722 | pos += 1; 723 | } 724 | } else { 725 | if c.is_ascii() { 726 | for ic in hex::encode(vec![c as u8]).chars() { 727 | edit_hex.insert(pos, ic); 728 | pos += 1; 729 | } 730 | } 731 | } 732 | } 733 | KeyCode::Home => pos = 0, 734 | KeyCode::End => pos = edit_hex.len(), 735 | KeyCode::Esc => break, 736 | _ => (), 737 | } 738 | } 739 | Ok(()) 740 | } 741 | 742 | fn edit_int(val: &mut Integer, valid_values: Option<&Vec>, stdout: &mut Stdout) { 743 | let mut new_int = val.as_signed().unwrap(); 744 | let mut selected = 0; 745 | let mut hit_space = false; 746 | let mut new = new_int.to_string(); 747 | write!( 748 | stdout, 749 | "edit {und}plist integer{res}", 750 | und = style::Attribute::Underlined, 751 | res = style::Attribute::Reset, 752 | ) 753 | .unwrap(); 754 | loop { 755 | if let Some(valid_values) = valid_values { 756 | write!( 757 | stdout, 758 | " directly or {inv}up{res}/{inv}down{res} select {inv}space{res} toggle bit", 759 | inv = style::Attribute::Reverse, 760 | res = style::Attribute::Reset, 761 | ) 762 | .unwrap(); 763 | let mut hex_val; 764 | write!(stdout, "\x1b8\r\n\x1B[2K\r\n").unwrap(); 765 | for (i, vals) in valid_values.iter().enumerate() { 766 | if i == selected { 767 | write!(stdout, "\x1b[7m").unwrap(); 768 | } 769 | hex_val = vals.split("---").next().unwrap().trim().to_owned(); 770 | if hex_val.contains(' ') { 771 | hex_val = hex_val.split(" ").next().unwrap().trim().to_owned(); 772 | } 773 | if hex_val.len() > 2 && &hex_val[..2] == "0x" { 774 | let dec_val = i64::from_str_radix(&hex_val[2..], 16).unwrap(); 775 | if dec_val & new_int == dec_val { 776 | write!(stdout, "\x1b[32m").unwrap(); 777 | if hit_space && i == selected { 778 | new_int -= dec_val; 779 | new = new_int.to_string(); 780 | hit_space = false; 781 | write!(stdout, "\x1b[31m").unwrap(); 782 | } 783 | } else { 784 | write!(stdout, "\x1b[31m").unwrap(); 785 | if hit_space && i == selected { 786 | new_int += dec_val; 787 | new = new_int.to_string(); 788 | hit_space = false; 789 | write!(stdout, "\x1b[32m").unwrap(); 790 | } 791 | } 792 | } 793 | write!(stdout, "{}\x1b[0m\x1B[0K\r\n", vals).unwrap(); 794 | } 795 | write!(stdout, "\x1B[2K\r\n").unwrap(); 796 | } 797 | write!(stdout, "\x1B8{}\x1B[0K", new).unwrap(); 798 | stdout.flush().unwrap(); 799 | 800 | match read_key().unwrap().0 { 801 | KeyCode::Enter => { 802 | *val = match new.parse::() { 803 | Ok(i) => Integer::from(i), 804 | _ => Integer::from(0), 805 | }; 806 | break; 807 | } 808 | KeyCode::Backspace => { 809 | if new.len() > 0 { 810 | let _ = new.pop().unwrap(); 811 | } 812 | if new.len() == 0 { 813 | new_int = 0; 814 | } else if &new != "-" { 815 | new_int = new.parse::().unwrap(); 816 | } 817 | } 818 | KeyCode::Char(' ') => hit_space = true, 819 | KeyCode::Char(c @ '0'..='9') => { 820 | new.push(c); 821 | new_int = match new.parse::() { 822 | Ok(int) => int, 823 | Err(_) => { 824 | new.pop(); 825 | write!(stdout, " \x1b[33mERROR:\x1b[0m int value exceeded").unwrap(); 826 | stdout.flush().unwrap(); 827 | read_key().unwrap(); 828 | new.parse::().unwrap() 829 | } 830 | }; 831 | } 832 | KeyCode::Char('-') => { 833 | if new.len() == 0 { 834 | new.push('-'); 835 | } 836 | } 837 | KeyCode::Up => { 838 | if selected > 0 { 839 | selected -= 1; 840 | } 841 | } 842 | KeyCode::Down => { 843 | if let Some(valid_values) = valid_values { 844 | if selected < valid_values.len() - 1 { 845 | selected += 1; 846 | } 847 | } 848 | } 849 | KeyCode::Esc => break, 850 | _ => (), 851 | }; 852 | } 853 | } 854 | 855 | pub fn edit_string( 856 | val: &mut String, 857 | valid_values: Option<&Vec>, 858 | stdout: &mut Stdout, 859 | ) -> Result> { 860 | let mut new_val_set = false; 861 | let mut new = String::from(&*val); 862 | let mut pos = new.len(); 863 | let mut selected = 0; 864 | write!( 865 | stdout, 866 | "edit {und}plist string{res}", 867 | und = style::Attribute::Underlined, 868 | res = style::Attribute::Reset, 869 | ) 870 | .unwrap(); 871 | if let Some(valid_values) = valid_values { 872 | write!( 873 | stdout, 874 | " directly or {inv}up{res}/{inv}down{res} select", 875 | inv = style::Attribute::Reverse, 876 | res = style::Attribute::Reset, 877 | ) 878 | .unwrap(); 879 | selected = valid_values.len(); 880 | if valid_values.len() > 0 { 881 | for (i, vals) in valid_values.iter().enumerate() { 882 | if vals.split("---").next().unwrap().trim() == &new { 883 | selected = i; 884 | } 885 | } 886 | } 887 | } 888 | loop { 889 | if let Some(valid_values) = valid_values { 890 | if valid_values.len() > 0 { 891 | write!(stdout, "\x1b8\r\n\x1B[2K\r\n").unwrap(); 892 | for (i, vals) in valid_values.iter().enumerate() { 893 | if (selected < 5 && i < 10) 894 | || (selected >= 5 && i + 5 >= selected && i < selected + 5) 895 | { 896 | if i == selected { 897 | write!(stdout, "\x1b[7m").unwrap(); 898 | } 899 | write!(stdout, "{}\x1b[0m\x1B[0K\r\n\x1b[2K", vals).unwrap(); 900 | } else if i > 10 { 901 | write!(stdout, "\r").unwrap(); 902 | } 903 | } 904 | write!(stdout, "\n\x1B[2K\r\n").unwrap(); 905 | } 906 | } 907 | write!( 908 | stdout, 909 | "\x1B8{}\x1B[0K", 910 | draw::highlight_non_print("\x1b[4m", &new, true) 911 | )?; 912 | write!(stdout, "\x1B8{}", "\x1B[C".repeat(pos))?; 913 | stdout.flush()?; 914 | match read_key().unwrap().0 { 915 | KeyCode::Enter => { 916 | *val = new; 917 | new_val_set = true; 918 | break; 919 | } 920 | KeyCode::Backspace => { 921 | if new.len() > 0 { 922 | if pos > 0 { 923 | let _ = new.remove(pos - 1); 924 | pos -= 1; 925 | } 926 | } 927 | } 928 | KeyCode::Delete => { 929 | if new.len() > 0 { 930 | if pos < new.len() { 931 | let _ = new.remove(pos); 932 | } 933 | } 934 | } 935 | KeyCode::Up => { 936 | if selected > 0 { 937 | selected -= 1; 938 | if let Some(valid_values) = valid_values { 939 | new = valid_values[selected] 940 | .split("---") 941 | .next() 942 | .unwrap() 943 | .trim() 944 | .to_owned(); 945 | pos = new.len(); 946 | } 947 | } 948 | } 949 | KeyCode::Down => { 950 | if let Some(valid_values) = valid_values { 951 | if selected < valid_values.len() - 1 { 952 | selected += 1; 953 | } 954 | if selected == valid_values.len() { 955 | selected = 0; 956 | } 957 | new = valid_values[selected] 958 | .split("---") 959 | .next() 960 | .unwrap() 961 | .trim() 962 | .to_owned(); 963 | pos = new.len(); 964 | } 965 | } 966 | KeyCode::Left => { 967 | if pos > 0 { 968 | pos -= 1; 969 | } 970 | } 971 | KeyCode::Right => { 972 | if pos < new.len() { 973 | pos += 1; 974 | } 975 | } 976 | KeyCode::Char(c) => { 977 | if c.is_ascii() { 978 | new.insert(pos, c); 979 | pos += 1; 980 | } 981 | } 982 | KeyCode::Home => pos = 0, 983 | KeyCode::End => pos = new.len(), 984 | KeyCode::Esc => break, 985 | _ => (), 986 | }; 987 | } 988 | Ok(new_val_set) 989 | } 990 | -------------------------------------------------------------------------------- /src/init.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fs::File; 3 | use std::io::{BufReader, Stdout, Write}; 4 | use std::path::{Path, PathBuf}; 5 | 6 | use plist::Value; 7 | 8 | use crate::edit::{find, Found}; 9 | use crate::res::{self, Resources}; 10 | 11 | use crossterm::terminal; 12 | 13 | use std::collections::HashMap; 14 | 15 | #[derive(Debug, Default)] 16 | pub struct Manifest(pub usize, pub String); 17 | 18 | #[derive(Debug, Default)] 19 | pub struct Settings { 20 | pub config_file_name: String, // name of config.plist 21 | pub sec_num: [usize; 5], // selected section for each depth 22 | pub depth: usize, // depth of plist section we are looking at 23 | pub sec_key: [String; 5], // key of selected section 24 | pub raw_sec_key: [String; 5], // raw key of selected section, e.g. plain array #s 25 | pub item_instructions: String, // item instructions for display in header 26 | pub held_item: Option, // last deleted or placed item value 27 | pub held_key: String, // last deleted or placed key 28 | pub live_value: String, // current value of highlighted key 29 | pub sec_length: [usize; 5], // number of items in current section 30 | pub resource_sections: Vec, // concat name of sections that contain resources 31 | pub build_type: String, // building release or debug version 32 | pub oc_build_version: String, // version number of OpenCorePkg to use 33 | pub oc_build_date: String, // date binaries were built 34 | pub oc_build_version_res_index: usize, // index of OpenCorePkg in config.json 35 | pub resource_ver_indexes: HashMap, // index of other parent resources 36 | pub can_expand: bool, // true if highlighted field can have children 37 | pub find_string: String, // last entered search string 38 | pub modified: bool, // true if plist changed and not saved 39 | pub bg_col: String, // colors for standard display 40 | pub bg_col_info: String, // background color for info display 41 | pub octool_version: String, // octool version being used 42 | pub show_info_url: bool, // display full url link in the info screens 43 | pub inside_an_array: bool, // true if current selection is inside an array 44 | } 45 | 46 | impl Settings { 47 | pub fn up(&mut self) { 48 | if self.sec_num[self.depth] > 0 { 49 | self.sec_num[self.depth] -= 1; 50 | } 51 | } 52 | pub fn down(&mut self) { 53 | if self.sec_length[self.depth] > 0 { 54 | if self.sec_num[self.depth] < self.sec_length[self.depth] - 1 { 55 | self.sec_num[self.depth] += 1; 56 | } 57 | } 58 | } 59 | pub fn left(&mut self) { 60 | if self.depth > 0 { 61 | self.sec_key[self.depth].clear(); 62 | self.depth -= 1; 63 | } 64 | self.inside_an_array = false; 65 | } 66 | pub fn right(&mut self) { 67 | if self.depth < 4 && self.can_expand { 68 | self.depth += 1; 69 | self.sec_num[self.depth] = 0; 70 | } 71 | self.inside_an_array = false; 72 | } 73 | pub fn add(&mut self) { 74 | self.sec_length[self.depth] += 1; 75 | self.modified = true; 76 | } 77 | pub fn delete(&mut self) { 78 | if self.sec_length[self.depth] > 0 { 79 | self.sec_length[self.depth] -= 1; 80 | } 81 | if self.sec_num[self.depth] == self.sec_length[self.depth] { 82 | self.up(); 83 | } 84 | self.modified = true; 85 | } 86 | /// return true if current selected item is a resource 87 | pub fn is_resource(&self) -> bool { 88 | if self.depth != 2 { 89 | false 90 | } else { 91 | let mut sec_sub = self.sec_key[0].clone(); 92 | sec_sub.push_str(&self.sec_key[1]); 93 | self.resource_sections.contains(&sec_sub) 94 | } 95 | } 96 | /// strip resource name from full path 97 | pub fn res_name(&self, name: &mut String) { 98 | *name = self.sec_key[self.depth] 99 | .to_owned() 100 | .split('/') 101 | .last() 102 | .unwrap() 103 | .to_string(); 104 | } 105 | } 106 | 107 | /// load static resources into resources struct, shouldn't need to change even if user 108 | /// changes opencore build version on the fly 109 | pub fn init_static( 110 | resources: &mut Resources, 111 | settings: &mut Settings, 112 | stdout: &mut Stdout, 113 | ) -> Result<(), Box> { 114 | //load other resource file 115 | resources.other = res::get_serde_json("tool_config_files/other.json", stdout)?; 116 | 117 | // build resource section vector 118 | let config_res_sections: Vec<(String, String, String, String)> = 119 | serde_json::from_value(resources.octool_config["resource_sections"].clone()).unwrap(); 120 | for (mut sec, sub, _, _) in config_res_sections { 121 | sec.push_str(&sub); 122 | settings.resource_sections.push(sec); 123 | } 124 | 125 | //load resources list file 126 | resources.resource_list = res::get_serde_json("tool_config_files/resource_list.json", stdout)?; 127 | 128 | //load dortania build_repo package 129 | write!( 130 | stdout, 131 | "\r\n\x1B[32mChecking\x1B[0m local dortania/build_repo/config.json ... " 132 | )?; 133 | let path = Path::new( 134 | resources.octool_config["dortania_config_path"] 135 | .as_str() 136 | .unwrap(), 137 | ); 138 | let url = resources.octool_config["dortania_config_zip"] 139 | .as_str() 140 | .unwrap(); 141 | if !path.exists() { 142 | write!( 143 | stdout, 144 | "\x1b[32mNot found\r\nDownloading\x1B[0m latest config.json ... " 145 | )?; 146 | stdout.flush().unwrap(); 147 | let path = path.parent().unwrap().join("builds.zip"); 148 | res::curl_file(&url, &path)?; 149 | let z_file = std::fs::File::open(&path)?; 150 | let mut z_archive = zip::ZipArchive::new(z_file)?; 151 | match z_archive.extract(&path.parent().unwrap()) { 152 | Ok(_) => std::fs::remove_file(&path)?, 153 | Err(e) => panic!("{:?}", e), 154 | } 155 | write!(stdout, "\x1b[32mDone\x1b[0m\r\n")? 156 | } else { 157 | let path = path.parent().unwrap(); 158 | let mut old_size = 0; 159 | let mut current_size = 1; 160 | let file_path = &path.join("build-repo-builds").join("size.json"); 161 | if file_path.exists() { 162 | let size_file = File::open(&file_path)?; 163 | let buf = BufReader::new(size_file); 164 | let size: serde_json::Value = serde_json::from_reader(buf)?; 165 | old_size = size["tree"][0]["size"].as_i64().unwrap_or(0); 166 | current_size = res::curl_build_size(&file_path)?; 167 | } else { 168 | let _ = res::curl_build_size(&file_path)?; 169 | } 170 | #[cfg(debug_assertions)] 171 | { 172 | write!( 173 | stdout, 174 | "debug: old {} current {}\r\n", 175 | old_size, current_size 176 | )?; 177 | } 178 | 179 | if old_size != current_size { 180 | write!( 181 | stdout, 182 | "\x1b[32mNew version found\r\nDownloading\x1B[0m latest config.json ... " 183 | )?; 184 | stdout.flush().unwrap(); 185 | let path = path.join("builds.zip"); 186 | res::curl_file(&url, &path)?; 187 | let z_file = std::fs::File::open(&path)?; 188 | let mut z_archive = zip::ZipArchive::new(z_file)?; 189 | match z_archive.extract(&path.parent().unwrap()) { 190 | Ok(_) => std::fs::remove_file(&path)?, 191 | Err(e) => panic!("{:?}", e), 192 | } 193 | write!(stdout, "\x1b[32mDone\x1b[0m\r\n")? 194 | } else if old_size == 0 { 195 | write!( 196 | stdout, 197 | "\x1b[31mWARNING\x1b[0m\r\nCould not retrieve config.json info from Github API at this time.\r\n" 198 | )?; 199 | } else { 200 | write!(stdout, "\x1b[32mAlready up to date\r\n")?; 201 | } 202 | }; 203 | resources.dortania = res::get_serde_json(path.join("config.json").to_str().unwrap(), stdout)?; 204 | 205 | Ok(()) 206 | } 207 | 208 | /// load OpenCore binary packages and support files based on the version of 209 | /// OpenCore that is selected, will change resources used on the fly if user 210 | /// uses the 'V' command to change OC version # 211 | pub fn init_oc_build( 212 | resources: &mut Resources, 213 | settings: &mut Settings, 214 | stdout: &mut Stdout, 215 | ) -> Result<(), Box> { 216 | settings.oc_build_version_res_index = Default::default(); // reset oc_build_version to top of dortania 217 | // settings.resource_ver_indexes = Default::default(); // this will clear out resource version indexes for dortania 218 | 219 | // test if version selected is latest version, don't try to download zip of latest 220 | // it doesn't exist yet 221 | let latest_ver = resources.dortania["OpenCorePkg"]["versions"][0]["version"] 222 | .as_str() 223 | .unwrap(); 224 | if latest_ver == &settings.oc_build_version { 225 | settings.oc_build_version = "latest".to_owned(); 226 | } 227 | 228 | if settings.oc_build_version == "latest" { 229 | settings.oc_build_version = resources.dortania["OpenCorePkg"]["versions"][0]["version"] 230 | .as_str() 231 | .unwrap() 232 | .to_owned(); 233 | let path = Path::new( 234 | resources.octool_config["opencorepkg_path"] 235 | .as_str() 236 | .unwrap(), 237 | ); 238 | resources.open_core_source_path = Path::new(&path).to_path_buf(); 239 | let path = path.join("Docs"); 240 | if !path.exists() { 241 | std::fs::create_dir_all(&path)?; 242 | } 243 | let url = resources.octool_config["current_configuration_tex"] 244 | .as_str() 245 | .unwrap(); 246 | res::curl_file(&url, &path.join(&url.split('/').last().unwrap()))?; 247 | let url = resources.octool_config["current_sample_plist"] 248 | .as_str() 249 | .unwrap(); 250 | res::curl_file(&url, &path.join(&url.split('/').last().unwrap()))?; 251 | } else { 252 | loop { 253 | if let Some(v) = resources.dortania["OpenCorePkg"]["versions"] 254 | [settings.oc_build_version_res_index]["version"] 255 | .as_str() 256 | { 257 | if v == settings.oc_build_version { 258 | break; 259 | } 260 | } else { 261 | write!( 262 | stdout, 263 | "\r\n\x1b[33mERROR:\x1b[0m Version \x1b[32m{}\x1b[0m of OpenCorePkg not found in repos, please check your input\x1b[0K\r\n\x1b[0K\ne.g. './octool -o \x1b[4m0.7.4\x1b[0m'\x1b[0K\n", 264 | settings.oc_build_version 265 | ) 266 | .unwrap(); 267 | settings.oc_build_version = "not found".to_owned(); 268 | return Ok(()); 269 | } 270 | settings.oc_build_version_res_index += 1; 271 | } 272 | let mut path = "resources/OpenCorePkg-".to_owned(); 273 | path.push_str(&settings.oc_build_version); 274 | resources.open_core_source_path = Path::new(&path).to_path_buf(); 275 | path.push_str(".zip"); 276 | let path = Path::new(&path).to_path_buf(); 277 | 278 | let mut url = "https://github.com/acidanthera/OpenCorePkg/archive/refs/tags/".to_owned(); 279 | url.push_str(&settings.oc_build_version); 280 | url.push_str(".zip"); 281 | write!( 282 | stdout, 283 | "\x1B[32mChecking\x1B[0m OpenCorePkg {} source\r\n", 284 | settings.oc_build_version 285 | )?; 286 | if !resources.open_core_source_path.exists() { 287 | write!( 288 | stdout, 289 | "\x1B[32mDownloading\x1B[0m OpenCorePkg {} source from Acidanthera ... ", 290 | settings.oc_build_version 291 | )?; 292 | stdout.flush()?; 293 | res::get_file_and_unzip(&url, "", &path, stdout, false)?; 294 | write!(stdout, "\x1B[32mDone\x1B[0m\r\n")?; 295 | } else { 296 | write!(stdout, "Already up to date\r\n")?; 297 | } 298 | } 299 | 300 | //this will always set the build index to the top value for the particular opencore version 301 | //selected, this will currently override any manifest setting for which sha to use 302 | settings.resource_ver_indexes.insert( 303 | "OpenCorePkg".to_owned(), 304 | Manifest( 305 | settings.oc_build_version_res_index, 306 | resources.dortania["OpenCorePkg"]["versions"][settings.oc_build_version_res_index] 307 | ["commit"]["sha"] 308 | .as_str() 309 | .unwrap_or("") 310 | .to_string(), 311 | ), 312 | ); 313 | settings.oc_build_date = resources.dortania["OpenCorePkg"]["versions"] 314 | [settings.oc_build_version_res_index]["date_built"] 315 | .as_str() 316 | .unwrap_or("") 317 | .to_owned(); 318 | 319 | let sample_plist = &resources.open_core_source_path.join("Docs/Sample.plist"); 320 | resources.sample_plist = Value::from_file(sample_plist) 321 | .expect(format!("Didn't find Sample.plist at {:?}", sample_plist).as_str()); 322 | 323 | write!( 324 | stdout, 325 | "\r\n\x1B[32mChecking\x1B[0m local OpenCorePkg {} binaries ... \x1b[32m", 326 | settings.oc_build_version 327 | )?; 328 | let path = res::get_or_update_local_parent( 329 | "OpenCorePkg", 330 | &resources.dortania, 331 | &settings.build_type, 332 | &settings.resource_ver_indexes.get("OpenCorePkg").unwrap().0, 333 | true, 334 | true, 335 | stdout, 336 | false, 337 | )?; 338 | 339 | match path { 340 | Some(p) => resources.open_core_binaries_path = p.parent().unwrap().to_path_buf(), 341 | _ => panic!("no OpenCorePkg found"), 342 | } 343 | 344 | Ok(()) 345 | } 346 | 347 | /// load config.plist or use a Sample.plist if no valid INPUT plist given 348 | /// and run plist through ocvalidate 349 | pub fn init_plist( 350 | config_plist: &mut PathBuf, 351 | resources: &mut Resources, 352 | settings: &mut Settings, 353 | stdout: &mut Stdout, 354 | ) -> Result<(), Box> { 355 | if !config_plist.exists() { 356 | *config_plist = resources 357 | .open_core_source_path 358 | .join("Docs/Sample.plist") 359 | .to_owned(); 360 | resources.config_plist = Value::from_file(&config_plist) 361 | .expect(format!("Didn't find valid plist at {:?}", config_plist).as_str()); 362 | } 363 | 364 | write!( 365 | stdout, 366 | "\n\x1B[32mValidating\x1B[0m {:?} with {} acidanthera/ocvalidate\r\n", 367 | config_plist, settings.oc_build_version, 368 | )?; 369 | validate_plist(&config_plist, &resources, stdout)?; 370 | 371 | //finish configuring settings 372 | settings.config_file_name = config_plist.to_str().unwrap().to_owned(); 373 | settings.sec_length[0] = resources.config_plist.as_dictionary().unwrap().keys().len(); 374 | let mut found_key = false; 375 | let keys: Vec = resources 376 | .config_plist 377 | .as_dictionary() 378 | .unwrap() 379 | .keys() 380 | .map(|s| s.to_string()) 381 | .collect(); 382 | for (i, k) in keys.iter().enumerate() { 383 | if !found_key { 384 | //highlight first key that is not commented out # 385 | if !k.starts_with('#') { 386 | settings.sec_num[0] = i; 387 | found_key = true; 388 | } 389 | } 390 | } 391 | 392 | Ok(()) 393 | } 394 | 395 | /// run loaded config.plist through the corresponding ocvalidate utility if it 396 | /// exists (no ocvalidate before oc 0.6.0, may be no ocvalidate available depending 397 | /// on what OS is currently being run) 398 | pub fn validate_plist( 399 | config_plist: &PathBuf, 400 | resources: &Resources, 401 | stdout: &mut Stdout, 402 | ) -> Result> { 403 | let mut config_okay = true; 404 | let ocvalidate_bin = resources 405 | .open_core_binaries_path 406 | .join("Utilities/ocvalidate") 407 | .join(match std::env::consts::OS { 408 | "macos" => "ocvalidate", 409 | "windows" => "ocvalidate.exe", 410 | "linux" => "ocvalidate.linux", 411 | _ => "ocvalidate", 412 | }); 413 | if ocvalidate_bin.exists() { 414 | let out = res::status( 415 | ocvalidate_bin.to_str().unwrap(), 416 | &[&config_plist.to_str().unwrap()], 417 | )?; 418 | terminal::disable_raw_mode()?; 419 | 420 | write!(stdout, "{}\r\n", String::from_utf8(out.stdout).unwrap())?; 421 | terminal::enable_raw_mode()?; 422 | 423 | if out.status.code().unwrap() != 0 { 424 | config_okay = false; 425 | write!( 426 | stdout, 427 | "\x1B[31mERROR: Problems(s) found in config.plist!\x1B[0m\r\n" 428 | )?; 429 | write!(stdout, "{}\r\n", String::from_utf8(out.stderr).unwrap())?; 430 | } 431 | } else { 432 | write!( 433 | stdout, 434 | "\r\n{:?}\r\n\x1b[33mocvalidate utility not found, skipping.\x1b[0m\r\n", 435 | ocvalidate_bin, 436 | )?; 437 | } 438 | Ok(config_okay) 439 | } 440 | 441 | /// run through vec of "config_differences" from tool_config_files/octool_config.json 442 | /// if the current config.plist being worked on contains the field in the vec then 443 | /// it is most likely to be the correct version of OpenCore 444 | pub fn guess_version(resources: &Resources) -> (String, bool) { 445 | let mut found = vec![Found::new()]; 446 | let config_differences: Vec<(String, String, String, String)> = 447 | serde_json::from_value(resources.config_differences["config_differences"].clone()).unwrap(); 448 | 449 | let mut first_diff = true; 450 | for (sec, sub, search, ver) in config_differences { 451 | find(&search, &resources.config_plist, &mut found); 452 | for result in &found { 453 | if result.keys.contains(&sec) && result.keys.contains(&sub) { 454 | return (ver.to_owned(), first_diff); 455 | } 456 | } 457 | first_diff = false; 458 | } 459 | ("".to_string(), false) 460 | } 461 | -------------------------------------------------------------------------------- /src/parse_tex.rs: -------------------------------------------------------------------------------- 1 | use std::{fs, path::PathBuf}; 2 | 3 | /// Output Configuration.tex info for specific field 4 | /// take a path to Configuration.tex and a Vec for desired Section, Subsection and Field 5 | /// return a Vec containing the formatted lines of the Configuration.tex 6 | pub fn parse_configuration( 7 | tex_path: &PathBuf, 8 | search_str: Vec, 9 | width: i32, 10 | gather_valid: bool, 11 | show_url: bool, 12 | ) -> Vec { 13 | let mut result = vec![]; 14 | if search_str.len() == 0 { 15 | result.push("no field values supplied".to_owned()); 16 | return result; 17 | } 18 | let contents = fs::read_to_string(tex_path).unwrap_or("".to_string()); 19 | if contents.len() == 0 { 20 | result.push("local Configuration.tex not found".to_owned()); 21 | return result; 22 | } 23 | 24 | let mut search_terms = vec![]; 25 | 26 | search_terms.push("\\section{".to_string() + &search_str[0]); 27 | let mut text_search = search_str.last().unwrap().to_owned(); 28 | if text_search.len() < 3 { 29 | result.push("array item #".to_string() + &text_search + "\r\n"); 30 | return result; 31 | } 32 | 33 | match search_str.len() { 34 | 1 => (), 35 | 2 => { 36 | search_terms.push("\\subsection{Properties".to_string()); 37 | search_terms.push("texttt{".to_string() + &text_search + "}\\"); 38 | } 39 | 3 => { 40 | if search_str[0] == "NVRAM" { 41 | search_terms.push("\\subsection{Introduction".to_string()); 42 | search_terms.push("texttt{".to_string() + &text_search + "}"); 43 | } else { 44 | search_terms.push("\\subsection{".to_string() + &search_str[1] + " Properties"); 45 | search_terms.push("texttt{".to_string() + &text_search + "}\\"); 46 | } 47 | } 48 | 4 => { 49 | let mut sub_search = "\\subsection{".to_string(); 50 | match search_str[0].as_str() { 51 | "NVRAM" => { 52 | sub_search = "\\subsection{Introduction".to_string(); 53 | text_search = search_str[2].to_owned() + ":" + &search_str[3] + "}"; 54 | } 55 | "DeviceProperties" => { 56 | sub_search.push_str("Common"); 57 | text_search.push_str("}"); 58 | } 59 | "Misc" => { 60 | if search_str[2].len() < 3 { 61 | sub_search.push_str("Entry Properties"); 62 | } else { 63 | sub_search = "\\subsubsection{".to_string() + &search_str[1]; 64 | } 65 | text_search.push_str("}"); 66 | } 67 | _ => { 68 | sub_search.push_str(&search_str[1]); 69 | sub_search.push_str(" Properties"); 70 | text_search.push_str("}\\"); 71 | } 72 | }; 73 | search_terms.push(sub_search); 74 | search_terms.push("texttt{".to_string() + &text_search); 75 | } 76 | 5 => { 77 | search_terms.push("\\subsubsection{".to_string() + &search_str[1]); 78 | search_terms.push("texttt{".to_string() + &text_search); 79 | } 80 | _ => return result, 81 | } 82 | 83 | // return search_terms; 84 | 85 | let mut lines = contents.lines(); 86 | 87 | for term in search_terms { 88 | loop { 89 | match lines.next() { 90 | Some(line) => { 91 | if line.contains(&term) { 92 | break; 93 | } 94 | } 95 | None => return result, 96 | } 97 | } 98 | } 99 | 100 | let mut align = false; 101 | let mut itemize = 0; 102 | let mut enumerate = 0; 103 | let mut columns = 0; 104 | let mut lines_between_valid = 0; 105 | 106 | for line in lines { 107 | if line.trim_start().starts_with("%") { 108 | // skip comments 109 | continue; 110 | } 111 | if line.contains("\\subsection{Introduction}") { 112 | continue; 113 | } 114 | if line.contains("\\begin{tabular") { 115 | for c in line.chars() { 116 | if c == 'c' { 117 | columns += 1; 118 | }; 119 | } 120 | continue; 121 | } 122 | if line.contains("\\begin{align*}") { 123 | align = true; 124 | continue; 125 | } 126 | if line.contains("\\end{align*}}") { 127 | align = false; 128 | continue; 129 | } 130 | // cheap hack to keep track of being in a list 131 | if line.contains("\\begin{itemize}") { 132 | itemize += 1; 133 | continue; 134 | } 135 | if line.contains("\\begin{enumerate}") { 136 | enumerate += 1; 137 | continue; 138 | } 139 | if line.contains("\\mbox") { 140 | continue; 141 | } 142 | // if line.contains("\\begin{") { 143 | // continue; 144 | // } 145 | if line.contains("\\end{tabular}") { 146 | columns = 0; 147 | continue; 148 | } 149 | if line.contains("\\end{itemize}") { 150 | itemize -= 1; 151 | continue; 152 | } 153 | if line.contains("\\end{enumerate}") { 154 | enumerate -= 1; 155 | continue; 156 | } 157 | if line.contains("\\end{") { 158 | continue; 159 | } 160 | if line.contains("\\item") && (itemize == 0 && enumerate == 0) { 161 | break; 162 | } 163 | if line.contains("\\subsection{") || line.contains("\\section{") { 164 | break; 165 | } 166 | let parsed_line = parse_line(line, columns, width, align, gather_valid, show_url); 167 | if gather_valid { 168 | // gather list items to display when editing a string or integer 169 | if itemize > 0 { 170 | // we are inside an itemize bracket 171 | if line.contains("---") { 172 | if lines_between_valid < 10 { 173 | result.push(parsed_line); 174 | } 175 | } 176 | } else { 177 | // stop gathering if there has been a big break 178 | if result.len() > 0 { 179 | lines_between_valid += 1; 180 | } 181 | } 182 | } else { 183 | if parsed_line.len() != 0 { 184 | result.push(parsed_line); 185 | // result.push(format!("\x1B[0K{}", parsed_line)); 186 | } 187 | } 188 | } 189 | result 190 | } 191 | 192 | /// Go through line 1 character at a time to apply .tex formatting 193 | /// 194 | /// TODO: pass back attributes so formatting/mode can exist for more than 1 line 195 | /// 196 | fn parse_line( 197 | line: &str, 198 | columns: i32, 199 | width: i32, 200 | align: bool, 201 | gather_valid: bool, 202 | show_url: bool, 203 | ) -> String { 204 | let mut ret = String::new(); 205 | let mut build_key = false; 206 | let mut key = String::new(); 207 | let mut col_width = 0; 208 | if columns > 0 { 209 | col_width = width / (columns + 1); 210 | } 211 | let mut ignore = false; 212 | let mut col_contents_len = 0; 213 | for c in line.chars() { 214 | if build_key { 215 | match c { 216 | // end of key 217 | '{' | '[' => { 218 | build_key = false; 219 | // build_name = true; 220 | if !gather_valid { 221 | match key.as_str() { 222 | "text" => ret.push_str("\x1B[0m"), 223 | "textit" => ret.push_str("\x1B[1m"), 224 | "textbf" => ret.push_str("\x1B[1m"), 225 | "emph" => ret.push_str("\x1B[7m"), 226 | "texttt" => ret.push_str("\x1B[4m"), 227 | "href" => { 228 | if show_url { 229 | ret.push_str("\x1B[34m"); 230 | } else { 231 | ignore = true; 232 | } 233 | } 234 | _ => ignore = true, 235 | }; 236 | } 237 | if &key != "href" { 238 | // hold href key to insert space after it 239 | key.clear(); 240 | } 241 | } 242 | // end of key - may be special character or formatting 243 | ' ' | ',' | '(' | ')' | '\\' | '0'..='9' | '$' | '&' => { 244 | build_key = false; 245 | if &key == "item" { 246 | if !gather_valid { 247 | ret.push('•'); 248 | } 249 | } 250 | ret.push(special_char(&key)); 251 | col_contents_len += 1; 252 | if c == ',' || c == '(' || c == ')' || (c >= '0' && c <= '9') || c == '$' { 253 | ret.push(c); 254 | } 255 | if c == '\\' { 256 | if key.len() > 0 { 257 | // check for double \ 258 | build_key = true; // or start of new key 259 | } 260 | } 261 | key.clear(); 262 | } 263 | // found escaped character 264 | '_' | '^' | '#' => { 265 | build_key = false; 266 | ret.push(c); 267 | col_contents_len += 1; 268 | key.clear(); 269 | } 270 | _ => key.push(c), 271 | } 272 | } else { 273 | match c { 274 | '\\' => build_key = true, 275 | '}' | ']' => { 276 | if !ignore { 277 | if !gather_valid { 278 | ret.push_str("\x1b[0m"); 279 | if &key == "href" { 280 | ret.push(' '); 281 | key.clear(); 282 | } else if c == ']' { 283 | ret.push(']'); 284 | } 285 | } 286 | } 287 | ignore = false; 288 | } 289 | '{' => { 290 | if !gather_valid { 291 | ret.push_str("\x1B[4m"); 292 | } 293 | } 294 | '&' => { 295 | if columns > 0 { 296 | let fill = col_width - col_contents_len - 1; 297 | if fill > 0 { 298 | ret.push_str(&" ".repeat(fill as usize)); 299 | } 300 | ret.push_str("|"); 301 | col_contents_len = 0; 302 | } else { 303 | if !align { 304 | ret.push('&'); 305 | } 306 | } 307 | } 308 | _ => { 309 | if !ignore { 310 | ret.push(c); 311 | col_contents_len += 1; 312 | } 313 | } 314 | } 315 | } 316 | } 317 | if key.len() > 0 { 318 | ret.push(special_char(&key)); 319 | } 320 | if !gather_valid { 321 | if key == "tightlist" { 322 | // ignore 323 | ret.clear(); 324 | } else { 325 | if key == "hline" { 326 | ret.push_str(&"-".repeat(width as usize - 4)); 327 | } 328 | ret.push_str("\r\n"); 329 | } 330 | } 331 | 332 | ret 333 | } 334 | 335 | fn special_char(key: &str) -> char { 336 | match key { 337 | "kappa" => '\u{03f0}', 338 | "lambda" => '\u{03bb}', 339 | "mu" => '\u{03bc}', 340 | "alpha" => '\u{03b1}', 341 | "beta" => '\u{03b2}', 342 | "gamma" => '\u{03b3}', 343 | "leq" => '\u{2264}', 344 | "cdot" => '\u{00b7}', 345 | "in" => '\u{220a}', 346 | "infty" => '\u{221e}', 347 | "textbackslash" => '\\', 348 | "hline" => '\u{200b}', 349 | _ => ' ', 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /src/snake.rs: -------------------------------------------------------------------------------- 1 | use core::iter::Cycle; 2 | use core::str::Chars; 3 | use rand::prelude::*; 4 | use std::collections::VecDeque; 5 | use std::error::Error; 6 | use std::io::{Stdout, Write}; 7 | use std::ops; 8 | 9 | use crossterm::event::{poll, read, Event, KeyCode}; 10 | use crossterm::terminal::size; 11 | 12 | use std::thread::sleep; 13 | use std::time::Duration; 14 | 15 | // blame mahasvan for this "secret" snake option 16 | 17 | #[derive(Debug, PartialEq, Copy, Clone)] 18 | struct CoordinateVector(pub i32, pub i32); 19 | impl ops::Add for CoordinateVector { 20 | type Output = Self; 21 | 22 | fn add(self, rhs: Self) -> Self::Output { 23 | CoordinateVector(self.0 + rhs.0, self.1 + rhs.1) 24 | } 25 | } 26 | 27 | struct Snake { 28 | seg: VecDeque, 29 | direction: CoordinateVector, 30 | } 31 | 32 | fn travel(snake: &mut Snake, grow: bool) -> CoordinateVector { 33 | let &old_head = snake.seg.back().unwrap(); 34 | if grow { 35 | let &old_tail = snake.seg.front().unwrap(); 36 | for _ in 0..5 { 37 | snake.seg.push_front(old_tail); 38 | } 39 | } else { 40 | snake.seg.pop_front().unwrap(); 41 | } 42 | let new_head = old_head + snake.direction; 43 | snake.seg.push_back(old_head + snake.direction); 44 | new_head 45 | } 46 | 47 | fn head_touching_object(snake: &Snake, object: CoordinateVector) -> bool { 48 | *snake.seg.back().unwrap() == object 49 | } 50 | 51 | fn head_touching_snake(snake: &Snake, other: &Snake) -> bool { 52 | let &head = snake.seg.back().unwrap(); 53 | // Find the position of first snake segment which is equal to the head 54 | let position = match other.seg.iter().position(|&coord| coord == head) { 55 | Some(p) => p, 56 | None => 100, 57 | }; 58 | // Return true if the found position is not the head. 59 | position < other.seg.len() - 1 60 | } 61 | 62 | fn head_out_of_bounds(snake: &Snake, bounds: CoordinateVector) -> bool { 63 | let &head = snake.seg.back().unwrap(); 64 | head.0 > bounds.0 || head.1 > bounds.1 || head.0 < 1 || head.1 < 1 65 | } 66 | 67 | pub fn snake(stdout: &mut Stdout) -> core::result::Result<(), Box> { 68 | let mut masc = "BLAME_MAHASVAN_FOR_THIS_".chars().cycle(); 69 | let mut apple = "113322446655".chars().cycle(); 70 | let mut stripe = "13".chars().cycle(); 71 | let mut score = 0; 72 | 73 | write!(stdout, "\x1b[2J")?; 74 | 75 | let (y1, x1) = size()?; 76 | let x = i32::from(x1); 77 | let y = i32::from(y1); 78 | 79 | let mut rng = thread_rng(); 80 | let board_bounds = CoordinateVector(y + 1, x + 1); 81 | let mut snake = Snake { 82 | seg: VecDeque::from(vec![CoordinateVector(y / 2, x / 2)]), 83 | direction: CoordinateVector(1, 0), 84 | }; 85 | let mut baddy = Snake { 86 | seg: VecDeque::from(vec![CoordinateVector( 87 | rng.gen_range(1..board_bounds.0), 88 | rng.gen_range(1..board_bounds.1), 89 | )]), 90 | direction: CoordinateVector(0, 1), 91 | }; 92 | let &tail = baddy.seg.front().unwrap(); 93 | for _ in 0..8 { 94 | baddy.seg.push_front(tail); 95 | } 96 | let mut food = get_new_food_position(&snake, board_bounds, &mut rng); 97 | 98 | travel(&mut snake, true); 99 | 100 | loop { 101 | let eating_food = head_touching_object(&snake, food); 102 | if eating_food { 103 | score += 1; 104 | food = get_new_food_position(&snake, board_bounds, &mut rng); 105 | } 106 | travel(&mut snake, eating_food); 107 | let t = rng.gen_range(1..100); 108 | if t > 95 { 109 | turn_right(&mut baddy); 110 | } else if t < 5 { 111 | turn_left(&mut baddy); 112 | } 113 | travel(&mut baddy, false); 114 | if head_out_of_bounds(&baddy, board_bounds) { 115 | baddy.seg.pop_back().unwrap(); 116 | let &tail = baddy.seg.front().unwrap(); 117 | baddy.seg.push_front(tail); 118 | turn_right(&mut baddy); 119 | }; 120 | display( 121 | stdout, 122 | &snake, 123 | &baddy, 124 | food, 125 | &mut masc, 126 | &mut apple, 127 | &mut stripe, 128 | score, 129 | ); 130 | if head_touching_snake(&snake, &snake) 131 | || head_out_of_bounds(&snake, board_bounds) 132 | || head_touching_snake(&baddy, &snake) 133 | { 134 | break; 135 | } 136 | stdout.flush().unwrap(); 137 | if poll(Duration::from_millis(100)).ok().unwrap() { 138 | if let Event::Key(ke) = read().ok().unwrap() { 139 | match ke.code { 140 | KeyCode::Left | KeyCode::Char('h') | KeyCode::Char('a') => { 141 | if snake.direction.1 != 0 { 142 | snake.direction = CoordinateVector(-1, 0); 143 | } 144 | } 145 | KeyCode::Right | KeyCode::Char('l') | KeyCode::Char('d') => { 146 | if snake.direction.1 != 0 { 147 | snake.direction = CoordinateVector(1, 0); 148 | } 149 | } 150 | KeyCode::Up | KeyCode::Char('k') | KeyCode::Char('w') => { 151 | if snake.direction.0 != 0 { 152 | snake.direction = CoordinateVector(0, -1); 153 | } 154 | } 155 | KeyCode::Down | KeyCode::Char('j') | KeyCode::Char('s') => { 156 | if snake.direction.0 != 0 { 157 | snake.direction = CoordinateVector(0, 1); 158 | } 159 | } 160 | KeyCode::Esc => break, 161 | _ => (), 162 | } 163 | } 164 | }; 165 | } 166 | for segment in snake.seg.iter() { 167 | write!( 168 | stdout, 169 | "\x1B[{};{}H\x1B[31;7m{}\x1B[0m", 170 | segment.1, segment.0, 'X' 171 | ) 172 | .unwrap(); 173 | stdout.flush().unwrap(); 174 | sleep(Duration::from_millis(5)); 175 | } 176 | Ok(()) 177 | } 178 | 179 | fn get_new_food_position( 180 | snake: &Snake, 181 | bounds: CoordinateVector, 182 | rng: &mut ThreadRng, 183 | ) -> CoordinateVector { 184 | let new_position = CoordinateVector(rng.gen_range(1..bounds.0), rng.gen_range(1..bounds.1)); 185 | match snake.seg.contains(&new_position) { 186 | true => get_new_food_position(snake, bounds, rng), 187 | false => new_position, 188 | } 189 | } 190 | 191 | fn turn_left(snake: &mut Snake) { 192 | let mut a = snake.direction.0; 193 | let mut b = snake.direction.1; 194 | if a != 0 { 195 | b = -a; 196 | a = 0; 197 | } else { 198 | a = b; 199 | b = 0; 200 | } 201 | snake.direction = CoordinateVector(a, b); 202 | } 203 | 204 | fn turn_right(snake: &mut Snake) { 205 | let mut a = snake.direction.0; 206 | let mut b = snake.direction.1; 207 | if a != 0 { 208 | b = a; 209 | a = 0; 210 | } else { 211 | a = -b; 212 | b = 0; 213 | } 214 | snake.direction = CoordinateVector(a, b); 215 | } 216 | 217 | fn display( 218 | stdout: &mut Stdout, 219 | snake: &Snake, 220 | baddy: &Snake, 221 | food: CoordinateVector, 222 | snk: &mut Cycle, 223 | apple: &mut Cycle, 224 | stripe: &mut Cycle, 225 | score: i32, 226 | ) { 227 | write!( 228 | stdout, 229 | "\x1B[{};{}H\x1B[3{}m{}\x1B[0m", 230 | food.1, 231 | food.0, 232 | apple.next().unwrap(), 233 | '' 234 | ) 235 | .unwrap(); 236 | let segment = snake.seg.back().unwrap(); 237 | write!( 238 | stdout, 239 | "\x1B[{};{}H\x1B[42;37m{}\x1B[0m", 240 | segment.1, 241 | segment.0, 242 | snk.next().unwrap() 243 | ) 244 | .unwrap(); 245 | let segment = snake.seg.front().unwrap(); 246 | write!(stdout, "\x1B[{};{}H{}", segment.1, segment.0, ' ').unwrap(); 247 | let segment = baddy.seg.back().unwrap(); 248 | write!( 249 | stdout, 250 | "\x1B[{};{}H\x1B[3{};7m{}\x1B[0m", 251 | segment.1, 252 | segment.0, 253 | stripe.next().unwrap(), 254 | '/' 255 | ) 256 | .unwrap(); 257 | let segment = baddy.seg.front().unwrap(); 258 | write!(stdout, "\x1B[{};{}H{}", segment.1, segment.0, ' ').unwrap(); 259 | write!(stdout, "\x1B[1;1H{}", score).unwrap(); 260 | } 261 | -------------------------------------------------------------------------------- /tool_config_files/config_differences.json: -------------------------------------------------------------------------------- 1 | { 2 | "config_differences": [ 3 | [ 4 | "Booter", 5 | "Quirks", 6 | "FixupAppleEfiImages", 7 | "0.9.7" 8 | ], 9 | [ 10 | "UEFI", 11 | "Quirks", 12 | "ShimRetainProtocol", 13 | "0.9.5" 14 | ], 15 | [ 16 | "Misc", 17 | "Boot", 18 | "InstanceIdentifier", 19 | "0.9.4" 20 | ], 21 | [ 22 | "UEFI", 23 | "Output", 24 | "ConsoleFont", 25 | "0.9.3" 26 | ], 27 | [ 28 | "UEFI", 29 | "Output", 30 | "InitialMode", 31 | "0.9.2" 32 | ], 33 | [ 34 | "UEFI", 35 | "Output", 36 | "GopBurstMode", 37 | "0.9.1" 38 | ], 39 | [ 40 | "UEFI", 41 | "Quirks", 42 | "ResizeUsePciRbIo", 43 | "0.9.0" 44 | ], 45 | [ 46 | "Misc", 47 | "Boot", 48 | "HibernateSkipsPicker", 49 | "0.8.8" 50 | ], 51 | [ 52 | "UEFI", 53 | "AppleInput", 54 | "PointerDwellClickTimeout", 55 | "0.8.6" 56 | ], 57 | [ 58 | "Misc", 59 | "Tools", 60 | "FullNvramAccess", 61 | "0.8.5" 62 | ], 63 | [ 64 | "UEFI", 65 | "Drivers", 66 | "LoadEarly", 67 | "0.8.3" 68 | ], 69 | [ 70 | "Kernel", 71 | "Quirks", 72 | "ForceAquantiaEthernet", 73 | "0.8.2" 74 | ], 75 | [ 76 | "Kernel", 77 | "Quirks", 78 | "ForceAquantiaEthernet", 79 | "0.8.1" 80 | ], 81 | [ 82 | "Kernel", 83 | "Quirks", 84 | "ForceAquantiaEthernet", 85 | "0.8.0" 86 | ], 87 | [ 88 | "Misc", 89 | "Debug", 90 | "LogModules", 91 | "0.7.9" 92 | ], 93 | [ 94 | "UEFI", 95 | "Audio", 96 | "AudioOutMask", 97 | "0.7.8" 98 | ], 99 | [ 100 | "UEFI", 101 | "Output", 102 | "UIScale", 103 | "0.7.6" 104 | ], 105 | [ 106 | "Booter", 107 | "Quirks", 108 | "ResizeAppleGpuBars", 109 | "0.7.5" 110 | ], 111 | [ 112 | "UEFI", 113 | "Drivers", 114 | "Comment", 115 | "0.7.4" 116 | ], 117 | [ 118 | "UEFI", 119 | "Quirks", 120 | "ForceOcWriteFlash", 121 | "0.7.3" 122 | ], 123 | [ 124 | "UEFI", 125 | "AppleInput", 126 | "GraphicsInputMirroring", 127 | "0.7.2" 128 | ], 129 | [ 130 | "Kernel", 131 | "Scheme", 132 | "CustomKernel", 133 | "0.7.1" 134 | ], 135 | [ 136 | "PlatformInfo", 137 | "Generic", 138 | "AdviseFeatures", 139 | "0.7.0" 140 | ], 141 | [ 142 | "UEFI", 143 | "Quirks", 144 | "EnableVectorAcceleration", 145 | "0.6.9" 146 | ], 147 | [ 148 | "Booter", 149 | "Quirks", 150 | "ForceBooterSignature", 151 | "0.6.8" 152 | ], 153 | [ 154 | "UEFI", 155 | "Quirks", 156 | "ActivateHpetSupport", 157 | "0.6.7" 158 | ], 159 | [ 160 | "UEFI", 161 | "Quirks", 162 | "DisableSecurityPolicy", 163 | "0.6.6" 164 | ], 165 | [ 166 | "UEFI", 167 | "Audio", 168 | "SetupDelay", 169 | "0.6.5" 170 | ], 171 | [ 172 | "Misc", 173 | "Security", 174 | "BlacklistAppleUpdate", 175 | "0.6.4" 176 | ], 177 | [ 178 | "UEFI", 179 | "Output", 180 | "ForceResolution", 181 | "0.6.3" 182 | ], 183 | [ 184 | "PlatformInfo", 185 | "Generic", 186 | "ProcessorType", 187 | "0.6.2" 188 | ], 189 | [ 190 | "UEFI", 191 | "ProtocolOverrides", 192 | "AppleSecureBoot", 193 | "0.6.1" 194 | ], 195 | [ 196 | "UEFI", 197 | "ProtocolOverrides", 198 | "AppleFramebufferInfo", 199 | "0.6.0" 200 | ] 201 | ] 202 | } 203 | -------------------------------------------------------------------------------- /tool_config_files/dyn_res_list.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rusty-bits/octool/b5faac7b26a86451db94a7d1371ed97996910683/tool_config_files/dyn_res_list.zip -------------------------------------------------------------------------------- /tool_config_files/octool_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "octool_version": "v0.5.1 2023-12-30", 3 | "octool_releases_url": "https://github.com/rusty-bits/octool/releases", 4 | "octool_latest_config_url": "https://raw.githubusercontent.com/rusty-bits/octool/main/tool_config_files/octool_config.json", 5 | "octool_latest_dyn_res_list_url": "https://raw.githubusercontent.com/rusty-bits/octool/main/tool_config_files/dyn_res_list.zip", 6 | 7 | "acpi_path": "Docs/AcpiSamples/Binaries", 8 | "drivers_path": "X64/EFI/OC/Drivers", 9 | "tools_path": "X64/EFI/OC/Tools", 10 | 11 | "dortania_config_path": "tool_config_files/build-repo-builds", 12 | "dortania_config_zip": "https://github.com/dortania/build-repo/archive/refs/heads/builds.zip", 13 | 14 | "opencorepkg_path": "resources/OpenCorePkg", 15 | "current_configuration_tex": "https://raw.githubusercontent.com/acidanthera/OpenCorePkg/master/Docs/Configuration.tex", 16 | "current_sample_plist": "https://raw.githubusercontent.com/acidanthera/OpenCorePkg/master/Docs/Sample.plist", 17 | 18 | "//comm_can_lang": "only include language files containing 'canopy_language' when OpenCanopy is used", 19 | "canopy_language": "en", 20 | 21 | "//comm_glob_audio": "always include these audio files when OpenCanopy is used", 22 | "global_audio_files": [ 23 | "AXEFIAudio_Beep.mp3", 24 | "AXEFIAudio_Click.mp3", 25 | "AXEFIAudio_VoiceOver_Boot.mp3" 26 | ], 27 | 28 | "//comm_show_url": "show url in info screens in addition to link name", 29 | "show_url_in_info_screens": false, 30 | 31 | "//comm_reset_ver": "when OpenCore version is changed, set other resource versions to match", 32 | "reset_res_versions": true, 33 | 34 | "//comm_clob_local": "replace local res list with updated list when octool is run", 35 | "clobber_local_dyn_res_list": true, 36 | 37 | "//comm_use_latest": "use latest version of OpenCore that fits the format of the config.plist being used", 38 | "use_latest_oc_on_guess": true, 39 | 40 | "//comm_build": "set use of either 'X64' or 'IA32' build architecture", 41 | "build_architecture": "X64", 42 | 43 | "resource_sections": [ 44 | [ 45 | "ACPI", 46 | "Add", 47 | "Path", 48 | "ACPI" 49 | ], 50 | [ 51 | "Kernel", 52 | "Add", 53 | "BundlePath", 54 | "Kexts" 55 | ], 56 | [ 57 | "Misc", 58 | "Tools", 59 | "Path", 60 | "Tools" 61 | ], 62 | [ 63 | "UEFI", 64 | "Drivers", 65 | "Path", 66 | "Drivers" 67 | ] 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /tool_config_files/other.json: -------------------------------------------------------------------------------- 1 | { 2 | "AppleMCEReporterDisabler": { 3 | "versions": [ 4 | { 5 | "links": { 6 | "debug": "https://github.com/acidanthera/bugtracker/files/3703498/AppleMCEReporterDisabler.kext.zip", 7 | "release": "https://github.com/acidanthera/bugtracker/files/3703498/AppleMCEReporterDisabler.kext.zip" 8 | }, 9 | "hashes": { 10 | "debug": { 11 | "sha256": "470417c4958dd6ecb982182140a6b76cf85f847c15f1b0f6f59617d5abcc5f76" 12 | }, 13 | "release": { 14 | "sha256": "470417c4958dd6ecb982182140a6b76cf85f847c15f1b0f6f59617d5abcc5f76" 15 | } 16 | } 17 | } 18 | ] 19 | }, 20 | "AtherosEthernetE2200": { 21 | "versions": [ 22 | { 23 | "links": { 24 | "debug": "https://github.com/Mieze/AtherosE2200Ethernet/releases/download/2.2.2/AtherosE2200Ethernet-V2.2.2.zip", 25 | "release": "https://github.com/Mieze/AtherosE2200Ethernet/releases/download/2.2.2/AtherosE2200Ethernet-V2.2.2.zip" 26 | }, 27 | "hashes": { 28 | "debug": { 29 | "sha256": "a50449953db3e3171f7645918c5f34fb3da7af0e0a9c7ec50b34550f5baf635a" 30 | }, 31 | "release": { 32 | "sha256": "a50449953db3e3171f7645918c5f34fb3da7af0e0a9c7ec50b34550f5baf635a" 33 | } 34 | } 35 | } 36 | ] 37 | }, 38 | "Getting-Started-With-ACPI": { 39 | "versions": [ 40 | { 41 | "links": { 42 | "debug": "https://github.com/dortania/Getting-Started-With-ACPI/archive/refs/heads/master.zip", 43 | "release": "https://github.com/dortania/Getting-Started-With-ACPI/archive/refs/heads/master.zip" 44 | } 45 | } 46 | ] 47 | }, 48 | "OcBinaryData": { 49 | "versions": [ 50 | { 51 | "links": { 52 | "debug": "https://github.com/acidanthera/OcBinaryData/archive/refs/heads/master.zip", 53 | "release": "https://github.com/acidanthera/OcBinaryData/archive/refs/heads/master.zip" 54 | } 55 | } 56 | ] 57 | }, 58 | "RadeonSensor": { 59 | "versions": [ 60 | { 61 | "version": "0.3.1", 62 | "hashes": { 63 | "debug": { 64 | "sha256": "16c765cba88bb30c5cab46f9281903116b139307fd1a91f368998eb514bb3ae5" 65 | }, 66 | "release": { 67 | "sha256":"16c765cba88bb30c5cab46f9281903116b139307fd1a91f368998eb514bb3ae5" 68 | } 69 | }, 70 | "links": { 71 | "debug": "https://github.com/aluveitie/RadeonSensor/releases/download/0.3.1/RadeonSensor-0.3.1.zip", 72 | "release": "https://github.com/aluveitie/RadeonSensor/releases/download/0.3.1/RadeonSensor-0.3.1.zip" 73 | } 74 | } 75 | ] 76 | }, 77 | "SmallTreeIntel82576": { 78 | "versions": [ 79 | { 80 | "links": { 81 | "debug": "https://github.com/khronokernel/SmallTree-I211-AT-patch/releases/download/1.3.0/SmallTreeIntel82576.kext.zip", 82 | "release": "https://github.com/khronokernel/SmallTree-I211-AT-patch/releases/download/1.3.0/SmallTreeIntel82576.kext.zip" 83 | }, 84 | "hashes": { 85 | "debug": { 86 | "sha256": "5fcced4fcd1e9f1b95012aca7cfd117f4eae13b525b215e740c851fda262fa6d" 87 | }, 88 | "release": { 89 | "sha256": "5fcced4fcd1e9f1b95012aca7cfd117f4eae13b525b215e740c851fda262fa6d" 90 | } 91 | } 92 | } 93 | ] 94 | }, 95 | "USBToolBox": { 96 | "versions": [ 97 | { 98 | "version": "1.1.1", 99 | "links": { 100 | "debug": "https://github.com/USBToolBox/kext/releases/download/1.1.1/USBToolBox-1.1.1-DEBUG.zip", 101 | "release": "https://github.com/USBToolBox/kext/releases/download/1.1.1/USBToolBox-1.1.1-RELEASE.zip" 102 | }, 103 | "hashes": { 104 | "debug": { 105 | "sha256": "5c545703d90e0cf288148a39787e3302d1d1c246981fa53d39d449d81b4536bd" 106 | }, 107 | "release": { 108 | "sha256": "6e88bc00cf895620046b2850fa0bfe6d3e21385b6d1eaad86036468e59b664de" 109 | } 110 | } 111 | } 112 | ] 113 | }, 114 | "VoodooSMBus": { 115 | "versions": [ 116 | { 117 | "version": "2.2", 118 | "links": { 119 | "debug": "https://github.com/VoodooSMBus/VoodooSMBus/releases/download/v2.2/VoodooSMBus-v2.2.zip", 120 | "release": "https://github.com/VoodooSMBus/VoodooSMBus/releases/download/v2.2/VoodooSMBus-v2.2.zip" 121 | }, 122 | "hashes": { 123 | "debug": { 124 | "sha256": "a65d68b112ef89e262cb713af1f821d7eaa5978d3ef1a47f9d4d2338cbc6aa8e" 125 | }, 126 | "release": { 127 | "sha256": "a65d68b112ef89e262cb713af1f821d7eaa5978d3ef1a47f9d4d2338cbc6aa8e" 128 | } 129 | } 130 | } 131 | ] 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /tool_config_files/resource_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "AcpiTest.efi": { 3 | "parent": "OpenCorePkg" 4 | }, 5 | "AcpiTestApp.efi": { 6 | "parent": "OpenCorePkg" 7 | }, 8 | "AirPortBrcm4360_Injector.kext": { 9 | "parent": "AirportBrcmFixup" 10 | }, 11 | "AirPortBrcmNIC_Injector.kext": { 12 | "parent": "AirportBrcmFixup" 13 | }, 14 | "AirportBrcmFixup.kext": { 15 | "parent": "AirportBrcmFixup" 16 | }, 17 | "AppleALC.kext": { 18 | "parent": "AppleALC" 19 | }, 20 | "AppleMCEReporterDisabler.kext": { 21 | "parent": "AppleMCEReporterDisabler" 22 | }, 23 | "AtherosE2200Ethernet.kext": { 24 | "parent": "AtherosEthernetE2200" 25 | }, 26 | "AudioDxe.efi": { 27 | "parent": "OpenCorePkg", 28 | "res_type": "driver" 29 | }, 30 | "BOOTx64.efi": { 31 | "parent": "OpenCorePkg" 32 | }, 33 | "BT4LEContinuityFixup.kext": { 34 | "parent": "BT4LEContinuityFixup" 35 | }, 36 | "BiosVideo.efi": { 37 | "parent": "OpenCorePkg", 38 | "res_type": "driver" 39 | }, 40 | "BlueToolFixup.kext": { 41 | "parent": "BrcmPatchRAM" 42 | }, 43 | "BootKicker.efi": { 44 | "parent": "OpenCorePkg", 45 | "res_type": "tool" 46 | }, 47 | "BrcmBluetoothInjector.kext": { 48 | "parent": "BrcmPatchRAM" 49 | }, 50 | "BrcmFirmwareData.kext": { 51 | "parent": "BrcmPatchRAM" 52 | }, 53 | "BrcmFirmwareRepo.kext": { 54 | "parent": "BrcmPatchRAM" 55 | }, 56 | "BrcmNonPatchRAM.kext": { 57 | "parent": "BrcmPatchRAM" 58 | }, 59 | "BrcmNonPatchRAM2.kext": { 60 | "parent": "BrcmPatchRAM" 61 | }, 62 | "BrcmPatchRAM.kext": { 63 | "parent": "BrcmPatchRAM" 64 | }, 65 | "BrcmPatchRAM2.kext": { 66 | "parent": "BrcmPatchRAM" 67 | }, 68 | "BrcmPatchRAM3.kext": { 69 | "parent": "BrcmPatchRAM" 70 | }, 71 | "BrightnessKeys.kext": { 72 | "parent": "BrightnessKeys" 73 | }, 74 | "CPUFriend.kext": { 75 | "parent": "CPUFriend" 76 | }, 77 | "ChipTune.efi": { 78 | "parent": "OpenCorePkg", 79 | "res_type": "tool" 80 | }, 81 | "CleanNvram.efi": { 82 | "parent": "OpenCorePkg", 83 | "res_type": "tool" 84 | }, 85 | "ControlMsrE2.efi": { 86 | "parent": "OpenCorePkg", 87 | "res_type": "tool" 88 | }, 89 | "CpuTopologySync.kext": { 90 | "parent": "CpuTopologySync" 91 | }, 92 | "CpuTscSync.kext": { 93 | "parent": "CpuTscSync" 94 | }, 95 | "CrScreenshotDxe.efi": { 96 | "parent": "OpenCorePkg", 97 | "res_type": "driver" 98 | }, 99 | "CryptoTest.efi": { 100 | "parent": "OpenCorePkg" 101 | }, 102 | "CryptoTestApp.efi": { 103 | "parent": "OpenCorePkg" 104 | }, 105 | "CsrUtil.efi": { 106 | "parent": "OpenCorePkg", 107 | "res_type": "tool" 108 | }, 109 | "DataHubTest.efi": { 110 | "parent": "OpenCorePkg" 111 | }, 112 | "DataHubTestApp.efi": { 113 | "parent": "OpenCorePkg" 114 | }, 115 | "DebugEnhancer.kext": { 116 | "parent": "DebugEnhancer" 117 | }, 118 | "ECEnabler.kext": { 119 | "parent": "ECEnabler" 120 | }, 121 | "Ext4Dxe.efi": { 122 | "parent": "OpenCorePkg", 123 | "res_type": "driver" 124 | }, 125 | "ExFatDxe.efi": { 126 | "parent": "OcBinaryData", 127 | "res_type": "driver" 128 | }, 129 | "ExFatDxeLegacy.efi": { 130 | "parent": "OcBinaryData", 131 | "res_type": "driver" 132 | }, 133 | "FeatureUnlock.kext": { 134 | "parent": "FeatureUnlock" 135 | }, 136 | "GdbSyms.efi": { 137 | "parent": "OpenCorePkg" 138 | }, 139 | "GopStop.efi": { 140 | "parent": "OpenCorePkg", 141 | "res_type": "tool" 142 | }, 143 | "HfsPlus.efi": { 144 | "parent": "OcBinaryData", 145 | "res_type": "driver" 146 | }, 147 | "HfsPlus32.efi": { 148 | "parent": "OcBinaryData", 149 | "res_type": "driver" 150 | }, 151 | "HfsPlusLegacy.efi": { 152 | "parent": "OcBinaryData", 153 | "res_type": "driver" 154 | }, 155 | "HibernationFixup.kext": { 156 | "parent": "HibernationFixup" 157 | }, 158 | "HiiDatabase.efi": { 159 | "parent": "OpenCorePkg", 160 | "res_type": "driver" 161 | }, 162 | "IntelBluetoothFirmware.kext": { 163 | "parent": "IntelBluetoothFirmware" 164 | }, 165 | "IntelBluetoothInjector.kext": { 166 | "parent": "IntelBluetoothFirmware" 167 | }, 168 | "InteBTPatcher.kext": { 169 | "parent": "IntelBluetoothFirmware" 170 | }, 171 | "IntelMausi.kext": { 172 | "parent": "IntelMausi" 173 | }, 174 | "KeyTester.efi": { 175 | "parent": "OpenCorePkg", 176 | "res_type": "tool" 177 | }, 178 | "Lilu.kext": { 179 | "parent": "Lilu" 180 | }, 181 | "MacHyperVSupport.kext": { 182 | "parent": "MacHyperVSupport" 183 | }, 184 | "MmapDump.efi": { 185 | "parent": "OpenCorePkg", 186 | "res_type": "tool" 187 | }, 188 | "NVMeFix.kext": { 189 | "parent": "NVMeFix" 190 | }, 191 | "NoTouchID.kext": { 192 | "parent": "NoTouchID" 193 | }, 194 | "NvmExpressDxe.efi": { 195 | "parent": "OpenCorePkg", 196 | "res_type": "driver" 197 | }, 198 | "OpenCanopy.efi": { 199 | "parent": "OpenCorePkg", 200 | "res_type": "driver" 201 | }, 202 | "OpenControl.efi": { 203 | "parent": "OpenCorePkg", 204 | "res_type": "tool" 205 | }, 206 | "OpenCore.efi": { 207 | "parent": "OpenCorePkg" 208 | }, 209 | "OpenHfsPlus.efi": { 210 | "parent": "OpenCorePkg", 211 | "res_type": "driver" 212 | }, 213 | "OpenLinuxBoot.efi": { 214 | "parent": "OpenCorePkg", 215 | "res_type": "driver" 216 | }, 217 | "OpenNtfsDxe.efi": { 218 | "parent": "OpenCorePkg", 219 | "res_type": "driver" 220 | }, 221 | "OpenPartitionDxe.efi": { 222 | "parent": "OpenCorePkg", 223 | "res_type": "driver" 224 | }, 225 | "OpenRuntime.efi": { 226 | "parent": "OpenCorePkg", 227 | "res_type": "driver" 228 | }, 229 | "OpenShell.efi": { 230 | "parent": "OpenCorePkg", 231 | "res_type": "tool" 232 | }, 233 | "OpenUsbKbDxe.efi": { 234 | "parent": "OpenCorePkg", 235 | "res_type": "driver" 236 | }, 237 | "OpenVariableRuntimeDxe.efi": { 238 | "parent": "OpenCorePkg", 239 | "res_type": "driver" 240 | }, 241 | "PavpProvision.efi": { 242 | "parent": "OpenCorePkg" 243 | }, 244 | "PropertyTest.efi": { 245 | "parent": "OpenCorePkg" 246 | }, 247 | "PropertyTestApp.efi": { 248 | "parent": "OpenCorePkg" 249 | }, 250 | "Ps2KeyboardDxe.efi": { 251 | "parent": "OpenCorePkg", 252 | "res_type": "driver" 253 | }, 254 | "Ps2MouseDxe.efi": { 255 | "parent": "OpenCorePkg", 256 | "res_type": "driver" 257 | }, 258 | "RTCMemoryFixup.kext": { 259 | "parent": "RTCMemoryFixup" 260 | }, 261 | "RadeonGadget.app": { 262 | "parent": "RadeonSensor" 263 | }, 264 | "RadeonSensor.kext": { 265 | "parent": "RadeonSensor" 266 | }, 267 | "RealtekRTL8111.kext": { 268 | "parent": "RealtekRTL8111" 269 | }, 270 | "ResetNvramEntry.efi": { 271 | "parent": "OpenCorePkg", 272 | "res_type": "driver" 273 | }, 274 | "ResetSystem.efi": { 275 | "parent": "OpenCorePkg", 276 | "res_type": "tool" 277 | }, 278 | "RestrictEvents.kext": { 279 | "parent": "RestrictEvents" 280 | }, 281 | "RtcRw.efi": { 282 | "parent": "OpenCorePkg", 283 | "res_type": "tool" 284 | }, 285 | "SMCBatteryManager.kext": { 286 | "parent": "VirtualSMC" 287 | }, 288 | "SMCDellSensors.kext": { 289 | "parent": "VirtualSMC" 290 | }, 291 | "SMCLightSensor.kext": { 292 | "parent": "VirtualSMC" 293 | }, 294 | "SMCProcessor.kext": { 295 | "parent": "VirtualSMC" 296 | }, 297 | "SMCRadeonGPU.kext": { 298 | "parent": "RadeonSensor" 299 | }, 300 | "SMCSuperIO.kext": { 301 | "parent": "VirtualSMC" 302 | }, 303 | "SSDT-ALS0.aml": { 304 | "parent": "OpenCorePkg" 305 | }, 306 | "SSDT-AWAC-DISABLE.aml": { 307 | "parent": "OpenCorePkg" 308 | }, 309 | "SSDT-AWAC.aml": { 310 | "parent": "Getting-Started-With-ACPI" 311 | }, 312 | "SSDT-BRG0.aml": { 313 | "parent": "OpenCorePkg" 314 | }, 315 | "SSDT-CPUR.aml": { 316 | "parent": "Getting-Started-With-ACPI" 317 | }, 318 | "SSDT-EC-DESKTOP.aml": { 319 | "parent": "Getting-Started-With-ACPI" 320 | }, 321 | "SSDT-EC-LAPTOP.aml": { 322 | "parent": "Getting-Started-With-ACPI" 323 | }, 324 | "SSDT-EC-USBX-DESKTOP.aml": { 325 | "parent": "Getting-Started-With-ACPI" 326 | }, 327 | "SSDT-EC-USBX-LAPTOP.aml": { 328 | "parent": "Getting-Started-With-ACPI" 329 | }, 330 | "SSDT-EC-USBX.aml": { 331 | "parent": "OpenCorePkg" 332 | }, 333 | "SSDT-EC.aml": { 334 | "parent": "OpenCorePkg" 335 | }, 336 | "SSDT-EHCx-DISABLE.aml": { 337 | "parent": "OpenCorePkg" 338 | }, 339 | "SSDT-HV-CPU.aml": { 340 | "parent": "OpenCorePkg" 341 | }, 342 | "SSDT-HV-PLUG.aml": { 343 | "parent": "OpenCorePkg" 344 | }, 345 | "SSDT-HV-VMBUS.aml": { 346 | "parent": "OpenCorePkg" 347 | }, 348 | "SSDT-IMEI-S.aml": { 349 | "parent": "Getting-Started-With-ACPI" 350 | }, 351 | "SSDT-IMEI.aml": { 352 | "parent": "OpenCorePkg" 353 | }, 354 | "SSDT-PLUG-DRTNIA.aml": { 355 | "parent": "Getting-Started-With-ACPI" 356 | }, 357 | "SSDT-PLUG.aml": { 358 | "parent": "OpenCorePkg" 359 | }, 360 | "SSDT-PMC.aml": { 361 | "parent": "OpenCorePkg" 362 | }, 363 | "SSDT-PNLF-CFL.aml": { 364 | "parent": "Getting-Started-With-ACPI" 365 | }, 366 | "SSDT-PNLF.aml": { 367 | "parent": "OpenCorePkg" 368 | }, 369 | "SSDT-PNLFCFL.aml": { 370 | "parent": "OpenCorePkg" 371 | }, 372 | "SSDT-RHUB.aml": { 373 | "parent": "Getting-Started-With-ACPI" 374 | }, 375 | "SSDT-RTC0-RANGE-HEDT.aml": { 376 | "parent": "Getting-Started-With-ACPI" 377 | }, 378 | "SSDT-RTC0-RANGE.aml": { 379 | "parent": "OpenCorePkg" 380 | }, 381 | "SSDT-RTC0.aml": { 382 | "parent": "OpenCorePkg" 383 | }, 384 | "SSDT-SBUS-MCHC.aml": { 385 | "parent": "OpenCorePkg" 386 | }, 387 | "SSDT-UNC.aml": { 388 | "parent": "OpenCorePkg" 389 | }, 390 | "SSDT-XOSI.aml": { 391 | "parent": "Getting-Started-With-ACPI" 392 | }, 393 | "Shell.efi": { 394 | "parent": "OpenCorePkg" 395 | }, 396 | "SmallTreeIntel82576.kext": { 397 | "parent": "SmallTreeIntel82576" 398 | }, 399 | "SmbiosTest.efi": { 400 | "parent": "OpenCorePkg" 401 | }, 402 | "SmbiosTestApp.efi": { 403 | "parent": "OpenCorePkg" 404 | }, 405 | "TpmInfo.efi": { 406 | "parent": "OpenCorePkg", 407 | "res_type": "tool" 408 | }, 409 | "ToggleSipEntry.efi": { 410 | "parent": "OpenCorePkg", 411 | "res_type": "driver" 412 | }, 413 | "UEFIGraphicsFB.kext": { 414 | "parent": "UEFIGraphicsFB" 415 | }, 416 | "USBToolBox.kext": { 417 | "parent": "USBToolBox" 418 | }, 419 | "UsbMouseDxe.efi": { 420 | "parent": "OpenCorePkg", 421 | "res_type": "driver" 422 | }, 423 | "VerifyMemOpt.efi": { 424 | "parent": "OpenCorePkg" 425 | }, 426 | "VerifyMsrE2.efi": { 427 | "parent": "OpenCorePkg" 428 | }, 429 | "VirtualSMC.kext": { 430 | "parent": "VirtualSMC" 431 | }, 432 | "VoodooGPIO.kext": { 433 | "parent": "VoodooI2C" 434 | }, 435 | "VoodooI2C.kext": { 436 | "parent": "VoodooI2C" 437 | }, 438 | "VoodooI2CAtmelMXT.kext": { 439 | "parent": "VoodooI2C" 440 | }, 441 | "VoodooI2CELAN.kext": { 442 | "parent": "VoodooI2C" 443 | }, 444 | "VoodooI2CFTE.kext": { 445 | "parent": "VoodooI2C" 446 | }, 447 | "VoodooI2CHID.kext": { 448 | "parent": "VoodooI2C" 449 | }, 450 | "VoodooI2CServices.kext": { 451 | "parent": "VoodooI2C" 452 | }, 453 | "VoodooI2CSynaptics.kext": { 454 | "parent": "VoodooI2C" 455 | }, 456 | "VoodooInput.kext": { 457 | "parent": "VoodooInput" 458 | }, 459 | "VoodooPS2Controller.kext": { 460 | "parent": "VoodooPS2" 461 | }, 462 | "VoodooPS2Keyboard.kext": { 463 | "parent": "VoodooPS2" 464 | }, 465 | "VoodooPS2Mouse.kext": { 466 | "parent": "VoodooPS2" 467 | }, 468 | "VoodooPS2Trackpad.kext": { 469 | "parent": "VoodooPS2" 470 | }, 471 | "VoodooRMI.kext": { 472 | "parent": "VoodooRMI" 473 | }, 474 | "VoodooSMBus.kext": { 475 | "parent": "VoodooSMBus" 476 | }, 477 | "RMII2C.kext": { 478 | "parent": "VoodooRMI" 479 | }, 480 | "RMISMBus.kext": { 481 | "parent": "VoodooRMI" 482 | }, 483 | "WhateverGreen.kext": { 484 | "parent": "WhateverGreen" 485 | }, 486 | "XhciDxe.efi": { 487 | "parent": "OpenCorePkg", 488 | "res_type": "driver" 489 | }, 490 | "btrfs_x64.efi": { 491 | "parent": "OcBinaryData", 492 | "res_type": "driver" 493 | }, 494 | "ext4_x64.efi": { 495 | "parent": "OcBinaryData", 496 | "res_type": "driver" 497 | } 498 | } 499 | --------------------------------------------------------------------------------