thindx/headers/d3dcompiler.h/dll/blobs.rs
1use crate::*;
2use crate::d3d::*;
3
4use std::path::*;
5use std::ptr::*;
6
7/// <h1 id="blobs" class="section-header"><a href="#blobs">ReadOnlyBlob Utilities</a></h1>
8impl Compiler {
9 /// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/d3dcompiler/nf-d3dcompiler-d3dcreateblob)\]
10 /// D3DCreateBlob
11 ///
12 /// Compresses a set of shaders into a more compact form.
13 ///
14 /// ### Arguments
15 /// * `data` - The data to create a [ReadOnlyBlob] out of.
16 ///
17 /// ### Errors
18 /// * [THINERR::MISSING_DLL_EXPORT] - `d3dcompiler_42.dll` and earlier
19 ///
20 /// ### Example
21 /// ```rust
22 /// # use thindx::d3d::*; let d3dc = Compiler::load_system(47).unwrap();
23 /// let blob = d3dc.create_read_only_blob(&[1,2,3,4]).unwrap();
24 /// assert_eq!(blob.get_buffer_size(), 4 );
25 /// assert_eq!(blob.get_buffer(), &[1,2,3,4] );
26 /// ```
27 ///
28 /// ### Remarks
29 /// * This was introduced by d3dcompiler_43.dll, and is unavailable in earlier versions.
30 pub fn create_read_only_blob(&self, data: &[u8]) -> Result<ReadOnlyBlob, MethodError> {
31 let f = self.D3DCreateBlob.ok_or(MethodError("D3DCreateBlob", THINERR::MISSING_DLL_EXPORT))?;
32
33 // SAFETY: ❌ needs fuzz testing against ~4GB `data` to attempt to induce alloc overflow bugs
34 // * `f` should be valid/sound like all `self.*`
35 // * `blob` is a trivial out param.
36 let mut blob = null_mut();
37 let hr = unsafe { f(data.len(), &mut blob) };
38 MethodError::check("D3DCreateBlob", hr)?;
39
40 if !blob.is_null() {
41 // SAFETY: ⚠️ see earlier safety comments about ~4GB overflow concerns
42 // * `T` is `u8`, no lifetime/drop concerns etc.
43 // * `blob` is non-null, non-dangling, and should be a valid ID3DBlob
44 // * read is within `data`'s range
45 // * write *should* be within `blob`'s range, unless `D3DCreateBlob` earlier has overflow bugs
46 unsafe { std::ptr::copy_nonoverlapping(data.as_ptr(), (*blob).GetBufferPointer().cast(), data.len()) };
47 }
48
49 // SAFETY: ✔️
50 // * `blob` should be null (panics) or a valid pointer.
51 // * `ReadOnlyBlob` imposes no restrictions on `blob`'s contents.
52 Ok(unsafe { ReadOnlyBlob::from_raw(blob) })
53 }
54
55 /// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/d3dcompiler/nf-d3dcompiler-d3dreadfiletoblob)\]
56 /// D3DReadFileToBlob
57 ///
58 /// > **Note:** You can use this API to develop your Windows Store apps, but you can't use it in apps that you submit to the Windows Store.
59 ///
60 /// Reads a file into memory.
61 ///
62 /// ### Arguments
63 /// * `file_name` - The path to read the blob from.
64 ///
65 /// ### Errors
66 /// * [THINERR::MISSING_DLL_EXPORT] - `d3dcompiler_43.dll` and earlier
67 /// * [ERROR::FILE_NOT_FOUND] - `file_name` not found
68 /// * [ERROR::ACCESS_DENIED] - Access denied (`file_name` not a file? bad perms? ...?)
69 ///
70 /// ### Example
71 /// ```rust
72 /// # use thindx::{*, d3d::*};
73 /// # use winapi::shared::winerror::*;
74 /// # let d3dc = Compiler::load_system(47).unwrap();
75 /// let blob : ReadOnlyBlob = d3dc.read_file_to_blob(r"test\data\basic.hlsl").unwrap();
76 ///
77 /// let err = d3dc.read_file_to_blob(r"test\data\nonexistant").err().unwrap();
78 /// assert_eq!(err.kind(), ErrorKind::from_win32(ERROR_FILE_NOT_FOUND));
79 ///
80 /// let err = d3dc.read_file_to_blob(r"test\data").err().unwrap();
81 /// assert_eq!(err.kind(), ErrorKind::from_win32(ERROR_ACCESS_DENIED));
82 /// ```
83 ///
84 /// ### Remarks
85 /// * This was introduced by d3dcompiler_44.dll, and is unavailable in earlier versions.
86 pub fn read_file_to_blob(&self, file_name: impl AsRef<Path>) -> Result<ReadOnlyBlob, MethodError> {
87 let f = self.D3DReadFileToBlob.ok_or(MethodError("D3DReadFileToBlob", THINERR::MISSING_DLL_EXPORT))?;
88 let file_name = file_name.to_wcstr("D3DReadFileToBlob")?;
89
90 // SAFETY: ❌ needs fuzz testing against ~4GB files to attempt to induce alloc overflow bugs
91 // * `f` should be valid/sound like all `self.*`
92 // * `file_name` is `\0` terminated per `to_wcstr`.
93 // * `blob` is a trivial out param.
94 let mut blob = null_mut();
95 let hr = unsafe { f(file_name.as_ptr(), &mut blob) };
96 MethodError::check("D3DReadFileToBlob", hr)?;
97
98 // SAFETY: ✔️
99 // * `blob` should be null (panics) or non-dangling, and should be a valid ID3DBlob
100 // * `ReadOnlyBlob` imposes no restrictions on `blob`'s contents.
101 Ok(unsafe { ReadOnlyBlob::from_raw(blob) })
102 }
103
104 /// \[[docs.microsoft.com](https://docs.microsoft.com/en-us/windows/win32/api/d3dcompiler/nf-d3dcompiler-d3dwriteblobtofile)\]
105 /// D3DWriteBlobToFile
106 ///
107 /// > **Note:** You can use this API to develop your Windows Store apps, but you can't use it in apps that you submit to the Windows Store.
108 ///
109 /// Writes a memory blob to a file on disk.
110 ///
111 /// ### Arguments
112 /// * `blob` - The blob of data to write to disk.
113 /// * `file_name` - The path to write it to.
114 /// * `overwrite` - Overwrite any existing file.
115 ///
116 /// ### Errors
117 /// * [THINERR::MISSING_DLL_EXPORT] - `d3dcompiler_43.dll` and earlier
118 /// * [ERROR::PATH_NOT_FOUND] - Path not found (missing filename in `file_name`)
119 /// * [ERROR::ACCESS_DENIED] - Access denied (target `file_name` is a directory?)
120 /// * [ERROR::FILE_EXISTS] - `file_name` already exists (if `!overwrite`)
121 ///
122 /// ### Example
123 /// ```rust
124 /// # use thindx::{*, d3d::*};
125 /// # use winapi::shared::winerror::*;
126 /// # let d3dc = Compiler::load_system(47).unwrap();
127 /// let blob = d3dc.create_read_only_blob(&[1,2,3,4]).unwrap();
128 /// d3dc.write_blob_to_file(&blob, r"..\target\1234.bin", true).unwrap();
129 ///
130 /// let err = d3dc.write_blob_to_file(&blob, r"..\target\1234.bin", false).unwrap_err();
131 /// assert_eq!(err.kind(), ErrorKind::from_win32(ERROR_FILE_EXISTS));
132 ///
133 /// let err = d3dc.write_blob_to_file(&blob, r"..\target\", false).unwrap_err();
134 /// assert_eq!(err.kind(), ErrorKind::from_win32(ERROR_PATH_NOT_FOUND));
135 ///
136 /// let err = d3dc.write_blob_to_file(&blob, r"..\target", false).unwrap_err();
137 /// assert_eq!(err.kind(), ErrorKind::from_win32(ERROR_ACCESS_DENIED));
138 /// ```
139 ///
140 /// ### Remarks
141 /// * This was introduced by d3dcompiler_44.dll, and is unavailable in earlier versions.
142 pub fn write_blob_to_file(
143 &self,
144 blob: &ReadOnlyBlob,
145 file_name: impl AsRef<Path>,
146 overwrite: bool,
147 ) -> Result<(), MethodError> {
148 let f = self.D3DWriteBlobToFile.ok_or(MethodError("D3DWriteBlobToFile", THINERR::MISSING_DLL_EXPORT))?;
149 let file_name = file_name.to_wcstr("D3DWriteBlobToFile")?;
150
151 // SAFETY: ✔️
152 // * `f` should be valid/sound like all `self.*`
153 // * `file_name` is `\0` terminated per `to_wcstr`.
154 // * `overwrite` is a trivial well tested bool.
155 let hr = unsafe { f(blob.as_raw(), file_name.as_ptr(), overwrite.into()) };
156 MethodError::check("D3DWriteBlobToFile", hr)
157 }
158}