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"
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.
30 typedef ULONG EncodedLenT
;
34 class MOZ_NON_TEMPORARY_CLASS StructToStream
{
37 * This constructor variant represents an empty/null struct to be serialized.
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
),
49 ::MesEncodeDynBufferHandleCreate(&mBuffer
, &mEncodedLen
, &mHandle
);
50 if (mStatus
!= RPC_S_OK
) {
54 MOZ_SEH_TRY
{ aEncodeFnPtr(mHandle
, &aSrcStruct
); }
55 #ifdef HAVE_SEH_EXCEPTIONS
56 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
57 mStatus
= ::RpcExceptionCode();
62 if (!mBuffer
|| !mEncodedLen
) {
63 mStatus
= RPC_X_NO_MEMORY
;
70 ::MesHandleFree(mHandle
);
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
) {
96 if (mStatus
!= RPC_S_OK
) {
102 aDestStream
->Write(&mEncodedLen
, sizeof(mEncodedLen
), &bytesWritten
);
106 if (bytesWritten
!= sizeof(mEncodedLen
)) {
110 if (mBuffer
&& mEncodedLen
) {
111 hr
= aDestStream
->Write(mBuffer
, mEncodedLen
, &bytesWritten
);
115 if (bytesWritten
!= mEncodedLen
) {
123 StructToStream(const StructToStream
&) = delete;
124 StructToStream(StructToStream
&&) = delete;
125 StructToStream
& operator=(const StructToStream
&) = delete;
126 StructToStream
& operator=(StructToStream
&&) = delete;
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;
143 explicit StructFromStream(IStream
* aStream
)
144 : mStatus(RPC_X_INVALID_BUFFER
), mHandle(nullptr) {
147 // Read the length of the encoded data first
148 detail::EncodedLenT encodedLen
= 0;
150 HRESULT hr
= aStream
->Read(&encodedLen
, sizeof(encodedLen
), &bytesRead
);
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
;
163 if (bytesRead
!= sizeof(encodedLen
)) {
168 mStatus
= RPC_S_OBJECT_NOT_FOUND
;
172 MOZ_ASSERT(encodedLen
% kRpcReqdBufAlignment
== 0);
173 if (encodedLen
% kRpcReqdBufAlignment
) {
177 // This memory allocation is fallible
178 mEncodedBuffer
.reset(static_cast<char*>(
179 ::_aligned_malloc(encodedLen
, kRpcReqdBufAlignment
)));
180 if (!mEncodedBuffer
) {
184 ULONG bytesReadFromStream
= 0;
185 hr
= aStream
->Read(mEncodedBuffer
.get(), encodedLen
, &bytesReadFromStream
);
186 if (FAILED(hr
) || bytesReadFromStream
!= encodedLen
) {
190 mStatus
= ::MesDecodeBufferHandleCreate(mEncodedBuffer
.get(), encodedLen
,
194 ~StructFromStream() {
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
) {
210 // NB: Deserialization will fail with BSTRs unless the destination data
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();
225 StructFromStream(const StructFromStream
&) = delete;
226 StructFromStream(StructFromStream
&&) = delete;
227 StructFromStream
& operator=(const StructFromStream
&) = delete;
228 StructFromStream
& operator=(StructFromStream
&&) = delete;
233 UniquePtr
<char, AlignedFreeDeleter
> mEncodedBuffer
;
237 } // namespace mozilla
239 #endif // mozilla_mscom_StructStream_h