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 #include "mozilla/mscom/Objref.h"
9 #include "mozilla/Assertions.h"
10 #include "mozilla/mscom/Utils.h"
11 #include "mozilla/RefPtr.h"
12 #include "mozilla/ScopeExit.h"
13 #include "mozilla/UniquePtr.h"
19 // {00000027-0000-0008-C000-000000000046}
20 static const GUID CLSID_AggStdMarshal
= {
21 0x27, 0x0, 0x8, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
28 typedef uint64_t OXID
;
39 enum STDOBJREF_FLAGS
{ SORF_PING
= 0, SORF_NOPING
= 0x1000 };
41 struct DUALSTRINGARRAY
{
42 static size_t SizeFromNumEntries(const uint16_t aNumEntries
) {
43 return sizeof(mNumEntries
) + sizeof(mSecurityOffset
) +
44 aNumEntries
* sizeof(uint16_t);
47 size_t SizeOf() const { return SizeFromNumEntries(mNumEntries
); }
50 uint16_t mSecurityOffset
;
51 uint16_t mStringArray
[1]; // Length is mNumEntries
54 struct OBJREF_STANDARD
{
55 static size_t SizeOfFixedLenHeader() { return sizeof(mStd
); }
57 size_t SizeOf() const { return SizeOfFixedLenHeader() + mResAddr
.SizeOf(); }
60 DUALSTRINGARRAY mResAddr
;
63 struct OBJREF_HANDLER
{
64 static size_t SizeOfFixedLenHeader() { return sizeof(mStd
) + sizeof(mClsid
); }
66 size_t SizeOf() const { return SizeOfFixedLenHeader() + mResAddr
.SizeOf(); }
70 DUALSTRINGARRAY mResAddr
;
73 struct OBJREF_CUSTOM
{
74 static size_t SizeOfFixedLenHeader() {
75 return sizeof(mClsid
) + sizeof(mCbExtension
) + sizeof(mReserved
);
79 uint32_t mCbExtension
;
85 OBJREF_TYPE_STANDARD
= 0x00000001UL
,
86 OBJREF_TYPE_HANDLER
= 0x00000002UL
,
87 OBJREF_TYPE_CUSTOM
= 0x00000004UL
,
88 OBJREF_TYPE_EXTENDED
= 0x00000008UL
,
92 static size_t SizeOfFixedLenHeader(OBJREF_FLAGS aFlags
) {
93 size_t size
= sizeof(mSignature
) + sizeof(mFlags
) + sizeof(mIid
);
96 case OBJREF_TYPE_STANDARD
:
97 size
+= OBJREF_STANDARD::SizeOfFixedLenHeader();
99 case OBJREF_TYPE_HANDLER
:
100 size
+= OBJREF_HANDLER::SizeOfFixedLenHeader();
102 case OBJREF_TYPE_CUSTOM
:
103 size
+= OBJREF_CUSTOM::SizeOfFixedLenHeader();
106 MOZ_ASSERT_UNREACHABLE("Unsupported OBJREF type");
113 size_t SizeOf() const {
114 size_t size
= sizeof(mSignature
) + sizeof(mFlags
) + sizeof(mIid
);
117 case OBJREF_TYPE_STANDARD
:
118 size
+= mObjRefStd
.SizeOf();
120 case OBJREF_TYPE_HANDLER
:
121 size
+= mObjRefHandler
.SizeOf();
124 MOZ_ASSERT_UNREACHABLE("Unsupported OBJREF type");
135 OBJREF_STANDARD mObjRefStd
;
136 OBJREF_HANDLER mObjRefHandler
;
137 OBJREF_CUSTOM mObjRefCustom
;
138 // There are others but we're not supporting them here
142 enum OBJREF_SIGNATURES
{ OBJREF_SIGNATURE
= 0x574F454DUL
};
146 struct ByteArrayDeleter
{
147 void operator()(void* aPtr
) { delete[] reinterpret_cast<uint8_t*>(aPtr
); }
150 template <typename T
>
151 using VarStructUniquePtr
= mozilla::UniquePtr
<T
, ByteArrayDeleter
>;
153 } // anonymous namespace
158 bool StripHandlerFromOBJREF(NotNull
<IStream
*> aStream
, const uint64_t aStartPos
,
159 const uint64_t aEndPos
) {
160 // Ensure that the current stream position is set to the beginning
161 LARGE_INTEGER seekTo
;
162 seekTo
.QuadPart
= aStartPos
;
164 HRESULT hr
= aStream
->Seek(seekTo
, STREAM_SEEK_SET
, nullptr);
172 hr
= aStream
->Read(&signature
, sizeof(signature
), &bytesRead
);
173 if (FAILED(hr
) || bytesRead
!= sizeof(signature
) ||
174 signature
!= OBJREF_SIGNATURE
) {
179 hr
= aStream
->Read(&type
, sizeof(type
), &bytesRead
);
180 if (FAILED(hr
) || bytesRead
!= sizeof(type
)) {
183 if (type
!= OBJREF_TYPE_HANDLER
) {
184 // If we're not a handler then just seek to the end of the OBJREF and return
185 // success; there is nothing left to do.
186 seekTo
.QuadPart
= aEndPos
;
187 return SUCCEEDED(aStream
->Seek(seekTo
, STREAM_SEEK_SET
, nullptr));
191 hr
= aStream
->Read(&iid
, sizeof(iid
), &bytesRead
);
192 if (FAILED(hr
) || bytesRead
!= sizeof(iid
) || !IsValidGUID(iid
)) {
196 // Seek past fixed-size STDOBJREF and CLSID
197 seekTo
.QuadPart
= sizeof(STDOBJREF
) + sizeof(CLSID
);
198 hr
= aStream
->Seek(seekTo
, STREAM_SEEK_CUR
, nullptr);
204 hr
= aStream
->Read(&numEntries
, sizeof(numEntries
), &bytesRead
);
205 if (FAILED(hr
) || bytesRead
!= sizeof(numEntries
)) {
209 // We'll try to use a stack buffer if resAddrSize <= kMinDualStringArraySize
210 const uint32_t kMinDualStringArraySize
= 12;
211 uint16_t staticResAddrBuf
[kMinDualStringArraySize
/ sizeof(uint16_t)];
213 size_t resAddrSize
= DUALSTRINGARRAY::SizeFromNumEntries(numEntries
);
215 DUALSTRINGARRAY
* resAddr
;
216 VarStructUniquePtr
<DUALSTRINGARRAY
> dynamicResAddrBuf
;
218 if (resAddrSize
<= kMinDualStringArraySize
) {
219 resAddr
= reinterpret_cast<DUALSTRINGARRAY
*>(staticResAddrBuf
);
221 dynamicResAddrBuf
.reset(
222 reinterpret_cast<DUALSTRINGARRAY
*>(new uint8_t[resAddrSize
]));
223 resAddr
= dynamicResAddrBuf
.get();
226 resAddr
->mNumEntries
= numEntries
;
228 // Because we've already read numEntries
229 ULONG bytesToRead
= resAddrSize
- sizeof(numEntries
);
231 hr
= aStream
->Read(&resAddr
->mSecurityOffset
, bytesToRead
, &bytesRead
);
232 if (FAILED(hr
) || bytesRead
!= bytesToRead
) {
236 // Signature doesn't change so we'll seek past that
237 seekTo
.QuadPart
= aStartPos
+ sizeof(signature
);
238 hr
= aStream
->Seek(seekTo
, STREAM_SEEK_SET
, nullptr);
245 uint32_t newType
= OBJREF_TYPE_STANDARD
;
246 hr
= aStream
->Write(&newType
, sizeof(newType
), &bytesWritten
);
247 if (FAILED(hr
) || bytesWritten
!= sizeof(newType
)) {
251 // Skip past IID and STDOBJREF since those don't change
252 seekTo
.QuadPart
= sizeof(IID
) + sizeof(STDOBJREF
);
253 hr
= aStream
->Seek(seekTo
, STREAM_SEEK_CUR
, nullptr);
258 hr
= aStream
->Write(resAddr
, resAddrSize
, &bytesWritten
);
259 if (FAILED(hr
) || bytesWritten
!= resAddrSize
) {
263 // The difference between a OBJREF_STANDARD and an OBJREF_HANDLER is
264 // sizeof(CLSID), so we'll zero out the remaining bytes.
265 hr
= aStream
->Write(&CLSID_NULL
, sizeof(CLSID
), &bytesWritten
);
266 if (FAILED(hr
) || bytesWritten
!= sizeof(CLSID
)) {
270 // Back up to the end of the tweaked OBJREF.
271 // There are now sizeof(CLSID) less bytes.
272 // Bug 1403180: Using -sizeof(CLSID) with a relative seek sometimes
273 // doesn't work on Windows 7.
274 // It succeeds, but doesn't seek the stream for some unknown reason.
275 // Use an absolute seek instead.
276 seekTo
.QuadPart
= aEndPos
- sizeof(CLSID
);
277 return SUCCEEDED(aStream
->Seek(seekTo
, STREAM_SEEK_SET
, nullptr));
280 uint32_t GetOBJREFSize(NotNull
<IStream
*> aStream
) {
281 // Make a clone so that we don't manipulate aStream's seek pointer
282 RefPtr
<IStream
> cloned
;
283 HRESULT hr
= aStream
->Clone(getter_AddRefs(cloned
));
288 uint32_t accumulatedSize
= 0;
293 hr
= cloned
->Read(&signature
, sizeof(signature
), &bytesRead
);
294 if (FAILED(hr
) || bytesRead
!= sizeof(signature
) ||
295 signature
!= OBJREF_SIGNATURE
) {
299 accumulatedSize
+= bytesRead
;
302 hr
= cloned
->Read(&type
, sizeof(type
), &bytesRead
);
303 if (FAILED(hr
) || bytesRead
!= sizeof(type
)) {
307 accumulatedSize
+= bytesRead
;
310 hr
= cloned
->Read(&iid
, sizeof(iid
), &bytesRead
);
311 if (FAILED(hr
) || bytesRead
!= sizeof(iid
) || !IsValidGUID(iid
)) {
315 accumulatedSize
+= bytesRead
;
317 LARGE_INTEGER seekTo
;
319 if (type
== OBJREF_TYPE_CUSTOM
) {
321 hr
= cloned
->Read(&clsid
, sizeof(CLSID
), &bytesRead
);
322 if (FAILED(hr
) || bytesRead
!= sizeof(CLSID
)) {
326 if (clsid
!= CLSID_StdMarshal
&& clsid
!= CLSID_AggStdMarshal
) {
327 // We can only calulate the size if the payload is a standard OBJREF as
328 // identified by clsid being CLSID_StdMarshal or CLSID_AggStdMarshal.
329 // (CLSID_AggStdMarshal, the aggregated standard marshaler, is used when
330 // the handler marshals an interface.)
334 accumulatedSize
+= bytesRead
;
337 sizeof(OBJREF_CUSTOM::mCbExtension
) + sizeof(OBJREF_CUSTOM::mReserved
);
338 hr
= cloned
->Seek(seekTo
, STREAM_SEEK_CUR
, nullptr);
343 accumulatedSize
+= seekTo
.LowPart
;
345 uint32_t payloadLen
= GetOBJREFSize(WrapNotNull(cloned
.get()));
350 accumulatedSize
+= payloadLen
;
351 return accumulatedSize
;
355 case OBJREF_TYPE_STANDARD
:
356 seekTo
.QuadPart
= OBJREF_STANDARD::SizeOfFixedLenHeader();
358 case OBJREF_TYPE_HANDLER
:
359 seekTo
.QuadPart
= OBJREF_HANDLER::SizeOfFixedLenHeader();
365 hr
= cloned
->Seek(seekTo
, STREAM_SEEK_CUR
, nullptr);
370 accumulatedSize
+= seekTo
.LowPart
;
373 hr
= cloned
->Read(&numEntries
, sizeof(numEntries
), &bytesRead
);
374 if (FAILED(hr
) || bytesRead
!= sizeof(numEntries
)) {
378 accumulatedSize
+= DUALSTRINGARRAY::SizeFromNumEntries(numEntries
);
379 return accumulatedSize
;
382 bool SetIID(NotNull
<IStream
*> aStream
, const uint64_t aStart
, REFIID aNewIid
) {
383 ULARGE_INTEGER initialStreamPos
;
385 LARGE_INTEGER seekTo
;
386 seekTo
.QuadPart
= 0LL;
387 HRESULT hr
= aStream
->Seek(seekTo
, STREAM_SEEK_CUR
, &initialStreamPos
);
392 auto resetStreamPos
= MakeScopeExit([&]() {
393 seekTo
.QuadPart
= initialStreamPos
.QuadPart
;
394 hr
= aStream
->Seek(seekTo
, STREAM_SEEK_SET
, nullptr);
395 MOZ_DIAGNOSTIC_ASSERT(SUCCEEDED(hr
));
399 aStart
+ sizeof(OBJREF::mSignature
) + sizeof(OBJREF::mFlags
);
400 hr
= aStream
->Seek(seekTo
, STREAM_SEEK_SET
, nullptr);
406 hr
= aStream
->Write(&aNewIid
, sizeof(IID
), &bytesWritten
);
407 return SUCCEEDED(hr
) && bytesWritten
== sizeof(IID
);
411 } // namespace mozilla