widget/windows/winrt/nsMetroFilePicker.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsMetroFilePicker.h"
michael@0 7 #include "nsComponentManagerUtils.h"
michael@0 8 #include "nsNetUtil.h"
michael@0 9 #include "nsAutoPtr.h"
michael@0 10 #include "MetroUtils.h"
michael@0 11
michael@0 12 #include <windows.ui.viewmanagement.h>
michael@0 13 #include <windows.storage.search.h>
michael@0 14
michael@0 15 using namespace ABI::Windows::Foundation;
michael@0 16 using namespace ABI::Windows::Foundation::Collections;
michael@0 17 using namespace ABI::Windows::Storage;
michael@0 18 using namespace ABI::Windows::Storage::Pickers;
michael@0 19 using namespace ABI::Windows::Storage::Streams;
michael@0 20 using namespace ABI::Windows::UI;
michael@0 21 using namespace ABI::Windows::UI::ViewManagement;
michael@0 22 using namespace Microsoft::WRL;
michael@0 23 using namespace Microsoft::WRL::Wrappers;
michael@0 24 using namespace mozilla::widget::winrt;
michael@0 25
michael@0 26 ///////////////////////////////////////////////////////////////////////////////
michael@0 27 // nsIFilePicker
michael@0 28
michael@0 29 nsMetroFilePicker::nsMetroFilePicker()
michael@0 30 {
michael@0 31 }
michael@0 32
michael@0 33 nsMetroFilePicker::~nsMetroFilePicker()
michael@0 34 {
michael@0 35 }
michael@0 36
michael@0 37 NS_IMPL_ISUPPORTS(nsMetroFilePicker, nsIFilePicker)
michael@0 38
michael@0 39 NS_IMETHODIMP
michael@0 40 nsMetroFilePicker::Init(nsIDOMWindow *parent, const nsAString& title, int16_t mode)
michael@0 41 {
michael@0 42 mMode = mode;
michael@0 43 HRESULT hr;
michael@0 44 switch(mMode) {
michael@0 45 case nsIFilePicker::modeOpen:
michael@0 46 case nsIFilePicker::modeOpenMultiple:
michael@0 47 hr = ActivateGenericInstance(RuntimeClass_Windows_Storage_Pickers_FileOpenPicker, mFileOpenPicker);
michael@0 48 AssertRetHRESULT(hr, NS_ERROR_UNEXPECTED);
michael@0 49 return NS_OK;
michael@0 50 case nsIFilePicker::modeSave:
michael@0 51 hr = ActivateGenericInstance(RuntimeClass_Windows_Storage_Pickers_FileSavePicker, mFileSavePicker);
michael@0 52 AssertRetHRESULT(hr, NS_ERROR_UNEXPECTED);
michael@0 53 return NS_OK;
michael@0 54 default:
michael@0 55 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 56 }
michael@0 57 }
michael@0 58
michael@0 59 NS_IMETHODIMP
michael@0 60 nsMetroFilePicker::Show(int16_t *aReturnVal)
michael@0 61 {
michael@0 62 // Metro file picker only offers an async variant which calls back to the
michael@0 63 // UI thread, which is the main thread. We therefore can't call it
michael@0 64 // synchronously from the main thread.
michael@0 65 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 66 }
michael@0 67
michael@0 68 HRESULT nsMetroFilePicker::OnPickSingleFile(IAsyncOperation<StorageFile*>* aFile,
michael@0 69 AsyncStatus aStatus)
michael@0 70 {
michael@0 71 if (aStatus != ABI::Windows::Foundation::AsyncStatus::Completed) {
michael@0 72 if (mCallback)
michael@0 73 mCallback->Done(nsIFilePicker::returnCancel);
michael@0 74 return S_OK;
michael@0 75 }
michael@0 76
michael@0 77 HRESULT hr;
michael@0 78 ComPtr<IStorageFile> file;
michael@0 79 hr = aFile->GetResults(file.GetAddressOf());
michael@0 80 // When the user cancels hr == S_OK and file is nullptr
michael@0 81 if (FAILED(hr) || !file) {
michael@0 82 if (mCallback)
michael@0 83 mCallback->Done(nsIFilePicker::returnCancel);
michael@0 84 return S_OK;
michael@0 85 }
michael@0 86 ComPtr<IStorageItem> storageItem;
michael@0 87 hr = file.As(&storageItem);
michael@0 88 if (FAILED(hr)) {
michael@0 89 if (mCallback)
michael@0 90 mCallback->Done(nsIFilePicker::returnCancel);
michael@0 91 return S_OK;
michael@0 92 }
michael@0 93
michael@0 94 HSTRING path;
michael@0 95 if (FAILED(storageItem->get_Path(&path))) {
michael@0 96 if (mCallback)
michael@0 97 mCallback->Done(nsIFilePicker::returnCancel);
michael@0 98 return S_OK;
michael@0 99 }
michael@0 100 WindowsDuplicateString(path, mFilePath.GetAddressOf());
michael@0 101 WindowsDeleteString(path);
michael@0 102
michael@0 103 if (mCallback) {
michael@0 104 mCallback->Done(nsIFilePicker::returnOK);
michael@0 105 }
michael@0 106 return S_OK;
michael@0 107 }
michael@0 108
michael@0 109 HRESULT nsMetroFilePicker::OnPickMultipleFiles(IAsyncOperation<IVectorView<StorageFile*>*>* aFileList,
michael@0 110 AsyncStatus aStatus)
michael@0 111 {
michael@0 112 if (aStatus != ABI::Windows::Foundation::AsyncStatus::Completed) {
michael@0 113 if (mCallback)
michael@0 114 mCallback->Done(nsIFilePicker::returnCancel);
michael@0 115 return S_OK;
michael@0 116 }
michael@0 117
michael@0 118 HRESULT hr;
michael@0 119 ComPtr<IVectorView<StorageFile*>> view;
michael@0 120 hr = aFileList->GetResults(view.GetAddressOf());
michael@0 121 if (FAILED(hr)) {
michael@0 122 if (mCallback)
michael@0 123 mCallback->Done(nsIFilePicker::returnCancel);
michael@0 124 return S_OK;
michael@0 125 }
michael@0 126
michael@0 127 unsigned int length;
michael@0 128 view->get_Size(&length);
michael@0 129 for (unsigned int idx = 0; idx < length; idx++) {
michael@0 130 ComPtr<IStorageFile> file;
michael@0 131 hr = view->GetAt(idx, file.GetAddressOf());
michael@0 132 if (FAILED(hr)) {
michael@0 133 continue;
michael@0 134 }
michael@0 135
michael@0 136 ComPtr<IStorageItem> storageItem;
michael@0 137 hr = file.As(&storageItem);
michael@0 138 if (FAILED(hr)) {
michael@0 139 continue;
michael@0 140 }
michael@0 141
michael@0 142 HSTRING path;
michael@0 143 if (SUCCEEDED(storageItem->get_Path(&path))) {
michael@0 144 nsCOMPtr<nsILocalFile> file =
michael@0 145 do_CreateInstance("@mozilla.org/file/local;1");
michael@0 146 unsigned int tmp;
michael@0 147 if (NS_SUCCEEDED(file->InitWithPath(
michael@0 148 nsAutoString(WindowsGetStringRawBuffer(path, &tmp))))) {
michael@0 149 mFiles.AppendObject(file);
michael@0 150 }
michael@0 151 }
michael@0 152 WindowsDeleteString(path);
michael@0 153 }
michael@0 154
michael@0 155 if (mCallback) {
michael@0 156 mCallback->Done(nsIFilePicker::returnOK);
michael@0 157 }
michael@0 158 return S_OK;
michael@0 159 }
michael@0 160
michael@0 161 NS_IMETHODIMP
michael@0 162 nsMetroFilePicker::Open(nsIFilePickerShownCallback *aCallback)
michael@0 163 {
michael@0 164 HRESULT hr;
michael@0 165 // Capture a reference to the callback which we'll also pass into the
michael@0 166 // closure to ensure it's not freed.
michael@0 167 mCallback = aCallback;
michael@0 168
michael@0 169 // The filepicker cannot open when in snapped view, try to unsnapp
michael@0 170 // before showing the filepicker.
michael@0 171 ApplicationViewState viewState;
michael@0 172 MetroUtils::GetViewState(viewState);
michael@0 173 if (viewState == ApplicationViewState::ApplicationViewState_Snapped) {
michael@0 174 bool unsnapped = SUCCEEDED(MetroUtils::TryUnsnap());
michael@0 175 NS_ENSURE_TRUE(unsnapped, NS_ERROR_FAILURE);
michael@0 176 }
michael@0 177
michael@0 178 switch(mMode) {
michael@0 179 case nsIFilePicker::modeOpen: {
michael@0 180 NS_ENSURE_ARG_POINTER(mFileOpenPicker);
michael@0 181
michael@0 182 // Initiate the file picker operation
michael@0 183 ComPtr<IAsyncOperation<StorageFile*>> asyncOperation;
michael@0 184 hr = mFileOpenPicker->PickSingleFileAsync(asyncOperation.GetAddressOf());
michael@0 185 AssertRetHRESULT(hr, NS_ERROR_FAILURE);
michael@0 186
michael@0 187 // Subscribe to the completed event
michael@0 188 ComPtr<IAsyncOperationCompletedHandler<StorageFile*>>
michael@0 189 completedHandler(Callback<IAsyncOperationCompletedHandler<StorageFile*>>(
michael@0 190 this, &nsMetroFilePicker::OnPickSingleFile));
michael@0 191 hr = asyncOperation->put_Completed(completedHandler.Get());
michael@0 192 AssertRetHRESULT(hr, NS_ERROR_UNEXPECTED);
michael@0 193 break;
michael@0 194 }
michael@0 195
michael@0 196 case nsIFilePicker::modeOpenMultiple: {
michael@0 197 NS_ENSURE_ARG_POINTER(mFileOpenPicker);
michael@0 198
michael@0 199 typedef IVectorView<StorageFile*> StorageTemplate;
michael@0 200 typedef IAsyncOperation<StorageTemplate*> AsyncCallbackTemplate;
michael@0 201 typedef IAsyncOperationCompletedHandler<StorageTemplate*> HandlerTemplate;
michael@0 202
michael@0 203 // Initiate the file picker operation
michael@0 204 ComPtr<AsyncCallbackTemplate> asyncOperation;
michael@0 205 hr = mFileOpenPicker->PickMultipleFilesAsync(asyncOperation.GetAddressOf());
michael@0 206 AssertRetHRESULT(hr, NS_ERROR_FAILURE);
michael@0 207
michael@0 208 // Subscribe to the completed event
michael@0 209 ComPtr<HandlerTemplate> completedHandler(Callback<HandlerTemplate>(
michael@0 210 this, &nsMetroFilePicker::OnPickMultipleFiles));
michael@0 211 hr = asyncOperation->put_Completed(completedHandler.Get());
michael@0 212 AssertRetHRESULT(hr, NS_ERROR_UNEXPECTED);
michael@0 213 break;
michael@0 214 }
michael@0 215
michael@0 216 case nsIFilePicker::modeSave: {
michael@0 217 NS_ENSURE_ARG_POINTER(mFileSavePicker);
michael@0 218
michael@0 219 // Set the default file name
michael@0 220 mFileSavePicker->put_SuggestedFileName(HStringReference(mDefaultFilename.BeginReading()).Get());
michael@0 221
michael@0 222 // Set the default file extension
michael@0 223 if (mDefaultExtension.Length() > 0) {
michael@0 224 nsAutoString defaultFileExtension(mDefaultExtension);
michael@0 225
michael@0 226 // Touch up the extansion format platform hands us.
michael@0 227 if (defaultFileExtension[0] == L'*') {
michael@0 228 defaultFileExtension.Cut(0, 1);
michael@0 229 } else if (defaultFileExtension[0] != L'.') {
michael@0 230 defaultFileExtension.Insert(L".", 0);
michael@0 231 }
michael@0 232
michael@0 233 // Sometimes the default file extension is not passed in correctly,
michael@0 234 // so we purposfully ignore failures here.
michael@0 235 HString ext;
michael@0 236 ext.Set(defaultFileExtension.BeginReading());
michael@0 237 hr = mFileSavePicker->put_DefaultFileExtension(ext.Get());
michael@0 238 NS_ASSERTION(SUCCEEDED(hr), "put_DefaultFileExtension failed, bad format for extension?");
michael@0 239
michael@0 240 // Due to a bug in the WinRT file picker, the first file extension in the
michael@0 241 // list is always used when saving a file. So we explicitly make sure the
michael@0 242 // default extension is the first one in the list here.
michael@0 243 if (mFirstTitle.Get()) {
michael@0 244 ComPtr<IMap<HSTRING, IVector<HSTRING>*>> map;
michael@0 245 mFileSavePicker->get_FileTypeChoices(map.GetAddressOf());
michael@0 246 if (map) {
michael@0 247 boolean found = false;
michael@0 248 unsigned int index;
michael@0 249 map->HasKey(mFirstTitle.Get(), &found);
michael@0 250 if (found) {
michael@0 251 ComPtr<IVector<HSTRING>> list;
michael@0 252 if (SUCCEEDED(map->Lookup(mFirstTitle.Get(), list.GetAddressOf()))) {
michael@0 253 HString ext;
michael@0 254 ext.Set(defaultFileExtension.get());
michael@0 255 found = false;
michael@0 256 list->IndexOf(HStringReference(defaultFileExtension.get()).Get(), &index, &found);
michael@0 257 if (found) {
michael@0 258 list->RemoveAt(index);
michael@0 259 list->InsertAt(0, HStringReference(defaultFileExtension.get()).Get());
michael@0 260 }
michael@0 261 }
michael@0 262 }
michael@0 263 }
michael@0 264 }
michael@0 265 }
michael@0 266
michael@0 267 // Dispatch the async show operation
michael@0 268 ComPtr<IAsyncOperation<StorageFile*>> asyncOperation;
michael@0 269 hr = mFileSavePicker->PickSaveFileAsync(asyncOperation.GetAddressOf());
michael@0 270 AssertRetHRESULT(hr, NS_ERROR_FAILURE);
michael@0 271
michael@0 272 // Subscribe to the completed event
michael@0 273 ComPtr<IAsyncOperationCompletedHandler<StorageFile*>>
michael@0 274 completedHandler(Callback<IAsyncOperationCompletedHandler<StorageFile*>>(
michael@0 275 this, &nsMetroFilePicker::OnPickSingleFile));
michael@0 276 hr = asyncOperation->put_Completed(completedHandler.Get());
michael@0 277 AssertRetHRESULT(hr, NS_ERROR_UNEXPECTED);
michael@0 278 break;
michael@0 279 }
michael@0 280
michael@0 281 case modeGetFolder:
michael@0 282 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 283
michael@0 284 default:
michael@0 285 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 286 }
michael@0 287 return NS_OK;
michael@0 288 }
michael@0 289
michael@0 290 NS_IMETHODIMP
michael@0 291 nsMetroFilePicker::GetFile(nsIFile **aFile)
michael@0 292 {
michael@0 293 NS_ENSURE_ARG_POINTER(aFile);
michael@0 294 *aFile = nullptr;
michael@0 295
michael@0 296 if (WindowsIsStringEmpty(mFilePath.Get()))
michael@0 297 return NS_OK;
michael@0 298
michael@0 299 nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
michael@0 300 NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
michael@0 301 unsigned int length;
michael@0 302 file->InitWithPath(nsAutoString(mFilePath.GetRawBuffer(&length)));
michael@0 303 NS_ADDREF(*aFile = file);
michael@0 304 return NS_OK;
michael@0 305 }
michael@0 306
michael@0 307 NS_IMETHODIMP
michael@0 308 nsMetroFilePicker::GetFileURL(nsIURI **aFileURL)
michael@0 309 {
michael@0 310 *aFileURL = nullptr;
michael@0 311 nsCOMPtr<nsIFile> file;
michael@0 312 nsresult rv = GetFile(getter_AddRefs(file));
michael@0 313 if (!file)
michael@0 314 return rv;
michael@0 315
michael@0 316 return NS_NewFileURI(aFileURL, file);
michael@0 317 }
michael@0 318
michael@0 319 NS_IMETHODIMP
michael@0 320 nsMetroFilePicker::GetFiles(nsISimpleEnumerator **aFiles)
michael@0 321 {
michael@0 322 NS_ENSURE_ARG_POINTER(aFiles);
michael@0 323 return NS_NewArrayEnumerator(aFiles, mFiles);
michael@0 324 }
michael@0 325
michael@0 326 // Set the filter index
michael@0 327 NS_IMETHODIMP
michael@0 328 nsMetroFilePicker::GetFilterIndex(int32_t *aFilterIndex)
michael@0 329 {
michael@0 330 // No associated concept with a Metro file picker
michael@0 331 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 332 }
michael@0 333
michael@0 334 NS_IMETHODIMP
michael@0 335 nsMetroFilePicker::SetFilterIndex(int32_t aFilterIndex)
michael@0 336 {
michael@0 337 // No associated concept with a Metro file picker
michael@0 338 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 339 }
michael@0 340
michael@0 341 // AFACT, it's up to use to supply the implementation of a vector list.
michael@0 342 class MozHStringVector : public RuntimeClass<IVector<HSTRING>> {
michael@0 343 InspectableClass(L"MozHStringVector", TrustLevel::BaseTrust)
michael@0 344 ~MozHStringVector() {
michael@0 345 Clear();
michael@0 346 }
michael@0 347
michael@0 348 // See IVector_impl in windows.foundation.collections.h
michael@0 349 public:
michael@0 350 STDMETHOD(GetAt)(unsigned aIndex, HSTRING* aString) {
michael@0 351 if (aIndex >= mList.Length()) {
michael@0 352 return E_INVALIDARG;
michael@0 353 }
michael@0 354 return WindowsDuplicateString(mList[aIndex], aString);
michael@0 355 }
michael@0 356
michael@0 357 STDMETHOD(get_Size)(unsigned int* aLength) {
michael@0 358 if (!aLength) {
michael@0 359 return E_INVALIDARG;
michael@0 360 }
michael@0 361 *aLength = mList.Length();
michael@0 362 return S_OK;
michael@0 363 }
michael@0 364
michael@0 365 STDMETHOD(Append)(HSTRING aString) {
michael@0 366 HSTRING str;
michael@0 367 if (FAILED(WindowsDuplicateString(aString, &str))) {
michael@0 368 return E_INVALIDARG;
michael@0 369 }
michael@0 370 mList.AppendElement(str);
michael@0 371 return S_OK;
michael@0 372 }
michael@0 373
michael@0 374 STDMETHOD(Clear)() {
michael@0 375 int length = mList.Length();
michael@0 376 for (int idx = 0; idx < length; idx++)
michael@0 377 WindowsDeleteString(mList[idx]);
michael@0 378 mList.Clear();
michael@0 379 return S_OK;
michael@0 380 }
michael@0 381
michael@0 382 // interfaces picker code doesn't seem to need
michael@0 383 STDMETHOD(GetView)(IVectorView<HSTRING> **aView) { return E_NOTIMPL; }
michael@0 384 STDMETHOD(IndexOf)(HSTRING aValue, unsigned *aIndex, boolean *found) { return E_NOTIMPL; }
michael@0 385 STDMETHOD(SetAt)(unsigned aIndex, HSTRING aString) { return E_NOTIMPL; }
michael@0 386 STDMETHOD(InsertAt)(unsigned aIndex, HSTRING aString) { return E_NOTIMPL; }
michael@0 387 STDMETHOD(RemoveAt)(unsigned aIndex) { return E_NOTIMPL; }
michael@0 388 STDMETHOD(RemoveAtEnd)() { return E_NOTIMPL; }
michael@0 389
michael@0 390 private:
michael@0 391 nsTArray<HSTRING> mList;
michael@0 392 };
michael@0 393
michael@0 394 nsresult
michael@0 395 nsMetroFilePicker::ParseFiltersIntoVector(ComPtr<IVector<HSTRING>>& aVector,
michael@0 396 const nsAString& aFilter,
michael@0 397 bool aAllowAll)
michael@0 398 {
michael@0 399 const char16_t *beg = aFilter.BeginReading();
michael@0 400 const char16_t *end = aFilter.EndReading();
michael@0 401 for (const char16_t *cur = beg, *fileTypeStart = beg; cur <= end; ++cur) {
michael@0 402 // Start of a a filetype, example: *.png
michael@0 403 if (cur == end || char16_t(' ') == *cur) {
michael@0 404 int32_t startPos = fileTypeStart - beg;
michael@0 405 int32_t endPos = cur - fileTypeStart - (cur == end ? 0 : 1);
michael@0 406 const nsAString& fileType = Substring(aFilter,
michael@0 407 startPos,
michael@0 408 endPos);
michael@0 409 // There is no way to say show all files in Metro save file picker, so
michael@0 410 // just use .data if * or *.* is specified.
michael@0 411 if (fileType.IsEmpty() ||
michael@0 412 fileType.Equals(L"*") ||
michael@0 413 fileType.Equals(L"*.*")) {
michael@0 414 HString str;
michael@0 415 if (aAllowAll) {
michael@0 416 str.Set(L"*");
michael@0 417 aVector->Append(str.Get());
michael@0 418 } else {
michael@0 419 str.Set(L".data");
michael@0 420 aVector->Append(str.Get());
michael@0 421 }
michael@0 422 } else {
michael@0 423 nsAutoString filter(fileType);
michael@0 424 if (filter[0] == L'*') {
michael@0 425 filter.Cut(0, 1);
michael@0 426 } else if (filter[0] != L'.') {
michael@0 427 filter.Insert(L".", 0);
michael@0 428 }
michael@0 429 HString str;
michael@0 430 str.Set(filter.BeginReading());
michael@0 431 aVector->Append(str.Get());
michael@0 432 }
michael@0 433
michael@0 434 fileTypeStart = cur + 1;
michael@0 435 }
michael@0 436 }
michael@0 437 return NS_OK;
michael@0 438 }
michael@0 439
michael@0 440 NS_IMETHODIMP
michael@0 441 nsMetroFilePicker::AppendFilter(const nsAString& aTitle,
michael@0 442 const nsAString& aFilter)
michael@0 443 {
michael@0 444 HRESULT hr;
michael@0 445 switch(mMode) {
michael@0 446 case nsIFilePicker::modeOpen:
michael@0 447 case nsIFilePicker::modeOpenMultiple: {
michael@0 448 NS_ENSURE_ARG_POINTER(mFileOpenPicker);
michael@0 449 ComPtr<IVector<HSTRING>> list;
michael@0 450 mFileOpenPicker->get_FileTypeFilter(list.GetAddressOf());
michael@0 451 nsresult rv = ParseFiltersIntoVector(list, aFilter, true);
michael@0 452 NS_ENSURE_SUCCESS(rv, rv);
michael@0 453 }
michael@0 454
michael@0 455 case nsIFilePicker::modeSave: {
michael@0 456 NS_ENSURE_ARG_POINTER(mFileSavePicker);
michael@0 457
michael@0 458 ComPtr<IMap<HSTRING,IVector<HSTRING>*>> map;
michael@0 459 hr = mFileSavePicker->get_FileTypeChoices(map.GetAddressOf());
michael@0 460 AssertRetHRESULT(hr, NS_ERROR_FAILURE);
michael@0 461
michael@0 462 HString key;
michael@0 463 key.Set(aTitle.BeginReading());
michael@0 464
michael@0 465 ComPtr<IVector<HSTRING>> saveTypes;
michael@0 466 saveTypes = Make<MozHStringVector>();
michael@0 467 nsresult rv = ParseFiltersIntoVector(saveTypes, aFilter, false);
michael@0 468 NS_ENSURE_SUCCESS(rv, rv);
michael@0 469
michael@0 470 if (WindowsIsStringEmpty(mFirstTitle.Get())) {
michael@0 471 mFirstTitle.Set(key.Get());
michael@0 472 }
michael@0 473
michael@0 474 boolean replaced;
michael@0 475 map->Insert(key.Get(), saveTypes.Get(), &replaced);
michael@0 476 }
michael@0 477 break;
michael@0 478
michael@0 479 default:
michael@0 480 return NS_ERROR_FAILURE;
michael@0 481 }
michael@0 482 return NS_OK;
michael@0 483 }
michael@0 484

mercurial