Bug 1761357 [wpt PR 33355] - Fix #33204: Move Safari stable runs to Big Sur, a=testonly
[gecko.git] / ipc / mscom / StructStream.h
blob45a32c7687e39d4233ba68bd74be9ae90aa1b616
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_mscom_StructStream_h
8 #define mozilla_mscom_StructStream_h
10 #include "mozilla/Attributes.h"
11 #include "mozilla/UniquePtr.h"
12 #include "nscore.h"
14 #include <memory.h>
15 #include <midles.h>
16 #include <objidl.h>
17 #include <rpc.h>
19 /**
20 * This code is used for (de)serializing data structures that have been
21 * declared using midl, thus allowing us to use Microsoft RPC for marshaling
22 * data for our COM handlers that may run in other processes that are not ours.
25 namespace mozilla {
26 namespace mscom {
28 namespace detail {
30 typedef ULONG EncodedLenT;
32 } // namespace detail
34 class MOZ_NON_TEMPORARY_CLASS StructToStream {
35 public:
36 /**
37 * This constructor variant represents an empty/null struct to be serialized.
39 StructToStream()
40 : mStatus(RPC_S_OK), mHandle(nullptr), mBuffer(nullptr), mEncodedLen(0) {}
42 template <typename StructT>
43 StructToStream(StructT& aSrcStruct, void (*aEncodeFnPtr)(handle_t, StructT*))
44 : mStatus(RPC_X_INVALID_BUFFER),
45 mHandle(nullptr),
46 mBuffer(nullptr),
47 mEncodedLen(0) {
48 mStatus =
49 ::MesEncodeDynBufferHandleCreate(&mBuffer, &mEncodedLen, &mHandle);
50 if (mStatus != RPC_S_OK) {
51 return;
54 MOZ_SEH_TRY { aEncodeFnPtr(mHandle, &aSrcStruct); }
55 #ifdef HAVE_SEH_EXCEPTIONS
56 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
57 mStatus = ::RpcExceptionCode();
58 return;
60 #endif
62 if (!mBuffer || !mEncodedLen) {
63 mStatus = RPC_X_NO_MEMORY;
64 return;
68 ~StructToStream() {
69 if (mHandle) {
70 ::MesHandleFree(mHandle);
72 if (mBuffer) {
73 // Bug 1440564: You'd think that MesHandleFree would free the buffer,
74 // since it was created by RPC, but it doesn't.
75 midl_user_free(mBuffer);
79 static unsigned long GetEmptySize() { return sizeof(detail::EncodedLenT); }
81 static HRESULT WriteEmpty(IStream* aDestStream) {
82 StructToStream emptyStruct;
83 return emptyStruct.Write(aDestStream);
86 explicit operator bool() const { return mStatus == RPC_S_OK; }
88 bool IsEmpty() const { return mStatus == RPC_S_OK && !mEncodedLen; }
90 unsigned long GetSize() const { return sizeof(mEncodedLen) + mEncodedLen; }
92 HRESULT Write(IStream* aDestStream) {
93 if (!aDestStream) {
94 return E_INVALIDARG;
96 if (mStatus != RPC_S_OK) {
97 return E_FAIL;
100 ULONG bytesWritten;
101 HRESULT hr =
102 aDestStream->Write(&mEncodedLen, sizeof(mEncodedLen), &bytesWritten);
103 if (FAILED(hr)) {
104 return hr;
106 if (bytesWritten != sizeof(mEncodedLen)) {
107 return E_UNEXPECTED;
110 if (mBuffer && mEncodedLen) {
111 hr = aDestStream->Write(mBuffer, mEncodedLen, &bytesWritten);
112 if (FAILED(hr)) {
113 return hr;
115 if (bytesWritten != mEncodedLen) {
116 return E_UNEXPECTED;
120 return hr;
123 StructToStream(const StructToStream&) = delete;
124 StructToStream(StructToStream&&) = delete;
125 StructToStream& operator=(const StructToStream&) = delete;
126 StructToStream& operator=(StructToStream&&) = delete;
128 private:
129 RPC_STATUS mStatus;
130 handle_t mHandle;
131 char* mBuffer;
132 detail::EncodedLenT mEncodedLen;
135 class MOZ_NON_TEMPORARY_CLASS StructFromStream {
136 struct AlignedFreeDeleter {
137 void operator()(void* aPtr) { ::_aligned_free(aPtr); }
140 static const detail::EncodedLenT kRpcReqdBufAlignment = 8;
142 public:
143 explicit StructFromStream(IStream* aStream)
144 : mStatus(RPC_X_INVALID_BUFFER), mHandle(nullptr) {
145 MOZ_ASSERT(aStream);
147 // Read the length of the encoded data first
148 detail::EncodedLenT encodedLen = 0;
149 ULONG bytesRead = 0;
150 HRESULT hr = aStream->Read(&encodedLen, sizeof(encodedLen), &bytesRead);
151 if (FAILED(hr)) {
152 return;
155 // NB: Some implementations of IStream return S_FALSE to indicate EOF,
156 // other implementations return S_OK and set the number of bytes read to 0.
157 // We must handle both.
158 if (hr == S_FALSE || !bytesRead) {
159 mStatus = RPC_S_OBJECT_NOT_FOUND;
160 return;
163 if (bytesRead != sizeof(encodedLen)) {
164 return;
167 if (!encodedLen) {
168 mStatus = RPC_S_OBJECT_NOT_FOUND;
169 return;
172 MOZ_ASSERT(encodedLen % kRpcReqdBufAlignment == 0);
173 if (encodedLen % kRpcReqdBufAlignment) {
174 return;
177 // This memory allocation is fallible
178 mEncodedBuffer.reset(static_cast<char*>(
179 ::_aligned_malloc(encodedLen, kRpcReqdBufAlignment)));
180 if (!mEncodedBuffer) {
181 return;
184 ULONG bytesReadFromStream = 0;
185 hr = aStream->Read(mEncodedBuffer.get(), encodedLen, &bytesReadFromStream);
186 if (FAILED(hr) || bytesReadFromStream != encodedLen) {
187 return;
190 mStatus = ::MesDecodeBufferHandleCreate(mEncodedBuffer.get(), encodedLen,
191 &mHandle);
194 ~StructFromStream() {
195 if (mHandle) {
196 ::MesHandleFree(mHandle);
200 explicit operator bool() const { return mStatus == RPC_S_OK || IsEmpty(); }
202 bool IsEmpty() const { return mStatus == RPC_S_OBJECT_NOT_FOUND; }
204 template <typename StructT>
205 bool Read(StructT* aDestStruct, void (*aDecodeFnPtr)(handle_t, StructT*)) {
206 if (!aDestStruct || !aDecodeFnPtr || mStatus != RPC_S_OK) {
207 return false;
210 // NB: Deserialization will fail with BSTRs unless the destination data
211 // is zeroed out!
212 ZeroMemory(aDestStruct, sizeof(StructT));
214 MOZ_SEH_TRY { aDecodeFnPtr(mHandle, aDestStruct); }
215 #ifdef HAVE_SEH_EXCEPTIONS
216 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
217 mStatus = ::RpcExceptionCode();
218 return false;
220 #endif
222 return true;
225 StructFromStream(const StructFromStream&) = delete;
226 StructFromStream(StructFromStream&&) = delete;
227 StructFromStream& operator=(const StructFromStream&) = delete;
228 StructFromStream& operator=(StructFromStream&&) = delete;
230 private:
231 RPC_STATUS mStatus;
232 handle_t mHandle;
233 UniquePtr<char, AlignedFreeDeleter> mEncodedBuffer;
236 } // namespace mscom
237 } // namespace mozilla
239 #endif // mozilla_mscom_StructStream_h