// Is path1 a prefix, and thus a parent, of path2? Eg. "a/b" is a parent of // "a/b/c", but "a/bb" is not. static bool isParent(const nsACString &path1, const nsACString &path2) { if (path1.Length() >= path2.Length()) return false; const nsACString& subStr = Substring(path2, 0, path1.Length()); return subStr.Equals(path1) && path2[path1.Length()] == '/'; }
bool StringBeginsWith( const nsACString& aSource, const nsACString& aSubstring, const nsCStringComparator& aComparator ) { nsACString::size_type src_len = aSource.Length(), sub_len = aSubstring.Length(); if (sub_len > src_len) return false; return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator); }
bool StringEndsWith(const nsACString& aSource, const nsACString& aSubstring) { nsACString::size_type src_len = aSource.Length(), sub_len = aSubstring.Length(); if (sub_len > src_len) { return false; } return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring); }
nsresult nsIDNService::decodeACE(const nsACString& in, nsACString& out, stringPrepFlag flag) { bool isAce; IsACE(in, &isAce); if (!isAce) { out.Assign(in); return NS_OK; } nsAutoString utf16; #ifdef IDNA2008 nsresult result = IDNA2008ToUnicode(in, utf16); NS_ENSURE_SUCCESS(result, result); #else // RFC 3490 - 4.2 ToUnicode // The ToUnicode output never contains more code points than its input. punycode_uint output_length = in.Length() - kACEPrefixLen + 1; punycode_uint *output = new punycode_uint[output_length]; NS_ENSURE_TRUE(output, NS_ERROR_OUT_OF_MEMORY); enum punycode_status status = punycode_decode(in.Length() - kACEPrefixLen, PromiseFlatCString(in).get() + kACEPrefixLen, &output_length, output, nullptr); if (status != punycode_success) { delete [] output; return NS_ERROR_FAILURE; } // UCS4 -> UTF8 output[output_length] = 0; ucs4toUtf16(output, utf16); delete [] output; #endif if (flag != eStringPrepForUI || isLabelSafe(utf16)) { CopyUTF16toUTF8(utf16, out); } else { out.Assign(in); return NS_OK; } // Validation: encode back to ACE and compare the strings nsAutoCString ace; nsresult rv = UTF8toACE(out, ace, flag); NS_ENSURE_SUCCESS(rv, rv); if (flag == eStringPrepForDNS && !ace.Equals(in, nsCaseInsensitiveCStringComparator())) { return NS_ERROR_FAILURE; } return NS_OK; }
bool BluetoothSocket::SendSocketData(const nsACString& aStr) { if (aStr.Length() > MAX_READ_SIZE) { return false; } SendSocketData(new UnixSocketRawData(aStr.BeginReading(), aStr.Length())); return true; }
NS_IMETHODIMP nsMimeBaseEmitter::Write(const nsACString &buf, PRUint32 *amountWritten) { unsigned int written = 0; nsresult rv = NS_OK; PRUint32 needToWrite; #ifdef DEBUG_BenB // If you want to see libmime output... printf("%s", buf); #endif PR_LOG(gMimeEmitterLogModule, PR_LOG_ALWAYS, (PromiseFlatCString(buf).get())); // // Make sure that the buffer we are "pushing" into has enough room // for the write operation. If not, we have to buffer, return, and get // it on the next time through // *amountWritten = 0; needToWrite = mBufferMgr->GetSize(); // First, handle any old buffer data... if (needToWrite > 0) { rv = WriteHelper(mBufferMgr->GetBuffer(), needToWrite, &written); mTotalWritten += written; mBufferMgr->ReduceBuffer(written); *amountWritten = written; // if we couldn't write all the old data, buffer the new data // and return if (mBufferMgr->GetSize() > 0) { mBufferMgr->IncreaseBuffer(buf.BeginReading(), buf.Length()); return rv; } } // if we get here, we are dealing with new data...try to write // and then do the right thing... rv = WriteHelper(buf.BeginReading(), buf.Length(), &written); *amountWritten = written; mTotalWritten += written; if (written < buf.Length()) { const nsACString &remainder = Substring(buf, written); mBufferMgr->IncreaseBuffer(remainder.BeginReading(), remainder.Length()); } return rv; }
nsCString PendingLookup::EscapeFingerprint(const nsACString& aFingerprint) { // Google's fingerprint doesn't have colons nsCString escaped; escaped.SetCapacity(aFingerprint.Length()); for (unsigned int i = 0; i < aFingerprint.Length(); ++i) { if (aFingerprint.Data()[i] != ':') { escaped.Append(aFingerprint.Data()[i]); } } return escaped; }
NS_CStringGetMutableData(nsACString& aStr, uint32_t aDataLength, char** aData) { if (aDataLength != UINT32_MAX) { aStr.SetLength(aDataLength); if (aStr.Length() != aDataLength) { *aData = nullptr; return 0; } } *aData = aStr.BeginWriting(); return aStr.Length(); }
nsresult nsIDNService::decodeACE(const nsACString& in, nsACString& out, bool allowUnassigned, bool convertAllLabels) { bool isAce; IsACE(in, &isAce); if (!isAce) { out.Assign(in); return NS_OK; } // RFC 3490 - 4.2 ToUnicode // The ToUnicode output never contains more code points than its input. punycode_uint output_length = in.Length() - kACEPrefixLen + 1; punycode_uint *output = new punycode_uint[output_length]; NS_ENSURE_TRUE(output, NS_ERROR_OUT_OF_MEMORY); enum punycode_status status = punycode_decode(in.Length() - kACEPrefixLen, PromiseFlatCString(in).get() + kACEPrefixLen, &output_length, output, nullptr); if (status != punycode_success) { delete [] output; return NS_ERROR_FAILURE; } // UCS4 -> UTF8 output[output_length] = 0; nsAutoString utf16; ucs4toUtf16(output, utf16); delete [] output; if (!convertAllLabels && !isLabelSafe(utf16)) { out.Assign(in); return NS_OK; } if (!isOnlySafeChars(utf16, mIDNBlacklist)) return NS_ERROR_FAILURE; CopyUTF16toUTF8(utf16, out); // Validation: encode back to ACE and compare the strings nsAutoCString ace; nsresult rv = UTF8toACE(out, ace, allowUnassigned, true); NS_ENSURE_SUCCESS(rv, rv); if (!ace.Equals(in, nsCaseInsensitiveCStringComparator())) return NS_ERROR_FAILURE; return NS_OK; }
NS_CStringSetDataRange(nsACString& aStr, uint32_t aCutOffset, uint32_t aCutLength, const char* aData, uint32_t aDataLength) { if (aCutOffset == UINT32_MAX) { // append case if (aData) { aStr.Append(aData, aDataLength); } return NS_OK; // XXX report errors } if (aCutLength == UINT32_MAX) { aCutLength = aStr.Length() - aCutOffset; } if (aData) { if (aDataLength == UINT32_MAX) { aStr.Replace(aCutOffset, aCutLength, nsDependentCString(aData)); } else { aStr.Replace(aCutOffset, aCutLength, Substring(aData, aDataLength)); } } else { aStr.Cut(aCutOffset, aCutLength); } return NS_OK; // XXX report errors }
static nsresult HashCString(nsICryptoHash* aHashService, const nsACString& aIn, /* out */ CryptoBuffer& aOut) { MOZ_ASSERT(aHashService); nsresult rv = aHashService->Init(nsICryptoHash::SHA256); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } rv = aHashService->Update( reinterpret_cast<const uint8_t*>(aIn.BeginReading()),aIn.Length()); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } nsAutoCString fullHash; // Passing false below means we will get a binary result rather than a // base64-encoded string. rv = aHashService->Finish(false, fullHash); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } aOut.Assign(fullHash); return rv; }
static nsresult ToUTF8(const nsACString &aString, const char *aCharset, bool aAllowSubstitution, nsACString &aResult) { nsresult rv; if (!aCharset || !*aCharset) return NS_ERROR_INVALID_ARG; nsDependentCString label(aCharset); nsAutoCString encoding; if (!EncodingUtils::FindEncodingForLabelNoReplacement(label, encoding)) { return NS_ERROR_UCONV_NOCONV; } nsCOMPtr<nsIUnicodeDecoder> unicodeDecoder = EncodingUtils::DecoderForEncoding(encoding); if (!aAllowSubstitution) unicodeDecoder->SetInputErrorBehavior(nsIUnicodeDecoder::kOnError_Signal); int32_t srcLen = aString.Length(); int32_t dstLen; const nsAFlatCString& inStr = PromiseFlatCString(aString); rv = unicodeDecoder->GetMaxLength(inStr.get(), srcLen, &dstLen); NS_ENSURE_SUCCESS(rv, rv); auto ustr = mozilla::MakeUnique<char16_t[]>(dstLen); NS_ENSURE_TRUE(ustr, NS_ERROR_OUT_OF_MEMORY); rv = unicodeDecoder->Convert(inStr.get(), &srcLen, ustr.get(), &dstLen); if (NS_SUCCEEDED(rv)){ CopyUTF16toUTF8(Substring(ustr.get(), ustr.get() + dstLen), aResult); } return rv; }
NS_IMETHODIMP nsAnnotationService::SetAnnotationBinary(nsIURI* aURI, const nsACString& aName, const PRUint8 *aData, PRUint32 aDataLen, const nsACString& aMimeType, PRInt32 aFlags, PRInt32 aExpiration) { if (aMimeType.Length() == 0) return NS_ERROR_INVALID_ARG; mozStorageTransaction transaction(mDBConn, PR_FALSE); mozIStorageStatement* statement; // class var, not owned by this function nsresult rv = StartSetAnnotation(aURI, aName, aFlags, aExpiration, &statement); NS_ENSURE_SUCCESS(rv, rv); mozStorageStatementScoper statementResetter(statement); rv = statement->BindBlobParameter(kAnnoIndex_Content, aData, aDataLen); NS_ENSURE_SUCCESS(rv, rv); rv = statement->BindUTF8StringParameter(kAnnoIndex_MimeType, aMimeType); NS_ENSURE_SUCCESS(rv, rv); rv = statement->Execute(); NS_ENSURE_SUCCESS(rv, rv); transaction.Commit(); // should reset the statement; observers may call our service back to get // annotation values! statement->Reset(); statementResetter.Abandon(); CallSetObservers(aURI, aName); return NS_OK; }
bool AppendUTF16toUTF8( const nsAString& aSource, nsACString& aDest, const mozilla::fallible_t& ) { nsAString::const_iterator source_start, source_end; CalculateUTF8Size calculator; copy_string(aSource.BeginReading(source_start), aSource.EndReading(source_end), calculator); uint32_t count = calculator.Size(); if (count) { uint32_t old_dest_length = aDest.Length(); // Grow the buffer if we need to. if (!aDest.SetLength(old_dest_length + count, mozilla::fallible_t())) { return false; } // All ready? Time to convert ConvertUTF16toUTF8 converter(aDest.BeginWriting() + old_dest_length); copy_string(aSource.BeginReading(source_start), aSource.EndReading(source_end), converter); NS_ASSERTION(converter.Size() == count, "Unexpected disparity between CalculateUTF8Size and " "ConvertUTF16toUTF8"); } return true; }
nsresult nsIDNService::stringPrepAndACE(const nsAString& in, nsACString& out) { nsresult rv = NS_OK; out.Truncate(); if (in.Length() > kMaxDNSNodeLen) { NS_ERROR("IDN node too large"); return NS_ERROR_FAILURE; } if (IsASCII(in)) LossyCopyUTF16toASCII(in, out); else { nsAutoString strPrep; rv = stringPrep(in, strPrep); if (NS_SUCCEEDED(rv)) { if (IsASCII(strPrep)) LossyCopyUTF16toASCII(strPrep, out); else rv = encodeToACE(strPrep, out); } } if (out.Length() > kMaxDNSNodeLen) { NS_ERROR("IDN node too large"); return NS_ERROR_FAILURE; } return rv; }
NS_IMETHODIMP nsUTF8ConverterService::ConvertURISpecToUTF8(const nsACString &aSpec, const char *aCharset, nsACString &aUTF8Spec) { // assume UTF-8 if the spec contains unescaped non-ASCII characters. // No valid spec in Mozilla would break this assumption. if (!IsASCII(aSpec)) { aUTF8Spec = aSpec; return NS_OK; } aUTF8Spec.Truncate(); nsAutoCString unescapedSpec; // NS_UnescapeURL does not fill up unescapedSpec unless there's at least // one character to unescape. bool written = NS_UnescapeURL(PromiseFlatCString(aSpec).get(), aSpec.Length(), esc_OnlyNonASCII, unescapedSpec); if (!written) { aUTF8Spec = aSpec; return NS_OK; } // return if ASCII only or escaped UTF-8 if (IsASCII(unescapedSpec) || IsUTF8(unescapedSpec)) { aUTF8Spec = unescapedSpec; return NS_OK; } return ToUTF8(unescapedSpec, aCharset, true, aUTF8Spec); }
void nsCertOverride::convertStringToBits(const nsACString& str, /*out*/ OverrideBits& ob) { ob = OverrideBits::None; for (uint32_t i = 0; i < str.Length(); i++) { switch (str.CharAt(i)) { case 'm': case 'M': ob |= OverrideBits::Mismatch; break; case 'u': case 'U': ob |= OverrideBits::Untrusted; break; case 't': case 'T': ob |= OverrideBits::Time; break; default: break; } } }
bool ParseString(const nsACString& aSource, char aDelimiter, nsTArray<nsCString>& aArray) { int32_t start = 0; int32_t end = aSource.Length(); uint32_t oldLength = aArray.Length(); for (;;) { int32_t delimiter = aSource.FindChar(aDelimiter, start); if (delimiter < 0) { delimiter = end; } if (delimiter != start) { if (!aArray.AppendElement(Substring(aSource, start, delimiter - start))) { aArray.RemoveElementsAt(oldLength, aArray.Length() - oldLength); return false; } } if (delimiter == end) break; start = ++delimiter; if (start == end) break; } return true; }
NS_IMETHODIMP FontTableURIProtocolHandler::NewURI(const nsACString& aSpec, const char* aCharset, nsIURI* aBaseURI, nsIURI** aResult) { nsresult rv; nsCOMPtr<nsIURI> uri; // Either you got here via a ref or a fonttable: uri if (aSpec.Length() && aSpec.CharAt(0) == '#') { rv = NS_MutateURI(aBaseURI).SetRef(aSpec).Finalize(uri); NS_ENSURE_SUCCESS(rv, rv); } else { // Relative URIs (other than #ref) are not meaningful within the // fonttable: scheme. // If aSpec is a relative URI -other- than a bare #ref, // this will leave uri empty, and we'll return a failure code below. rv = NS_MutateURI(new mozilla::net::nsSimpleURI::Mutator()) .SetSpec(aSpec) .Finalize(uri); NS_ENSURE_SUCCESS(rv, rv); } bool schemeIs; if (NS_FAILED(uri->SchemeIs(FONTTABLEURI_SCHEME, &schemeIs)) || !schemeIs) { NS_WARNING("Non-fonttable spec in FontTableURIProtocolHandler"); return NS_ERROR_NOT_AVAILABLE; } uri.forget(aResult); return NS_OK; }
PRBool ParseString(const nsACString& aSource, char aDelimiter, nsTArray<nsCString>& aArray) { PRInt32 start = 0; PRInt32 end = aSource.Length(); PRUint32 oldLength = aArray.Length(); for (;;) { PRInt32 delimiter = aSource.FindChar(aDelimiter, start); if (delimiter < 0) { delimiter = end; } if (delimiter != start) { if (!aArray.AppendElement(Substring(aSource, start, delimiter - start))) { aArray.RemoveElementsAt(oldLength, aArray.Length() - oldLength); return PR_FALSE; } } if (delimiter == end) break; start = ++delimiter; if (start == end) break; } return PR_TRUE; }
nsresult nsIDNService::stringPrepAndACE(const nsAString& in, nsACString& out, bool allowUnassigned, bool convertAllLabels) { nsresult rv = NS_OK; out.Truncate(); if (in.Length() > kMaxDNSNodeLen) { NS_WARNING("IDN node too large"); return NS_ERROR_FAILURE; } if (IsASCII(in)) LossyCopyUTF16toASCII(in, out); else if (!convertAllLabels && isLabelSafe(in)) CopyUTF16toUTF8(in, out); else { nsAutoString strPrep; rv = stringPrep(in, strPrep, allowUnassigned); if (NS_SUCCEEDED(rv)) { if (IsASCII(strPrep)) LossyCopyUTF16toASCII(strPrep, out); else rv = encodeToACE(strPrep, out); } } if (out.Length() > kMaxDNSNodeLen) { NS_WARNING("IDN node too large"); return NS_ERROR_FAILURE; } return rv; }
nsresult nsUrlClassifierStreamUpdater::AddRequestBody(const nsACString &aRequestBody) { nsresult rv; nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = strStream->SetData(aRequestBody.BeginReading(), aRequestBody.Length()); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIUploadChannel> uploadChannel = do_QueryInterface(mChannel, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = uploadChannel->SetUploadStream(strStream, NS_LITERAL_CSTRING("text/plain"), -1); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST")); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
NS_IMETHODIMP nsNSSCertificateDB::ConstructX509FromBase64(const nsACString& base64, /*out*/ nsIX509Cert** _retval) { nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) { return NS_ERROR_NOT_AVAILABLE; } if (!_retval) { return NS_ERROR_INVALID_POINTER; } // Base64Decode() doesn't consider a zero length input as an error, and just // returns the empty string. We don't want this behavior, so the below check // catches this case. if (base64.Length() < 1) { return NS_ERROR_ILLEGAL_VALUE; } nsAutoCString certDER; nsresult rv = Base64Decode(base64, certDER); if (NS_FAILED(rv)) { return rv; } return ConstructX509(certDER.get(), certDER.Length(), _retval); }
void TranslateResourceValue(const char* aProviderType, const char* aProvider, const char* aArc, const char* aResourceValue, nsACString& aResult) { PRUint32 chopStart=0, chopEnd=0; // bytes to chop off the front/back of aResourceValue static const char localeUrn[] = "urn:mozilla:locale:"; if ((strcmp(aArc, "selectedLocale") == 0) && (strncmp(aResourceValue, localeUrn, sizeof(localeUrn)-1) == 0)) { chopStart = sizeof(localeUrn) - 1; chopEnd = strlen(aProvider) + 1; } static const char skinUrn[] = "urn:mozilla:skin:"; if ((strcmp(aArc, "selectedSkin") == 0) && (strncmp(aResourceValue, skinUrn, sizeof(skinUrn)-1) == 0)) { chopStart = sizeof(skinUrn) - 1; chopEnd = strlen(aProvider) + 1; } // strip off 'urn:mozilla:<foo>:' and ':<provider>' aResult = (aResourceValue + chopStart); aResult.Truncate(aResult.Length() - chopEnd); }
NS_IMETHODIMP nsPersistentProperties::SetStringProperty(const nsACString& aKey, const nsAString& aNewValue, nsAString& aOldValue) { const nsAFlatCString& flatKey = PromiseFlatCString(aKey); PropertyTableEntry *entry = static_cast<PropertyTableEntry*> (PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_ADD)); if (entry->mKey) { aOldValue = entry->mValue; NS_WARNING(nsPrintfCString(aKey.Length() + 30, "the property %s already exists\n", flatKey.get()).get()); } else { aOldValue.Truncate(); } entry->mKey = ArenaStrdup(flatKey, &mArena); entry->mValue = ArenaStrdup(PromiseFlatString(aNewValue), &mArena); return NS_OK; }
void AppendUTF8toUTF16( const nsACString& aSource, nsAString& aDest ) { if (!AppendUTF8toUTF16(aSource, aDest, mozilla::fallible_t())) { NS_ABORT_OOM(aDest.Length() + aSource.Length()); } }
nsresult NS_CopyNativeToUnicode(const nsACString& aInput, nsAString& aOutput) { uint32_t inputLen = aInput.Length(); nsACString::const_iterator iter; aInput.BeginReading(iter); const char* buf = iter.get(); // determine length of result uint32_t resultLen = 0; int n = ::MultiByteToWideChar(CP_ACP, 0, buf, inputLen, nullptr, 0); if (n > 0) { resultLen += n; } // allocate sufficient space if (!aOutput.SetLength(resultLen, fallible)) { return NS_ERROR_OUT_OF_MEMORY; } if (resultLen > 0) { nsAString::iterator out_iter; aOutput.BeginWriting(out_iter); char16_t* result = out_iter.get(); ::MultiByteToWideChar(CP_ACP, 0, buf, inputLen, wwc(result), resultLen); } return NS_OK; }
/** Takes an ASCII string like "foo[i]", turns it into "foo" and returns "[i]" in bracketPart * * \param string input/output: the string to split, becomes the string without the bracket part * \param bracketPart output: gets the bracket part. * * Notice that if there are multiple brackets like "foo[i].bar[j]", only the last bracket is split. */ static bool SplitLastSquareBracket(nsACString& string, nsCString& bracketPart) { MOZ_ASSERT(bracketPart.IsEmpty(), "SplitLastSquareBracket must be called with empty bracketPart string"); if (string.IsEmpty()) return false; char *string_start = string.BeginWriting(); char *s = string_start + string.Length() - 1; if (*s != ']') return false; while (*s != '[' && s != string_start) s--; if (*s != '[') return false; bracketPart.Assign(s); *s = 0; string.EndWriting(); string.SetLength(s - string_start); return true; }
// Get the base domain for aHostURI; e.g. for "www.bbc.co.uk", this would be // "bbc.co.uk". Only properly-formed URI's are tolerated, though a trailing // dot may be present. If aHostURI is an IP address, an alias such as // 'localhost', an eTLD such as 'co.uk', or the empty string, aBaseDomain will // be the exact host. The result of this function should only be used in exact // string comparisons, since substring comparisons will not be valid for the // special cases elided above. NS_IMETHODIMP ThirdPartyUtil::GetBaseDomain(nsIURI* aHostURI, nsACString& aBaseDomain) { // Get the base domain. this will fail if the host contains a leading dot, // more than one trailing dot, or is otherwise malformed. nsresult rv = mTLDService->GetBaseDomain(aHostURI, 0, aBaseDomain); if (rv == NS_ERROR_HOST_IS_IP_ADDRESS || rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) { // aHostURI is either an IP address, an alias such as 'localhost', an eTLD // such as 'co.uk', or the empty string. Uses the normalized host in such // cases. rv = aHostURI->GetAsciiHost(aBaseDomain); } NS_ENSURE_SUCCESS(rv, rv); // aHostURI (and thus aBaseDomain) may be the string '.'. If so, fail. if (aBaseDomain.Length() == 1 && aBaseDomain.Last() == '.') return NS_ERROR_INVALID_ARG; // Reject any URIs without a host that aren't file:// URIs. This makes it the // only way we can get a base domain consisting of the empty string, which // means we can safely perform foreign tests on such URIs where "not foreign" // means "the involved URIs are all file://". if (aBaseDomain.IsEmpty()) { bool isFileURI = false; aHostURI->SchemeIs("file", &isFileURI); NS_ENSURE_TRUE(isFileURI, NS_ERROR_INVALID_ARG); } return NS_OK; }
NS_IMETHODIMP nsMacShellService::OpenApplicationWithURI(nsIFile* aApplication, const nsACString& aURI) { nsCOMPtr<nsILocalFileMac> lfm(do_QueryInterface(aApplication)); CFURLRef appURL; nsresult rv = lfm->GetCFURL(&appURL); if (NS_FAILED(rv)) return rv; const nsCString spec(aURI); const UInt8* uriString = (const UInt8*)spec.get(); CFURLRef uri = ::CFURLCreateWithBytes(nullptr, uriString, aURI.Length(), kCFStringEncodingUTF8, nullptr); if (!uri) return NS_ERROR_OUT_OF_MEMORY; CFArrayRef uris = ::CFArrayCreate(nullptr, (const void**)&uri, 1, nullptr); if (!uris) { ::CFRelease(uri); return NS_ERROR_OUT_OF_MEMORY; } LSLaunchURLSpec launchSpec; launchSpec.appURL = appURL; launchSpec.itemURLs = uris; launchSpec.passThruParams = nullptr; launchSpec.launchFlags = kLSLaunchDefaults; launchSpec.asyncRefCon = nullptr; OSErr err = ::LSOpenFromURLSpec(&launchSpec, nullptr); ::CFRelease(uris); ::CFRelease(uri); return err != noErr ? NS_ERROR_FAILURE : NS_OK; }