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}