Bug 1828719 - Remove omnijar Gradle project from srcdir r=geckoview-reviewers,nalexan...
[gecko.git] / ipc / mscom / Objref.cpp
blob37108c71ac1f6e5acb754db5ad44e16a99121412
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"
15 #include <guiddef.h>
16 #include <objidl.h>
17 #include <winnt.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}};
23 namespace {
25 #pragma pack(push, 1)
27 typedef uint64_t OID;
28 typedef uint64_t OXID;
29 typedef GUID IPID;
31 struct STDOBJREF {
32 uint32_t mFlags;
33 uint32_t mPublicRefs;
34 OXID mOxid;
35 OID mOid;
36 IPID mIpid;
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); }
49 uint16_t 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(); }
59 STDOBJREF mStd;
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(); }
68 STDOBJREF mStd;
69 CLSID mClsid;
70 DUALSTRINGARRAY mResAddr;
73 struct OBJREF_CUSTOM {
74 static size_t SizeOfFixedLenHeader() {
75 return sizeof(mClsid) + sizeof(mCbExtension) + sizeof(mReserved);
78 CLSID mClsid;
79 uint32_t mCbExtension;
80 uint32_t mReserved;
81 uint8_t mPayload[1];
84 enum OBJREF_FLAGS {
85 OBJREF_TYPE_STANDARD = 0x00000001UL,
86 OBJREF_TYPE_HANDLER = 0x00000002UL,
87 OBJREF_TYPE_CUSTOM = 0x00000004UL,
88 OBJREF_TYPE_EXTENDED = 0x00000008UL,
91 struct OBJREF {
92 static size_t SizeOfFixedLenHeader(OBJREF_FLAGS aFlags) {
93 size_t size = sizeof(mSignature) + sizeof(mFlags) + sizeof(mIid);
95 switch (aFlags) {
96 case OBJREF_TYPE_STANDARD:
97 size += OBJREF_STANDARD::SizeOfFixedLenHeader();
98 break;
99 case OBJREF_TYPE_HANDLER:
100 size += OBJREF_HANDLER::SizeOfFixedLenHeader();
101 break;
102 case OBJREF_TYPE_CUSTOM:
103 size += OBJREF_CUSTOM::SizeOfFixedLenHeader();
104 break;
105 default:
106 MOZ_ASSERT_UNREACHABLE("Unsupported OBJREF type");
107 return 0;
110 return size;
113 size_t SizeOf() const {
114 size_t size = sizeof(mSignature) + sizeof(mFlags) + sizeof(mIid);
116 switch (mFlags) {
117 case OBJREF_TYPE_STANDARD:
118 size += mObjRefStd.SizeOf();
119 break;
120 case OBJREF_TYPE_HANDLER:
121 size += mObjRefHandler.SizeOf();
122 break;
123 default:
124 MOZ_ASSERT_UNREACHABLE("Unsupported OBJREF type");
125 return 0;
128 return size;
131 uint32_t mSignature;
132 uint32_t mFlags;
133 IID mIid;
134 union {
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 };
144 #pragma pack(pop)
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
155 namespace mozilla {
156 namespace mscom {
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);
165 if (FAILED(hr)) {
166 return false;
169 ULONG bytesRead;
171 uint32_t signature;
172 hr = aStream->Read(&signature, sizeof(signature), &bytesRead);
173 if (FAILED(hr) || bytesRead != sizeof(signature) ||
174 signature != OBJREF_SIGNATURE) {
175 return false;
178 uint32_t type;
179 hr = aStream->Read(&type, sizeof(type), &bytesRead);
180 if (FAILED(hr) || bytesRead != sizeof(type)) {
181 return false;
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));
190 IID iid;
191 hr = aStream->Read(&iid, sizeof(iid), &bytesRead);
192 if (FAILED(hr) || bytesRead != sizeof(iid) || !IsValidGUID(iid)) {
193 return false;
196 // Seek past fixed-size STDOBJREF and CLSID
197 seekTo.QuadPart = sizeof(STDOBJREF) + sizeof(CLSID);
198 hr = aStream->Seek(seekTo, STREAM_SEEK_CUR, nullptr);
199 if (FAILED(hr)) {
200 return false;
203 uint16_t numEntries;
204 hr = aStream->Read(&numEntries, sizeof(numEntries), &bytesRead);
205 if (FAILED(hr) || bytesRead != sizeof(numEntries)) {
206 return false;
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);
220 } else {
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) {
233 return false;
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);
239 if (FAILED(hr)) {
240 return false;
243 ULONG bytesWritten;
245 uint32_t newType = OBJREF_TYPE_STANDARD;
246 hr = aStream->Write(&newType, sizeof(newType), &bytesWritten);
247 if (FAILED(hr) || bytesWritten != sizeof(newType)) {
248 return false;
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);
254 if (FAILED(hr)) {
255 return false;
258 hr = aStream->Write(resAddr, resAddrSize, &bytesWritten);
259 if (FAILED(hr) || bytesWritten != resAddrSize) {
260 return false;
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)) {
267 return false;
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));
284 if (FAILED(hr)) {
285 return 0;
288 uint32_t accumulatedSize = 0;
290 ULONG bytesRead;
292 uint32_t signature;
293 hr = cloned->Read(&signature, sizeof(signature), &bytesRead);
294 if (FAILED(hr) || bytesRead != sizeof(signature) ||
295 signature != OBJREF_SIGNATURE) {
296 return 0;
299 accumulatedSize += bytesRead;
301 uint32_t type;
302 hr = cloned->Read(&type, sizeof(type), &bytesRead);
303 if (FAILED(hr) || bytesRead != sizeof(type)) {
304 return 0;
307 accumulatedSize += bytesRead;
309 IID iid;
310 hr = cloned->Read(&iid, sizeof(iid), &bytesRead);
311 if (FAILED(hr) || bytesRead != sizeof(iid) || !IsValidGUID(iid)) {
312 return 0;
315 accumulatedSize += bytesRead;
317 LARGE_INTEGER seekTo;
319 if (type == OBJREF_TYPE_CUSTOM) {
320 CLSID clsid;
321 hr = cloned->Read(&clsid, sizeof(CLSID), &bytesRead);
322 if (FAILED(hr) || bytesRead != sizeof(CLSID)) {
323 return 0;
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.)
331 return 0;
334 accumulatedSize += bytesRead;
336 seekTo.QuadPart =
337 sizeof(OBJREF_CUSTOM::mCbExtension) + sizeof(OBJREF_CUSTOM::mReserved);
338 hr = cloned->Seek(seekTo, STREAM_SEEK_CUR, nullptr);
339 if (FAILED(hr)) {
340 return 0;
343 accumulatedSize += seekTo.LowPart;
345 uint32_t payloadLen = GetOBJREFSize(WrapNotNull(cloned.get()));
346 if (!payloadLen) {
347 return 0;
350 accumulatedSize += payloadLen;
351 return accumulatedSize;
354 switch (type) {
355 case OBJREF_TYPE_STANDARD:
356 seekTo.QuadPart = OBJREF_STANDARD::SizeOfFixedLenHeader();
357 break;
358 case OBJREF_TYPE_HANDLER:
359 seekTo.QuadPart = OBJREF_HANDLER::SizeOfFixedLenHeader();
360 break;
361 default:
362 return 0;
365 hr = cloned->Seek(seekTo, STREAM_SEEK_CUR, nullptr);
366 if (FAILED(hr)) {
367 return 0;
370 accumulatedSize += seekTo.LowPart;
372 uint16_t numEntries;
373 hr = cloned->Read(&numEntries, sizeof(numEntries), &bytesRead);
374 if (FAILED(hr) || bytesRead != sizeof(numEntries)) {
375 return 0;
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);
388 if (FAILED(hr)) {
389 return false;
392 auto resetStreamPos = MakeScopeExit([&]() {
393 seekTo.QuadPart = initialStreamPos.QuadPart;
394 hr = aStream->Seek(seekTo, STREAM_SEEK_SET, nullptr);
395 MOZ_DIAGNOSTIC_ASSERT(SUCCEEDED(hr));
398 seekTo.QuadPart =
399 aStart + sizeof(OBJREF::mSignature) + sizeof(OBJREF::mFlags);
400 hr = aStream->Seek(seekTo, STREAM_SEEK_SET, nullptr);
401 if (FAILED(hr)) {
402 return false;
405 ULONG bytesWritten;
406 hr = aStream->Write(&aNewIid, sizeof(IID), &bytesWritten);
407 return SUCCEEDED(hr) && bytesWritten == sizeof(IID);
410 } // namespace mscom
411 } // namespace mozilla