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/. */
6 
7 #include <stdint.h>
8 #include <string.h>
9 
10 #include "nsArrayEnumerator.h"
11 #include "nsIObjectInputStream.h"
12 #include "nsIObjectOutputStream.h"
13 #include "nsSupportsArray.h"
14 #include "nsSupportsArrayEnumerator.h"
15 
16 // Disable deprecation warnings generated by nsISupportsArray and associated
17 // classes.
18 #if defined(__GNUC__)
19 #pragma GCC diagnostic push
20 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
21 #elif defined(_MSC_VER)
22 #pragma warning (push)
23 #pragma warning (disable : 4996)
24 #endif
25 
26 nsresult
operator ()(const nsIID & aIID,void ** aResult) const27 nsQueryElementAt::operator()(const nsIID& aIID, void** aResult) const
28 {
29   nsresult status =
30     mCollection ? mCollection->QueryElementAt(mIndex, aIID, aResult) :
31                   NS_ERROR_NULL_POINTER;
32 
33   if (mErrorPtr) {
34     *mErrorPtr = status;
35   }
36 
37   return status;
38 }
39 
nsSupportsArray()40 nsSupportsArray::nsSupportsArray()
41 {
42 }
43 
~nsSupportsArray()44 nsSupportsArray::~nsSupportsArray()
45 {
46   Clear();
47 }
48 
49 nsresult
Create(nsISupports * aOuter,REFNSIID aIID,void ** aResult)50 nsSupportsArray::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
51 {
52   if (aOuter) {
53     return NS_ERROR_NO_AGGREGATION;
54   }
55 
56   nsCOMPtr<nsISupportsArray> it = new nsSupportsArray();
57 
58   return it->QueryInterface(aIID, aResult);
59 }
60 
NS_IMPL_ISUPPORTS(nsSupportsArray,nsIArray,nsISupportsArray,nsICollection,nsISerializable)61 NS_IMPL_ISUPPORTS(nsSupportsArray, nsIArray, nsISupportsArray, nsICollection,
62                   nsISerializable)
63 
64 NS_IMETHODIMP
65 nsSupportsArray::Read(nsIObjectInputStream* aStream)
66 {
67   nsresult rv;
68 
69   uint32_t newArraySize;
70   rv = aStream->Read32(&newArraySize);
71   if (NS_FAILED(rv)) {
72     return rv;
73   }
74 
75   uint32_t count;
76   rv = aStream->Read32(&count);
77   if (NS_FAILED(rv)) {
78     return rv;
79   }
80 
81   NS_ASSERTION(count <= newArraySize, "overlarge mCount!");
82   if (count > newArraySize) {
83     count = newArraySize;
84   }
85 
86   // Don't clear out our array until we know we have enough space for the new
87   // one and have successfully copied everything out of the stream.
88   nsCOMArray<nsISupports> tmp;
89   tmp.SetCapacity(newArraySize);
90   tmp.SetCount(count);
91 
92   auto elems = tmp.Elements();
93   for (uint32_t i = 0; i < count; i++) {
94     rv = aStream->ReadObject(true, &elems[i]);
95     if (NS_FAILED(rv)) {
96       return rv;
97     }
98   }
99 
100   // Now clear out existing refs and replace with the new array.
101   mArray.Clear();
102   mArray.SwapElements(tmp);
103 
104   return NS_OK;
105 }
106 
107 NS_IMETHODIMP
Write(nsIObjectOutputStream * aStream)108 nsSupportsArray::Write(nsIObjectOutputStream* aStream)
109 {
110   nsresult rv;
111 
112   rv = aStream->Write32(mArray.Capacity());
113   if (NS_FAILED(rv)) {
114     return rv;
115   }
116 
117   rv = aStream->Write32(mArray.Length());
118   if (NS_FAILED(rv)) {
119     return rv;
120   }
121 
122   for (size_t i = 0; i < mArray.Length(); i++) {
123     rv = aStream->WriteObject(mArray[i], true);
124     if (NS_FAILED(rv)) {
125       return rv;
126     }
127   }
128 
129   return NS_OK;
130 }
131 
132 NS_IMETHODIMP
GetElementAt(uint32_t aIndex,nsISupports ** aOutPtr)133 nsSupportsArray::GetElementAt(uint32_t aIndex, nsISupports** aOutPtr)
134 {
135   nsCOMPtr<nsISupports> elm = mArray.SafeElementAt(aIndex);
136   elm.forget(aOutPtr);
137   return NS_OK;
138 }
139 
NS_IMETHODIMP_(int32_t)140 NS_IMETHODIMP_(int32_t)
141 nsSupportsArray::IndexOf(const nsISupports* aPossibleElement)
142 {
143   // nsCOMArray takes a non-const param, but it just passes through to
144   // nsTArray which takes a const param.
145   return mArray.IndexOf(const_cast<nsISupports*>(aPossibleElement));
146 }
147 
NS_IMETHODIMP_(bool)148 NS_IMETHODIMP_(bool)
149 nsSupportsArray::InsertElementAt(nsISupports* aElement, uint32_t aIndex)
150 {
151   return mArray.InsertObjectAt(aElement, aIndex);
152 }
153 
NS_IMETHODIMP_(bool)154 NS_IMETHODIMP_(bool)
155 nsSupportsArray::ReplaceElementAt(nsISupports* aElement, uint32_t aIndex)
156 {
157   // nsCOMArray::ReplaceObjectAt will grow the array if necessary. Instead
158   // we do the bounds check and only replace if it's in range.
159   if (aIndex < mArray.Length()) {
160     mArray.ReplaceElementAt(aIndex, aElement);
161     return true;
162   }
163   return false;
164 }
165 
NS_IMETHODIMP_(bool)166 NS_IMETHODIMP_(bool)
167 nsSupportsArray::RemoveElementAt(uint32_t aIndex)
168 {
169   return mArray.RemoveObjectAt(aIndex);
170 }
171 
172 NS_IMETHODIMP
RemoveElement(nsISupports * aElement)173 nsSupportsArray::RemoveElement(nsISupports* aElement)
174 {
175   return mArray.RemoveObject(aElement) ? NS_OK : NS_ERROR_FAILURE;
176 }
177 
178 NS_IMETHODIMP
Clear(void)179 nsSupportsArray::Clear(void)
180 {
181   mArray.Clear();
182   return NS_OK;
183 }
184 
185 NS_IMETHODIMP
DeprecatedEnumerate(nsIEnumerator ** aResult)186 nsSupportsArray::DeprecatedEnumerate(nsIEnumerator** aResult)
187 {
188   RefPtr<nsSupportsArrayEnumerator> e = new nsSupportsArrayEnumerator(this);
189   e.forget(aResult);
190   return NS_OK;
191 }
192 
193 NS_IMETHODIMP
Clone(nsISupportsArray ** aResult)194 nsSupportsArray::Clone(nsISupportsArray** aResult)
195 {
196   nsCOMPtr<nsISupportsArray> newArray;
197   nsresult rv = NS_NewISupportsArray(getter_AddRefs(newArray));
198   if (NS_WARN_IF(NS_FAILED(rv))) {
199     return rv;
200   }
201 
202   for (size_t i = 0; i < mArray.Length(); i++) {
203     // AppendElement does an odd cast of bool to nsresult, we just cast back
204     // here.
205     if (!(bool)newArray->AppendElement(mArray[i])) {
206       return NS_ERROR_OUT_OF_MEMORY;
207     }
208   }
209 
210   newArray.forget(aResult);
211   return NS_OK;
212 }
213 
214 nsresult
NS_NewISupportsArray(nsISupportsArray ** aInstancePtrResult)215 NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult)
216 {
217   nsresult rv;
218   rv = nsSupportsArray::Create(nullptr, NS_GET_IID(nsISupportsArray),
219                                (void**)aInstancePtrResult);
220   return rv;
221 }
222 
223 /**
224  * nsIArray adapters.
225  */
226 NS_IMETHODIMP
GetLength(uint32_t * aLength)227 nsSupportsArray::GetLength(uint32_t* aLength) {
228   return Count(aLength);
229 }
230 
231 NS_IMETHODIMP
QueryElementAt(uint32_t aIndex,const nsIID & aIID,void ** aResult)232 nsSupportsArray::QueryElementAt(uint32_t aIndex, const nsIID& aIID, void** aResult)
233 {
234   nsISupports* element = mArray.SafeElementAt(aIndex);
235   if (element) {
236     return element->QueryInterface(aIID, aResult);
237   }
238   return NS_ERROR_FAILURE;
239 }
240 
241 NS_IMETHODIMP
IndexOf(uint32_t aStartIndex,nsISupports * aElement,uint32_t * aResult)242 nsSupportsArray::IndexOf(uint32_t aStartIndex, nsISupports* aElement, uint32_t* aResult)
243 {
244   int32_t idx = mArray.IndexOf(aElement, aStartIndex);
245   if (idx < 0) {
246     return NS_ERROR_FAILURE;
247   }
248 
249   *aResult = static_cast<uint32_t>(idx);
250   return NS_OK;
251 }
252 
253 NS_IMETHODIMP
Enumerate(nsISimpleEnumerator ** aResult)254 nsSupportsArray::Enumerate(nsISimpleEnumerator** aResult)
255 {
256   return NS_NewArrayEnumerator(aResult, this);
257 }
258 
259 #if defined(__GNUC__)
260 #pragma GCC diagnostic pop
261 #elif defined(_MSC_VER)
262 #pragma warning (pop)
263 #endif
264 
265