nsresult nsHyphenator::Hyphenate(const nsAString& aString, nsTArray<PRPackedBool>& aHyphens) { if (!aHyphens.SetLength(aString.Length())) { return NS_ERROR_OUT_OF_MEMORY; } memset(aHyphens.Elements(), PR_FALSE, aHyphens.Length()); PRBool inWord = PR_FALSE; PRUint32 wordStart = 0, wordLimit = 0; for (PRUint32 i = 0; i < aString.Length(); i++) { PRUnichar ch = aString[i]; nsIUGenCategory::nsUGenCategory cat = mCategories->Get(ch); if (cat == nsIUGenCategory::kLetter || cat == nsIUGenCategory::kMark) { if (!inWord) { inWord = PR_TRUE; wordStart = i; } wordLimit = i + 1; if (i < aString.Length() - 1) { continue; } } if (inWord) { NS_ConvertUTF16toUTF8 utf8(aString.BeginReading() + wordStart, wordLimit - wordStart); nsAutoTArray<char,200> utf8hyphens; utf8hyphens.SetLength(utf8.Length() + 5); char **rep = nsnull; int *pos = nsnull; int *cut = nsnull; int err = hnj_hyphen_hyphenate2((HyphenDict*)mDict, utf8.BeginReading(), utf8.Length(), utf8hyphens.Elements(), nsnull, &rep, &pos, &cut); if (!err) { PRUint32 utf16offset = wordStart; const char *cp = utf8.BeginReading(); while (cp < utf8.EndReading()) { if (UTF8traits::isASCII(*cp)) { // single-byte utf8 char cp++; utf16offset++; } else if (UTF8traits::is2byte(*cp)) { // 2-byte sequence cp += 2; utf16offset++; } else if (UTF8traits::is3byte(*cp)) { // 3-byte sequence cp += 3; utf16offset++; } else { // must be a 4-byte sequence (no need to check validity, // as this was just created with NS_ConvertUTF16toUTF8) NS_ASSERTION(UTF8traits::is4byte(*cp), "unexpected utf8 byte"); cp += 4; utf16offset += 2; } NS_ASSERTION(cp <= utf8.EndReading(), "incomplete utf8 string?"); NS_ASSERTION(utf16offset <= aString.Length(), "length mismatch?"); if (utf8hyphens[cp - utf8.BeginReading() - 1] & 0x01) { aHyphens[utf16offset - 1] = PR_TRUE; } } } } inWord = PR_FALSE; } return NS_OK; }
bool nsDSURIContentListener::CheckOneFrameOptionsPolicy(nsIHttpChannel* aHttpChannel, const nsAString& aPolicy) { static const char allowFrom[] = "allow-from"; const uint32_t allowFromLen = ArrayLength(allowFrom) - 1; bool isAllowFrom = StringHead(aPolicy, allowFromLen).LowerCaseEqualsLiteral(allowFrom); // return early if header does not have one of the values with meaning if (!aPolicy.LowerCaseEqualsLiteral("deny") && !aPolicy.LowerCaseEqualsLiteral("sameorigin") && !isAllowFrom) { return true; } nsCOMPtr<nsIURI> uri; aHttpChannel->GetURI(getter_AddRefs(uri)); // XXXkhuey when does this happen? Is returning true safe here? if (!mDocShell) { return true; } // We need to check the location of this window and the location of the top // window, if we're not the top. X-F-O: SAMEORIGIN requires that the // document must be same-origin with top window. X-F-O: DENY requires that // the document must never be framed. nsCOMPtr<nsPIDOMWindowOuter> thisWindow = mDocShell->GetWindow(); // If we don't have DOMWindow there is no risk of clickjacking if (!thisWindow) { return true; } // GetScriptableTop, not GetTop, because we want this to respect // <iframe mozbrowser> boundaries. nsCOMPtr<nsPIDOMWindowOuter> topWindow = thisWindow->GetScriptableTop(); // if the document is in the top window, it's not in a frame. if (thisWindow == topWindow) { return true; } // Find the top docshell in our parent chain that doesn't have the system // principal and use it for the principal comparison. Finding the top // content-type docshell doesn't work because some chrome documents are // loaded in content docshells (see bug 593387). nsCOMPtr<nsIDocShellTreeItem> thisDocShellItem( do_QueryInterface(static_cast<nsIDocShell*>(mDocShell))); nsCOMPtr<nsIDocShellTreeItem> parentDocShellItem; nsCOMPtr<nsIDocShellTreeItem> curDocShellItem = thisDocShellItem; nsCOMPtr<nsIDocument> topDoc; nsresult rv; nsCOMPtr<nsIScriptSecurityManager> ssm = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (!ssm) { MOZ_CRASH(); } // Traverse up the parent chain and stop when we see a docshell whose // parent has a system principal, or a docshell corresponding to // <iframe mozbrowser>. while (NS_SUCCEEDED( curDocShellItem->GetParent(getter_AddRefs(parentDocShellItem))) && parentDocShellItem) { nsCOMPtr<nsIDocShell> curDocShell = do_QueryInterface(curDocShellItem); if (curDocShell && curDocShell->GetIsMozBrowserOrApp()) { break; } bool system = false; topDoc = parentDocShellItem->GetDocument(); if (topDoc) { if (NS_SUCCEEDED( ssm->IsSystemPrincipal(topDoc->NodePrincipal(), &system)) && system) { // Found a system-principled doc: last docshell was top. break; } } else { return false; } curDocShellItem = parentDocShellItem; } // If this document has the top non-SystemPrincipal docshell it is not being // framed or it is being framed by a chrome document, which we allow. if (curDocShellItem == thisDocShellItem) { return true; } // If the value of the header is DENY, and the previous condition is // not met (current docshell is not the top docshell), prohibit the // load. if (aPolicy.LowerCaseEqualsLiteral("deny")) { ReportXFOViolation(curDocShellItem, uri, eDENY); return false; } topDoc = curDocShellItem->GetDocument(); nsCOMPtr<nsIURI> topUri; topDoc->NodePrincipal()->GetURI(getter_AddRefs(topUri)); // If the X-Frame-Options value is SAMEORIGIN, then the top frame in the // parent chain must be from the same origin as this document. if (aPolicy.LowerCaseEqualsLiteral("sameorigin")) { rv = ssm->CheckSameOriginURI(uri, topUri, true); if (NS_FAILED(rv)) { ReportXFOViolation(curDocShellItem, uri, eSAMEORIGIN); return false; /* wasn't same-origin */ } } // If the X-Frame-Options value is "allow-from [uri]", then the top // frame in the parent chain must be from that origin if (isAllowFrom) { if (aPolicy.Length() == allowFromLen || (aPolicy[allowFromLen] != ' ' && aPolicy[allowFromLen] != '\t')) { ReportXFOViolation(curDocShellItem, uri, eALLOWFROM); return false; } rv = NS_NewURI(getter_AddRefs(uri), Substring(aPolicy, allowFromLen)); if (NS_FAILED(rv)) { return false; } rv = ssm->CheckSameOriginURI(uri, topUri, true); if (NS_FAILED(rv)) { ReportXFOViolation(curDocShellItem, uri, eALLOWFROM); return false; } } return true; }
nsresult nsKeygenFormProcessor::GetPublicKey(nsAString& aValue, nsAString& aChallenge, nsAFlatString& aKeyType, nsAString& aOutPublicKey, nsAString& aKeyParams) { nsNSSShutDownPreventionLock locker; nsresult rv = NS_ERROR_FAILURE; char *keystring = nullptr; char *keyparamsString = nullptr, *str = nullptr; uint32_t keyGenMechanism; int32_t primeBits; PK11SlotInfo *slot = nullptr; PK11RSAGenParams rsaParams; SECOidTag algTag; int keysize = 0; void *params; SECKEYPrivateKey *privateKey = nullptr; SECKEYPublicKey *publicKey = nullptr; CERTSubjectPublicKeyInfo *spkInfo = nullptr; PLArenaPool *arena = nullptr; SECStatus sec_rv = SECFailure; SECItem spkiItem; SECItem pkacItem; SECItem signedItem; CERTPublicKeyAndChallenge pkac; pkac.challenge.data = nullptr; nsIGeneratingKeypairInfoDialogs * dialogs; nsKeygenThread *KeygenRunnable = 0; nsCOMPtr<nsIKeygenThread> runnable; // permanent and sensitive flags for keygen PK11AttrFlags attrFlags = PK11_ATTR_TOKEN | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE; // Get the key size // for (size_t i = 0; i < number_of_key_size_choices; ++i) { if (aValue.Equals(mSECKeySizeChoiceList[i].name)) { keysize = mSECKeySizeChoiceList[i].size; break; } } if (!keysize) { goto loser; } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { goto loser; } // Set the keygen mechanism if (aKeyType.IsEmpty() || aKeyType.LowerCaseEqualsLiteral("rsa")) { keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; } else if (aKeyType.LowerCaseEqualsLiteral("dsa")) { char * end; keyparamsString = ToNewCString(aKeyParams); if (!keyparamsString) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; } keyGenMechanism = CKM_DSA_KEY_PAIR_GEN; if (strcmp(keyparamsString, "null") == 0) goto loser; str = keyparamsString; bool found_match = false; do { end = strchr(str, ','); if (end != nullptr) *end = '\0'; primeBits = pqg_prime_bits(str); if (keysize == primeBits) { found_match = true; break; } str = end + 1; } while (end != nullptr); if (!found_match) { goto loser; } } else if (aKeyType.LowerCaseEqualsLiteral("ec")) { keyparamsString = ToNewCString(aKeyParams); if (!keyparamsString) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; } keyGenMechanism = CKM_EC_KEY_PAIR_GEN; /* ecParams are initialized later */ } else { goto loser; } // Get the slot rv = GetSlot(keyGenMechanism, &slot); if (NS_FAILED(rv)) { goto loser; } switch (keyGenMechanism) { case CKM_RSA_PKCS_KEY_PAIR_GEN: rsaParams.keySizeInBits = keysize; rsaParams.pe = DEFAULT_RSA_KEYGEN_PE; algTag = DEFAULT_RSA_KEYGEN_ALG; params = &rsaParams; break; case CKM_DSA_KEY_PAIR_GEN: // XXX Fix this! XXX // goto loser; case CKM_EC_KEY_PAIR_GEN: /* XXX We ought to rethink how the KEYGEN tag is * displayed. The pulldown selections presented * to the user must depend on the keytype. * The displayed selection could be picked * from the keyparams attribute (this is currently called * the pqg attribute). * For now, we pick ecparams from the keyparams field * if it specifies a valid supported curve, or else * we pick one of secp384r1, secp256r1 or secp192r1 * respectively depending on the user's selection * (High, Medium, Low). * (RSA uses RSA-2048, RSA-1024 and RSA-512 for historical * reasons, while ECC choices represent a stronger mapping) * NOTE: The user's selection * is silently ignored when a valid curve is presented * in keyparams. */ if ((params = decode_ec_params(keyparamsString)) == nullptr) { /* The keyparams attribute did not specify a valid * curve name so use a curve based on the keysize. * NOTE: Here keysize is used only as an indication of * High/Medium/Low strength; elliptic curve * cryptography uses smaller keys than RSA to provide * equivalent security. */ switch (keysize) { case 2048: params = decode_ec_params("secp384r1"); break; case 1024: case 512: params = decode_ec_params("secp256r1"); break; } } /* XXX The signature algorithm ought to choose the hashing * algorithm based on key size once ECDSA variations based * on SHA256 SHA384 and SHA512 are standardized. */ algTag = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST; break; default: goto loser; } /* Make sure token is initialized. */ rv = setPassword(slot, m_ctx); if (NS_FAILED(rv)) goto loser; sec_rv = PK11_Authenticate(slot, true, m_ctx); if (sec_rv != SECSuccess) { goto loser; } rv = getNSSDialogs((void**)&dialogs, NS_GET_IID(nsIGeneratingKeypairInfoDialogs), NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID); if (NS_SUCCEEDED(rv)) { KeygenRunnable = new nsKeygenThread(); NS_IF_ADDREF(KeygenRunnable); } if (NS_FAILED(rv) || !KeygenRunnable) { rv = NS_OK; privateKey = PK11_GenerateKeyPairWithFlags(slot, keyGenMechanism, params, &publicKey, attrFlags, m_ctx); } else { KeygenRunnable->SetParams( slot, attrFlags, nullptr, 0, keyGenMechanism, params, m_ctx ); runnable = do_QueryInterface(KeygenRunnable); if (runnable) { { nsPSMUITracker tracker; if (tracker.isUIForbidden()) { rv = NS_ERROR_NOT_AVAILABLE; } else { rv = dialogs->DisplayGeneratingKeypairInfo(m_ctx, runnable); // We call join on the thread, // so we can be sure that no simultaneous access to the passed parameters will happen. KeygenRunnable->Join(); } } NS_RELEASE(dialogs); if (NS_SUCCEEDED(rv)) { PK11SlotInfo *used_slot = nullptr; rv = KeygenRunnable->ConsumeResult(&used_slot, &privateKey, &publicKey); if (NS_SUCCEEDED(rv) && used_slot) { PK11_FreeSlot(used_slot); } } } } if (NS_FAILED(rv) || !privateKey) { goto loser; } // just in case we'll need to authenticate to the db -jp // privateKey->wincx = m_ctx; /* * Create a subject public key info from the public key. */ spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey); if ( !spkInfo ) { goto loser; } /* * Now DER encode the whole subjectPublicKeyInfo. */ sec_rv=DER_Encode(arena, &spkiItem, CERTSubjectPublicKeyInfoTemplate, spkInfo); if (sec_rv != SECSuccess) { goto loser; } /* * set up the PublicKeyAndChallenge data structure, then DER encode it */ pkac.spki = spkiItem; pkac.challenge.len = aChallenge.Length(); pkac.challenge.data = (unsigned char *)ToNewCString(aChallenge); if (!pkac.challenge.data) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; } sec_rv = DER_Encode(arena, &pkacItem, CERTPublicKeyAndChallengeTemplate, &pkac); if ( sec_rv != SECSuccess ) { goto loser; } /* * now sign the DER encoded PublicKeyAndChallenge */ sec_rv = SEC_DerSignData(arena, &signedItem, pkacItem.data, pkacItem.len, privateKey, algTag); if ( sec_rv != SECSuccess ) { goto loser; } /* * Convert the signed public key and challenge into base64/ascii. */ keystring = BTOA_DataToAscii(signedItem.data, signedItem.len); if (!keystring) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; } CopyASCIItoUTF16(keystring, aOutPublicKey); nsCRT::free(keystring); rv = NS_OK; loser: if ( sec_rv != SECSuccess ) { if ( privateKey ) { PK11_DestroyTokenObject(privateKey->pkcs11Slot,privateKey->pkcs11ID); } if ( publicKey ) { PK11_DestroyTokenObject(publicKey->pkcs11Slot,publicKey->pkcs11ID); } } if ( spkInfo ) { SECKEY_DestroySubjectPublicKeyInfo(spkInfo); } if ( publicKey ) { SECKEY_DestroyPublicKey(publicKey); } if ( privateKey ) { SECKEY_DestroyPrivateKey(privateKey); } if ( arena ) { PORT_FreeArena(arena, true); } if (slot != nullptr) { PK11_FreeSlot(slot); } if (KeygenRunnable) { NS_RELEASE(KeygenRunnable); } if (keyparamsString) { nsMemory::Free(keyparamsString); } if (pkac.challenge.data) { nsMemory::Free(pkac.challenge.data); } return rv; }
nsresult nsHyphenator::Hyphenate(const nsAString& aString, nsTArray<bool>& aHyphens) { if (!aHyphens.SetLength(aString.Length())) { return NS_ERROR_OUT_OF_MEMORY; } memset(aHyphens.Elements(), PR_FALSE, aHyphens.Length()); bool inWord = false; PRUint32 wordStart = 0, wordLimit = 0; PRUint32 chLen; for (PRUint32 i = 0; i < aString.Length(); i += chLen) { PRUint32 ch = aString[i]; chLen = 1; if (NS_IS_HIGH_SURROGATE(ch)) { if (i + 1 < aString.Length() && NS_IS_LOW_SURROGATE(aString[i+1])) { ch = SURROGATE_TO_UCS4(ch, aString[i+1]); chLen = 2; } else { NS_WARNING("unpaired surrogate found during hyphenation"); } } nsIUGenCategory::nsUGenCategory cat = mCategories->Get(ch); if (cat == nsIUGenCategory::kLetter || cat == nsIUGenCategory::kMark) { if (!inWord) { inWord = PR_TRUE; wordStart = i; } wordLimit = i + chLen; if (i + chLen < aString.Length()) { continue; } } if (inWord) { const PRUnichar *begin = aString.BeginReading(); NS_ConvertUTF16toUTF8 utf8(begin + wordStart, wordLimit - wordStart); nsAutoTArray<char,200> utf8hyphens; utf8hyphens.SetLength(utf8.Length() + 5); char **rep = nsnull; int *pos = nsnull; int *cut = nsnull; int err = hnj_hyphen_hyphenate2((HyphenDict*)mDict, utf8.BeginReading(), utf8.Length(), utf8hyphens.Elements(), nsnull, &rep, &pos, &cut); if (!err) { // Surprisingly, hnj_hyphen_hyphenate2 converts the 'hyphens' buffer // from utf8 code unit indexing (which would match the utf8 input // string directly) to Unicode character indexing. // We then need to convert this to utf16 code unit offsets for Gecko. const char *hyphPtr = utf8hyphens.Elements(); const PRUnichar *cur = begin + wordStart; const PRUnichar *end = begin + wordLimit; while (cur < end) { if (*hyphPtr & 0x01) { aHyphens[cur - begin] = PR_TRUE; } cur++; if (cur < end && NS_IS_LOW_SURROGATE(*cur) && NS_IS_HIGH_SURROGATE(*(cur-1))) { cur++; } hyphPtr++; } } } inWord = PR_FALSE; } return NS_OK; }
NS_IMETHODIMP nsHtml5Parser::Parse(const nsAString& aSourceBuffer, void* aKey, const nsACString& aContentType, // ignored PRBool aLastCall, nsDTDMode aMode) // ignored { NS_PRECONDITION(!mExecutor->IsFragmentMode(), "Document.write called in fragment mode!"); // Maintain a reference to ourselves so we don't go away // till we're completely done. The old parser grips itself in this method. nsCOMPtr<nsIParser> kungFuDeathGrip(this); // Gripping the other objects just in case, since the other old grip // required grips to these, too. nsRefPtr<nsHtml5StreamParser> streamKungFuDeathGrip(mStreamParser); nsRefPtr<nsHtml5TreeOpExecutor> treeOpKungFuDeathGrip(mExecutor); if (!mExecutor->HasStarted()) { NS_ASSERTION(!mStreamParser, "Had stream parser but document.write started life cycle."); // This is the first document.write() on a document.open()ed document mExecutor->SetParser(this); mTreeBuilder->setScriptingEnabled(mExecutor->IsScriptEnabled()); mTokenizer->start(); mExecutor->Start(); /* * If you move the following line, be very careful not to cause * WillBuildModel to be called before the document has had its * script global object set. */ mExecutor->WillBuildModel(eDTDMode_unknown); } // Return early if the parser has processed EOF if (mExecutor->IsComplete()) { return NS_OK; } if (aLastCall && aSourceBuffer.IsEmpty() && aKey == GetRootContextKey()) { // document.close() NS_ASSERTION(!mStreamParser, "Had stream parser but got document.close()."); mDocumentClosed = PR_TRUE; if (!mBlocked) { ParseUntilBlocked(); } return NS_OK; } NS_ASSERTION(IsInsertionPointDefined(), "Doc.write reached parser with undefined insertion point."); NS_ASSERTION(!(mStreamParser && !aKey), "Got a null key in a non-script-created parser"); if (aSourceBuffer.IsEmpty()) { return NS_OK; } nsRefPtr<nsHtml5UTF16Buffer> buffer = new nsHtml5UTF16Buffer(aSourceBuffer.Length()); memcpy(buffer->getBuffer(), aSourceBuffer.BeginReading(), aSourceBuffer.Length() * sizeof(PRUnichar)); buffer->setEnd(aSourceBuffer.Length()); // The buffer is inserted to the stream here in case it won't be parsed // to completion. // The script is identified by aKey. If there's nothing in the buffer // chain for that key, we'll insert at the head of the queue. // When the script leaves something in the queue, a zero-length // key-holder "buffer" is inserted in the queue. If the same script // leaves something in the chain again, it will be inserted immediately // before the old key holder belonging to the same script. nsHtml5UTF16Buffer* prevSearchBuf = nsnull; nsHtml5UTF16Buffer* searchBuf = mFirstBuffer; // after document.open, the first level of document.write has null key if (aKey) { while (searchBuf != mLastBuffer) { if (searchBuf->key == aKey) { // found a key holder // now insert the new buffer between the previous buffer // and the key holder. buffer->next = searchBuf; if (prevSearchBuf) { prevSearchBuf->next = buffer; } else { mFirstBuffer = buffer; } break; } prevSearchBuf = searchBuf; searchBuf = searchBuf->next; } if (searchBuf == mLastBuffer) { // key was not found nsHtml5UTF16Buffer* keyHolder = new nsHtml5UTF16Buffer(aKey); keyHolder->next = mFirstBuffer; buffer->next = keyHolder; mFirstBuffer = buffer; } } else { // we have a first level document.write after document.open() // insert immediately before mLastBuffer while (searchBuf != mLastBuffer) { prevSearchBuf = searchBuf; searchBuf = searchBuf->next; } buffer->next = mLastBuffer; if (prevSearchBuf) { prevSearchBuf->next = buffer; } else { mFirstBuffer = buffer; } } while (!mBlocked && buffer->hasMore()) { buffer->adjust(mLastWasCR); mLastWasCR = PR_FALSE; if (buffer->hasMore()) { PRInt32 lineNumberSave; PRBool inRootContext = (!mStreamParser && (aKey == mRootContextKey)); if (inRootContext) { mTokenizer->setLineNumber(mRootContextLineNumber); } else { // we aren't the root context, so save the line number on the // *stack* so that we can restore it. lineNumberSave = mTokenizer->getLineNumber(); } mLastWasCR = mTokenizer->tokenizeBuffer(buffer); if (inRootContext) { mRootContextLineNumber = mTokenizer->getLineNumber(); } else { mTokenizer->setLineNumber(lineNumberSave); } if (mTreeBuilder->HasScript()) { mTreeBuilder->Flush(); // Move ops to the executor mExecutor->FlushDocumentWrite(); // run the ops } // Ignore suspension requests } } if (!mBlocked) { // buffer was tokenized to completion NS_ASSERTION(!buffer->hasMore(), "Buffer wasn't tokenized to completion?"); // Scripting semantics require a forced tree builder flush here mTreeBuilder->Flush(); // Move ops to the executor mExecutor->FlushDocumentWrite(); // run the ops } else if (buffer->hasMore()) { // The buffer wasn't tokenized to completion. Tokenize the untokenized // content in order to preload stuff. This content will be retokenized // later for normal parsing. if (!mDocWriteSpeculatorActive) { mDocWriteSpeculatorActive = PR_TRUE; if (!mDocWriteSpeculativeTreeBuilder) { // Lazily initialize if uninitialized mDocWriteSpeculativeTreeBuilder = new nsHtml5TreeBuilder(nsnull, mExecutor->GetStage()); mDocWriteSpeculativeTreeBuilder->setScriptingEnabled( mTreeBuilder->isScriptingEnabled()); mDocWriteSpeculativeTokenizer = new nsHtml5Tokenizer(mDocWriteSpeculativeTreeBuilder); mDocWriteSpeculativeTokenizer->setInterner(&mAtomTable); mDocWriteSpeculativeTokenizer->start(); } mDocWriteSpeculativeTokenizer->resetToDataState(); mDocWriteSpeculativeTreeBuilder->loadState(mTreeBuilder, &mAtomTable); mDocWriteSpeculativeLastWasCR = PR_FALSE; } // Note that with multilevel document.write if we didn't just activate the // speculator, it's possible that the speculator is now in the wrong state. // That's OK for the sake of simplicity. The worst that can happen is // that the speculative loads aren't exactly right. The content will be // reparsed anyway for non-preload purposes. PRInt32 originalStart = buffer->getStart(); while (buffer->hasMore()) { buffer->adjust(mDocWriteSpeculativeLastWasCR); if (buffer->hasMore()) { mDocWriteSpeculativeLastWasCR = mDocWriteSpeculativeTokenizer->tokenizeBuffer(buffer); } } buffer->setStart(originalStart); mDocWriteSpeculativeTreeBuilder->Flush(); mDocWriteSpeculativeTreeBuilder->DropHandles(); mExecutor->FlushSpeculativeLoads(); } return NS_OK; }
void nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations (nsAString& aString, CSSStyleSheet* aSheet, bool aIsNegated, bool aUseStandardNamespacePrefixes) const { nsAutoString temp; bool isPseudoElement = IsPseudoElement(); // For non-pseudo-element selectors or for lone pseudo-elements, deal with // namespace prefixes. bool wroteNamespace = false; if (!isPseudoElement || !mNext) { // append the namespace prefix if needed nsXMLNameSpaceMap *sheetNS = aSheet ? aSheet->GetNameSpaceMap() : nullptr; // sheetNS is non-null if and only if we had an @namespace rule. If it's // null, that means that the only namespaces we could have are the // wildcard namespace (which can be implicit in this case) and the "none" // namespace, which then needs to be explicitly specified. if (aUseStandardNamespacePrefixes) { #ifdef DEBUG // We have no sheet to look up prefix information from. This is // only for debugging, so use some "standard" prefixes that // are recognizable. wroteNamespace = AppendStandardNamespacePrefixToString(aString, mNameSpace); if (wroteNamespace) { aString.Append(char16_t('|')); } #endif } else if (!sheetNS) { NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown || mNameSpace == kNameSpaceID_None, "How did we get this namespace?"); if (mNameSpace == kNameSpaceID_None) { aString.Append(char16_t('|')); wroteNamespace = true; } } else if (sheetNS->FindNameSpaceID(nullptr) == mNameSpace) { // We have the default namespace (possibly including the wildcard // namespace). Do nothing. NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown || CanBeNamespaced(aIsNegated), "How did we end up with this namespace?"); } else if (mNameSpace == kNameSpaceID_None) { NS_ASSERTION(CanBeNamespaced(aIsNegated), "How did we end up with this namespace?"); aString.Append(char16_t('|')); wroteNamespace = true; } else if (mNameSpace != kNameSpaceID_Unknown) { NS_ASSERTION(CanBeNamespaced(aIsNegated), "How did we end up with this namespace?"); nsIAtom *prefixAtom = sheetNS->FindPrefix(mNameSpace); NS_ASSERTION(prefixAtom, "how'd we get a non-default namespace " "without a prefix?"); nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(prefixAtom), aString); aString.Append(char16_t('|')); wroteNamespace = true; } else { // A selector for an element in any namespace, while the default // namespace is something else. :not() is special in that the default // namespace is not implied for non-type selectors, so if this is a // negated non-type selector we don't need to output an explicit wildcard // namespace here, since those default to a wildcard namespace. if (CanBeNamespaced(aIsNegated)) { aString.AppendLiteral("*|"); wroteNamespace = true; } } } if (!mLowercaseTag) { // Universal selector: avoid writing the universal selector when we // can avoid it, especially since we're required to avoid it for the // inside of :not() if (wroteNamespace || (!mIDList && !mClassList && !mPseudoClassList && !mAttrList && (aIsNegated || !mNegations))) { aString.Append(char16_t('*')); } } else { // Append the tag name nsAutoString tag; (isPseudoElement ? mLowercaseTag : mCasedTag)->ToString(tag); if (isPseudoElement) { if (!mNext) { // Lone pseudo-element selector -- toss in a wildcard type selector // XXXldb Why? aString.Append(char16_t('*')); } // While our atoms use one colon, most pseudo-elements require two // colons (those not in CSS level 2) and all pseudo-elements allow // two colons. So serialize to the non-deprecated two colon syntax. aString.Append(char16_t(':')); // This should not be escaped since (a) the pseudo-element string // has a ":" that can't be escaped and (b) all pseudo-elements at // this point are known, and therefore we know they don't need // escaping. aString.Append(tag); } else { nsStyleUtil::AppendEscapedCSSIdent(tag, aString); } } // Append the id, if there is one if (mIDList) { nsAtomList* list = mIDList; while (list != nullptr) { list->mAtom->ToString(temp); aString.Append(char16_t('#')); nsStyleUtil::AppendEscapedCSSIdent(temp, aString); list = list->mNext; } } // Append each class in the linked list if (mClassList) { if (isPseudoElement) { #ifdef MOZ_XUL MOZ_ASSERT(nsCSSAnonBoxes::IsTreePseudoElement(mLowercaseTag), "must be tree pseudo-element"); aString.Append(char16_t('(')); for (nsAtomList* list = mClassList; list; list = list->mNext) { nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(list->mAtom), aString); aString.Append(char16_t(',')); } // replace the final comma with a close-paren aString.Replace(aString.Length() - 1, 1, char16_t(')')); #else NS_ERROR("Can't happen"); #endif } else { nsAtomList* list = mClassList; while (list != nullptr) { list->mAtom->ToString(temp); aString.Append(char16_t('.')); nsStyleUtil::AppendEscapedCSSIdent(temp, aString); list = list->mNext; } } } // Append each attribute selector in the linked list if (mAttrList) { nsAttrSelector* list = mAttrList; while (list != nullptr) { aString.Append(char16_t('[')); // Append the namespace prefix if (list->mNameSpace == kNameSpaceID_Unknown) { aString.Append(char16_t('*')); aString.Append(char16_t('|')); } else if (list->mNameSpace != kNameSpaceID_None) { if (aUseStandardNamespacePrefixes) { #ifdef DEBUG AppendStandardNamespacePrefixToString(aString, list->mNameSpace); aString.Append(char16_t('|')); #endif } else if (aSheet) { nsXMLNameSpaceMap *sheetNS = aSheet->GetNameSpaceMap(); nsIAtom *prefixAtom = sheetNS->FindPrefix(list->mNameSpace); // Default namespaces don't apply to attribute selectors, so // we must have a useful prefix. NS_ASSERTION(prefixAtom, "How did we end up with a namespace if the prefix " "is unknown?"); nsAutoString prefix; prefixAtom->ToString(prefix); nsStyleUtil::AppendEscapedCSSIdent(prefix, aString); aString.Append(char16_t('|')); } } // Append the attribute name list->mCasedAttr->ToString(temp); nsStyleUtil::AppendEscapedCSSIdent(temp, aString); if (list->mFunction != NS_ATTR_FUNC_SET) { // Append the function if (list->mFunction == NS_ATTR_FUNC_INCLUDES) aString.Append(char16_t('~')); else if (list->mFunction == NS_ATTR_FUNC_DASHMATCH) aString.Append(char16_t('|')); else if (list->mFunction == NS_ATTR_FUNC_BEGINSMATCH) aString.Append(char16_t('^')); else if (list->mFunction == NS_ATTR_FUNC_ENDSMATCH) aString.Append(char16_t('$')); else if (list->mFunction == NS_ATTR_FUNC_CONTAINSMATCH) aString.Append(char16_t('*')); aString.Append(char16_t('=')); // Append the value nsStyleUtil::AppendEscapedCSSString(list->mValue, aString); if (list->mValueCaseSensitivity == nsAttrSelector::ValueCaseSensitivity::CaseInsensitive) { aString.Append(NS_LITERAL_STRING(" i")); } } aString.Append(char16_t(']')); list = list->mNext; } } // Append each pseudo-class in the linked list for (nsPseudoClassList* list = mPseudoClassList; list; list = list->mNext) { nsCSSPseudoClasses::PseudoTypeToString(list->mType, temp); // This should not be escaped since (a) the pseudo-class string // has a ":" that can't be escaped and (b) all pseudo-classes at // this point are known, and therefore we know they don't need // escaping. aString.Append(temp); if (list->u.mMemory) { aString.Append(char16_t('(')); if (nsCSSPseudoClasses::HasStringArg(list->mType)) { nsStyleUtil::AppendEscapedCSSIdent( nsDependentString(list->u.mString), aString); } else if (nsCSSPseudoClasses::HasNthPairArg(list->mType)) { int32_t a = list->u.mNumbers[0], b = list->u.mNumbers[1]; temp.Truncate(); if (a != 0) { if (a == -1) { temp.Append(char16_t('-')); } else if (a != 1) { temp.AppendInt(a); } temp.Append(char16_t('n')); } if (b != 0 || a == 0) { if (b >= 0 && a != 0) // check a != 0 for whether we printed above temp.Append(char16_t('+')); temp.AppendInt(b); } aString.Append(temp); } else { NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(list->mType), "unexpected pseudo-class"); nsString tmp; list->u.mSelectors->ToString(tmp, aSheet); aString.Append(tmp); } aString.Append(char16_t(')')); } } }
nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const nsAString& aValue) { return CheckSanityOfStringLength(aPrefName, aValue.Length()); }
NS_IMETHODIMP nsHtml5Parser::Parse(const nsAString& aSourceBuffer, void* aKey, const nsACString& aContentType, bool aLastCall, nsDTDMode aMode) // ignored { nsresult rv; if (NS_FAILED(rv = mExecutor->IsBroken())) { return rv; } if (aSourceBuffer.Length() > INT32_MAX) { return mExecutor->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY); } // Maintain a reference to ourselves so we don't go away // till we're completely done. The old parser grips itself in this method. nsCOMPtr<nsIParser> kungFuDeathGrip(this); // Gripping the other objects just in case, since the other old grip // required grips to these, too. nsRefPtr<nsHtml5StreamParser> streamKungFuDeathGrip(GetStreamParser()); nsRefPtr<nsHtml5TreeOpExecutor> treeOpKungFuDeathGrip(mExecutor); if (!mExecutor->HasStarted()) { NS_ASSERTION(!GetStreamParser(), "Had stream parser but document.write started life cycle."); // This is the first document.write() on a document.open()ed document mExecutor->SetParser(this); mTreeBuilder->setScriptingEnabled(mExecutor->IsScriptEnabled()); bool isSrcdoc = false; nsCOMPtr<nsIChannel> channel; rv = GetChannel(getter_AddRefs(channel)); if (NS_SUCCEEDED(rv)) { isSrcdoc = NS_IsSrcdocChannel(channel); } mTreeBuilder->setIsSrcdocDocument(isSrcdoc); mTokenizer->start(); mExecutor->Start(); if (!aContentType.EqualsLiteral("text/html")) { mTreeBuilder->StartPlainText(); mTokenizer->StartPlainText(); } /* * If you move the following line, be very careful not to cause * WillBuildModel to be called before the document has had its * script global object set. */ mExecutor->WillBuildModel(eDTDMode_unknown); } // Return early if the parser has processed EOF if (mExecutor->IsComplete()) { return NS_OK; } if (aLastCall && aSourceBuffer.IsEmpty() && !aKey) { // document.close() NS_ASSERTION(!GetStreamParser(), "Had stream parser but got document.close()."); if (mDocumentClosed) { // already closed return NS_OK; } mDocumentClosed = true; if (!mBlocked && !mInDocumentWrite) { ParseUntilBlocked(); } return NS_OK; } // If we got this far, we are dealing with a document.write or // document.writeln call--not document.close(). NS_ASSERTION(IsInsertionPointDefined(), "Doc.write reached parser with undefined insertion point."); NS_ASSERTION(!(GetStreamParser() && !aKey), "Got a null key in a non-script-created parser"); // XXX is this optimization bogus? if (aSourceBuffer.IsEmpty()) { return NS_OK; } // This guard is here to prevent document.close from tokenizing synchronously // while a document.write (that wrote the script that called document.close!) // is still on the call stack. mozilla::AutoRestore<bool> guard(mInDocumentWrite); mInDocumentWrite = true; // The script is identified by aKey. If there's nothing in the buffer // chain for that key, we'll insert at the head of the queue. // When the script leaves something in the queue, a zero-length // key-holder "buffer" is inserted in the queue. If the same script // leaves something in the chain again, it will be inserted immediately // before the old key holder belonging to the same script. // // We don't do the actual data insertion yet in the hope that the data gets // tokenized and there no data or less data to copy to the heap after // tokenization. Also, this way, we avoid inserting one empty data buffer // per document.write, which matters for performance when the parser isn't // blocked and a badly-authored script calls document.write() once per // input character. (As seen in a benchmark!) // // The insertion into the input stream happens conceptually before anything // gets tokenized. To make sure multi-level document.write works right, // it's necessary to establish the location of our parser key up front // in case this is the first write with this key. // // In a document.open() case, the first write level has a null key, so that // case is handled separately, because normal buffers containing data // have null keys. // These don't need to be owning references, because they always point to // the buffer queue and buffers can't be removed from the buffer queue // before document.write() returns. The buffer queue clean-up happens the // next time ParseUntilBlocked() is called. // However, they are made owning just in case the reasoning above is flawed // and a flaw would lead to worse problems with plain pointers. If this // turns out to be a perf problem, it's worthwhile to consider making // prevSearchbuf a plain pointer again. nsRefPtr<nsHtml5OwningUTF16Buffer> prevSearchBuf; nsRefPtr<nsHtml5OwningUTF16Buffer> firstLevelMarker; if (aKey) { if (mFirstBuffer == mLastBuffer) { nsHtml5OwningUTF16Buffer* keyHolder = new nsHtml5OwningUTF16Buffer(aKey); keyHolder->next = mLastBuffer; mFirstBuffer = keyHolder; } else if (mFirstBuffer->key != aKey) { prevSearchBuf = mFirstBuffer; for (;;) { if (prevSearchBuf->next == mLastBuffer) { // key was not found nsHtml5OwningUTF16Buffer* keyHolder = new nsHtml5OwningUTF16Buffer(aKey); keyHolder->next = mFirstBuffer; mFirstBuffer = keyHolder; prevSearchBuf = nullptr; break; } if (prevSearchBuf->next->key == aKey) { // found a key holder break; } prevSearchBuf = prevSearchBuf->next; } } // else mFirstBuffer is the keyholder // prevSearchBuf is the previous buffer before the keyholder or null if // there isn't one. } else { // We have a first-level write in the document.open() case. We insert before // mLastBuffer, effectively, by making mLastBuffer be a new sentinel object // and redesignating the previous mLastBuffer as our firstLevelMarker. We // need to put a marker there, because otherwise additional document.writes // from nested event loops would insert in the wrong place. Sigh. mLastBuffer->next = new nsHtml5OwningUTF16Buffer((void*)nullptr); firstLevelMarker = mLastBuffer; mLastBuffer = mLastBuffer->next; } nsHtml5DependentUTF16Buffer stackBuffer(aSourceBuffer); while (!mBlocked && stackBuffer.hasMore()) { stackBuffer.adjust(mLastWasCR); mLastWasCR = false; if (stackBuffer.hasMore()) { int32_t lineNumberSave; bool inRootContext = (!GetStreamParser() && !aKey); if (inRootContext) { mTokenizer->setLineNumber(mRootContextLineNumber); } else { // we aren't the root context, so save the line number on the // *stack* so that we can restore it. lineNumberSave = mTokenizer->getLineNumber(); } mLastWasCR = mTokenizer->tokenizeBuffer(&stackBuffer); if (inRootContext) { mRootContextLineNumber = mTokenizer->getLineNumber(); } else { mTokenizer->setLineNumber(lineNumberSave); } if (mTreeBuilder->HasScript()) { mTreeBuilder->Flush(); // Move ops to the executor mExecutor->FlushDocumentWrite(); // run the ops // Flushing tree ops can cause all sorts of things. // Return early if the parser got terminated. if (mExecutor->IsComplete()) { return NS_OK; } } // Ignore suspension requests } } nsRefPtr<nsHtml5OwningUTF16Buffer> heapBuffer; if (stackBuffer.hasMore()) { // The buffer wasn't tokenized to completion. Create a copy of the tail // on the heap. heapBuffer = stackBuffer.FalliblyCopyAsOwningBuffer(); if (!heapBuffer) { // Allocation failed. The parser is now broken. return mExecutor->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY); } } if (heapBuffer) { // We have something to insert before the keyholder holding in the non-null // aKey case and we have something to swap into firstLevelMarker in the // null aKey case. if (aKey) { NS_ASSERTION(mFirstBuffer != mLastBuffer, "Where's the keyholder?"); // the key holder is still somewhere further down the list from // prevSearchBuf (which may be null) if (mFirstBuffer->key == aKey) { NS_ASSERTION(!prevSearchBuf, "Non-null prevSearchBuf when mFirstBuffer is the key holder?"); heapBuffer->next = mFirstBuffer; mFirstBuffer = heapBuffer; } else { if (!prevSearchBuf) { prevSearchBuf = mFirstBuffer; } // We created a key holder earlier, so we will find it without walking // past the end of the list. while (prevSearchBuf->next->key != aKey) { prevSearchBuf = prevSearchBuf->next; } heapBuffer->next = prevSearchBuf->next; prevSearchBuf->next = heapBuffer; } } else { NS_ASSERTION(firstLevelMarker, "How come we don't have a marker."); firstLevelMarker->Swap(heapBuffer); } } if (!mBlocked) { // buffer was tokenized to completion NS_ASSERTION(!stackBuffer.hasMore(), "Buffer wasn't tokenized to completion?"); // Scripting semantics require a forced tree builder flush here mTreeBuilder->Flush(); // Move ops to the executor mExecutor->FlushDocumentWrite(); // run the ops } else if (stackBuffer.hasMore()) { // The buffer wasn't tokenized to completion. Tokenize the untokenized // content in order to preload stuff. This content will be retokenized // later for normal parsing. if (!mDocWriteSpeculatorActive) { mDocWriteSpeculatorActive = true; if (!mDocWriteSpeculativeTreeBuilder) { // Lazily initialize if uninitialized mDocWriteSpeculativeTreeBuilder = new nsHtml5TreeBuilder(nullptr, mExecutor->GetStage()); mDocWriteSpeculativeTreeBuilder->setScriptingEnabled( mTreeBuilder->isScriptingEnabled()); mDocWriteSpeculativeTokenizer = new nsHtml5Tokenizer(mDocWriteSpeculativeTreeBuilder, false); mDocWriteSpeculativeTokenizer->setInterner(&mAtomTable); mDocWriteSpeculativeTokenizer->start(); } mDocWriteSpeculativeTokenizer->resetToDataState(); mDocWriteSpeculativeTreeBuilder->loadState(mTreeBuilder, &mAtomTable); mDocWriteSpeculativeLastWasCR = false; } // Note that with multilevel document.write if we didn't just activate the // speculator, it's possible that the speculator is now in the wrong state. // That's OK for the sake of simplicity. The worst that can happen is // that the speculative loads aren't exactly right. The content will be // reparsed anyway for non-preload purposes. // The buffer position for subsequent non-speculative parsing now lives // in heapBuffer, so it's ok to let the buffer position of stackBuffer // to be overwritten and not restored below. while (stackBuffer.hasMore()) { stackBuffer.adjust(mDocWriteSpeculativeLastWasCR); if (stackBuffer.hasMore()) { mDocWriteSpeculativeLastWasCR = mDocWriteSpeculativeTokenizer->tokenizeBuffer(&stackBuffer); } } mDocWriteSpeculativeTreeBuilder->Flush(); mDocWriteSpeculativeTreeBuilder->DropHandles(); mExecutor->FlushSpeculativeLoads(); } return NS_OK; }
void ToUpperCase(nsAString& aString) { PRUnichar *buf = aString.BeginWriting(); ToUpperCase(buf, buf, aString.Length()); }
void HTMLTextAreaElement::SetRangeText(const nsAString& aReplacement, uint32_t aStart, uint32_t aEnd, const SelectionMode& aSelectMode, ErrorResult& aRv, int32_t aSelectionStart, int32_t aSelectionEnd) { if (aStart > aEnd) { aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); return; } nsAutoString value; GetValueInternal(value, false); uint32_t inputValueLength = value.Length(); if (aStart > inputValueLength) { aStart = inputValueLength; } if (aEnd > inputValueLength) { aEnd = inputValueLength; } if (aSelectionStart == -1 && aSelectionEnd == -1) { aRv = GetSelectionRange(&aSelectionStart, &aSelectionEnd); if (aRv.Failed()) { if (mState.IsSelectionCached()) { aSelectionStart = mState.GetSelectionProperties().GetStart(); aSelectionEnd = mState.GetSelectionProperties().GetEnd(); aRv = NS_OK; } } } if (aStart <= aEnd) { value.Replace(aStart, aEnd - aStart, aReplacement); nsresult rv = SetValueInternal(value, nsTextEditorState::eSetValue_ByContent); if (NS_FAILED(rv)) { aRv.Throw(rv); return; } } uint32_t newEnd = aStart + aReplacement.Length(); int32_t delta = aReplacement.Length() - (aEnd - aStart); switch (aSelectMode) { case mozilla::dom::SelectionMode::Select: { aSelectionStart = aStart; aSelectionEnd = newEnd; } break; case mozilla::dom::SelectionMode::Start: { aSelectionStart = aSelectionEnd = aStart; } break; case mozilla::dom::SelectionMode::End: { aSelectionStart = aSelectionEnd = newEnd; } break; case mozilla::dom::SelectionMode::Preserve: { if ((uint32_t)aSelectionStart > aEnd) { aSelectionStart += delta; } else if ((uint32_t)aSelectionStart > aStart) { aSelectionStart = aStart; } if ((uint32_t)aSelectionEnd > aEnd) { aSelectionEnd += delta; } else if ((uint32_t)aSelectionEnd > aStart) { aSelectionEnd = newEnd; } } break; default: MOZ_CRASH("Unknown mode!"); } Optional<nsAString> direction; SetSelectionRange(aSelectionStart, aSelectionEnd, direction, aRv); }
nsresult nsHTMLCanvasElement::ToDataURLImpl(const nsAString& aMimeType, nsIVariant* aEncoderOptions, nsAString& aDataURL) { bool fallbackToPNG = false; nsIntSize size = GetWidthHeight(); if (size.height == 0 || size.width == 0) { aDataURL = NS_LITERAL_STRING("data:,"); return NS_OK; } nsAutoString type; nsContentUtils::ASCIIToLower(aMimeType, type); nsAutoString params; // Quality parameter is only valid for the image/jpeg MIME type if (type.EqualsLiteral("image/jpeg")) { PRUint16 vartype; if (aEncoderOptions && NS_SUCCEEDED(aEncoderOptions->GetDataType(&vartype)) && vartype <= nsIDataType::VTYPE_DOUBLE) { double quality; // Quality must be between 0.0 and 1.0, inclusive if (NS_SUCCEEDED(aEncoderOptions->GetAsDouble(&quality)) && quality >= 0.0 && quality <= 1.0) { params.AppendLiteral("quality="); params.AppendInt(NS_lround(quality * 100.0)); } } } // If we haven't parsed the params check for proprietary options. // The proprietary option -moz-parse-options will take a image lib encoder // parse options string as is and pass it to the encoder. bool usingCustomParseOptions = false; if (params.Length() == 0) { NS_NAMED_LITERAL_STRING(mozParseOptions, "-moz-parse-options:"); nsAutoString paramString; if (NS_SUCCEEDED(aEncoderOptions->GetAsAString(paramString)) && StringBeginsWith(paramString, mozParseOptions)) { nsDependentSubstring parseOptions = Substring(paramString, mozParseOptions.Length(), paramString.Length() - mozParseOptions.Length()); params.Append(parseOptions); usingCustomParseOptions = true; } } nsCOMPtr<nsIInputStream> stream; nsresult rv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG); // If there are unrecognized custom parse options, we should fall back to // the default values for the encoder without any options at all. if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) { fallbackToPNG = false; rv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG); } NS_ENSURE_SUCCESS(rv, rv); // build data URL string if (fallbackToPNG) aDataURL = NS_LITERAL_STRING("data:image/png;base64,"); else aDataURL = NS_LITERAL_STRING("data:") + type + NS_LITERAL_STRING(";base64,"); PRUint32 count; rv = stream->Available(&count); NS_ENSURE_SUCCESS(rv, rv); return Base64EncodeInputStream(stream, aDataURL, count, aDataURL.Length()); }
// Parses the encoder options and sets the bits per pixel to use and PNG or BMP // See InitFromData for a description of the parse options nsresult nsICOEncoder::ParseOptions(const nsAString& aOptions, uint32_t* bpp, bool *usePNG) { // If no parsing options just use the default of 24BPP and PNG yes if (aOptions.Length() == 0) { if (usePNG) { *usePNG = true; } if (bpp) { *bpp = 24; } } // Parse the input string into a set of name/value pairs. // From format: format=<png|bmp>;bpp=<bpp_value> // to format: [0] = format=<png|bmp>, [1] = bpp=<bpp_value> nsTArray<nsCString> nameValuePairs; if (!ParseString(NS_ConvertUTF16toUTF8(aOptions), ';', nameValuePairs)) { return NS_ERROR_INVALID_ARG; } // For each name/value pair in the set for (int i = 0; i < nameValuePairs.Length(); ++i) { // Split the name value pair [0] = name, [1] = value nsTArray<nsCString> nameValuePair; if (!ParseString(nameValuePairs[i], '=', nameValuePair)) { return NS_ERROR_INVALID_ARG; } if (nameValuePair.Length() != 2) { return NS_ERROR_INVALID_ARG; } // Parse the format portion of the string format=<png|bmp>;bpp=<bpp_value> if (nameValuePair[0].Equals("format", nsCaseInsensitiveCStringComparator())) { if (nameValuePair[1].Equals("png", nsCaseInsensitiveCStringComparator())) { *usePNG = true; } else if (nameValuePair[1].Equals("bmp", nsCaseInsensitiveCStringComparator())) { *usePNG = false; } else { return NS_ERROR_INVALID_ARG; } } // Parse the bpp portion of the string format=<png|bmp>;bpp=<bpp_value> if (nameValuePair[0].Equals("bpp", nsCaseInsensitiveCStringComparator())) { if (nameValuePair[1].Equals("24")) { *bpp = 24; } else if (nameValuePair[1].Equals("32")) { *bpp = 32; } else { return NS_ERROR_INVALID_ARG; } } } return NS_OK; }
nsresult BluetoothHfpManager::HandleVolumeChanged(const nsAString& aData) { MOZ_ASSERT(NS_IsMainThread()); // The string that we're interested in will be a JSON string that looks like: // {"key":"volumeup", "value":1.0} // {"key":"volumedown", "value":0.2} JSContext* cx = nsContentUtils::GetSafeJSContext(); if (!cx) { return NS_OK; } JS::Value val; if (!JS_ParseJSON(cx, aData.BeginReading(), aData.Length(), &val)) { return JS_ReportPendingException(cx) ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } if (!val.isObject()) { return NS_OK; } JSObject& obj(val.toObject()); JS::Value key; if (!JS_GetProperty(cx, &obj, "key", &key)) { MOZ_ASSERT(!JS_IsExceptionPending(cx)); return NS_ERROR_OUT_OF_MEMORY; } if (!key.isString()) { return NS_OK; } JSBool match; if (!JS_StringEqualsAscii(cx, key.toString(), AUDIO_VOLUME_MASTER, &match)) { MOZ_ASSERT(!JS_IsExceptionPending(cx)); return NS_ERROR_OUT_OF_MEMORY; } if (!match) { return NS_OK; } JS::Value value; if (!JS_GetProperty(cx, &obj, "value", &value)) { MOZ_ASSERT(!JS_IsExceptionPending(cx)); return NS_ERROR_OUT_OF_MEMORY; } if (!value.isNumber()) { return NS_ERROR_UNEXPECTED; } // AG volume range: [0.0, 1.0] float volume = value.toNumber(); // HS volume range: [0, 15] mCurrentVgs = ceil(volume * 15); nsDiscriminatedUnion du; du.mType = 0; du.u.mInt8Value = mCurrentVgs; nsCString vgs; if (NS_FAILED(nsVariant::ConvertToACString(du, vgs))) { NS_WARNING("Failed to convert volume to string"); return NS_ERROR_FAILURE; } nsAutoCString newVgs; newVgs += "+VGS: "; newVgs += vgs; SendLine(newVgs.get()); return NS_OK; }
NS_IMETHODIMP nsTypeAheadFind::Find(const nsAString& aSearchString, bool aLinksOnly, uint16_t* aResult) { *aResult = FIND_NOTFOUND; nsCOMPtr<nsIPresShell> presShell (GetPresShell()); if (!presShell) { nsCOMPtr<nsIDocShell> ds (do_QueryReferent(mDocShell)); NS_ENSURE_TRUE(ds, NS_ERROR_FAILURE); presShell = ds->GetPresShell(); NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); mPresShell = do_GetWeakReference(presShell); } nsCOMPtr<nsISelection> selection; nsCOMPtr<nsISelectionController> selectionController = do_QueryReferent(mSelectionController); if (!selectionController) { GetSelection(presShell, getter_AddRefs(selectionController), getter_AddRefs(selection)); // cache for reuse mSelectionController = do_GetWeakReference(selectionController); } else { selectionController->GetSelection( nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection)); } if (selection) selection->CollapseToStart(); if (aSearchString.IsEmpty()) { mTypeAheadBuffer.Truncate(); // These will be initialized to their true values after the first character // is typed mStartFindRange = nullptr; mSelectionController = nullptr; *aResult = FIND_FOUND; return NS_OK; } bool atEnd = false; if (mTypeAheadBuffer.Length()) { const nsAString& oldStr = Substring(mTypeAheadBuffer, 0, mTypeAheadBuffer.Length()); const nsAString& newStr = Substring(aSearchString, 0, mTypeAheadBuffer.Length()); if (oldStr.Equals(newStr)) atEnd = true; const nsAString& newStr2 = Substring(aSearchString, 0, aSearchString.Length()); const nsAString& oldStr2 = Substring(mTypeAheadBuffer, 0, aSearchString.Length()); if (oldStr2.Equals(newStr2)) atEnd = true; if (!atEnd) mStartFindRange = nullptr; } if (!mIsSoundInitialized && !mNotFoundSoundURL.IsEmpty()) { // This makes sure system sound library is loaded so that // there's no lag before the first sound is played // by waiting for the first keystroke, we still get the startup time benefits. mIsSoundInitialized = true; mSoundInterface = do_CreateInstance("@mozilla.org/sound;1"); if (mSoundInterface && !mNotFoundSoundURL.EqualsLiteral("beep")) { mSoundInterface->Init(); } } #ifdef XP_WIN // After each keystroke, ensure sound object is destroyed, to free up memory // allocated for error sound, otherwise Windows' nsISound impl // holds onto the last played sound, using up memory. mSoundInterface = nullptr; #endif int32_t bufferLength = mTypeAheadBuffer.Length(); mTypeAheadBuffer = aSearchString; bool isFirstVisiblePreferred = false; // --------- Initialize find if 1st char ---------- if (bufferLength == 0) { // If you can see the selection (not collapsed or thru caret browsing), // or if already focused on a page element, start there. // Otherwise we're going to start at the first visible element bool isSelectionCollapsed = true; if (selection) selection->GetIsCollapsed(&isSelectionCollapsed); // If true, we will scan from top left of visible area // If false, we will scan from start of selection isFirstVisiblePreferred = !atEnd && !mCaretBrowsingOn && isSelectionCollapsed; if (isFirstVisiblePreferred) { // Get the focused content. If there is a focused node, ensure the // selection is at that point. Otherwise, we will just want to start // from the caret position or the beginning of the document. nsPresContext* presContext = presShell->GetPresContext(); NS_ENSURE_TRUE(presContext, NS_OK); nsCOMPtr<nsIDocument> document = do_QueryInterface(presShell->GetDocument()); if (!document) return NS_ERROR_UNEXPECTED; nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID); if (fm) { nsPIDOMWindowOuter* window = document->GetWindow(); nsCOMPtr<nsIDOMElement> focusedElement; nsCOMPtr<mozIDOMWindowProxy> focusedWindow; fm->GetFocusedElementForWindow(window, false, getter_AddRefs(focusedWindow), getter_AddRefs(focusedElement)); // If the root element is focused, then it's actually the document // that has the focus, so ignore this. if (focusedElement && !SameCOMIdentity(focusedElement, document->GetRootElement())) { fm->MoveCaretToFocus(window); isFirstVisiblePreferred = false; } } } } // ----------- Find the text! --------------------- // Beware! This may flush notifications via synchronous // ScrollSelectionIntoView. nsresult rv = FindItNow(nullptr, aLinksOnly, isFirstVisiblePreferred, false, aResult); // ---------Handle success or failure --------------- if (NS_SUCCEEDED(rv)) { if (mTypeAheadBuffer.Length() == 1) { // If first letter, store where the first find succeeded // (mStartFindRange) mStartFindRange = nullptr; if (selection) { nsCOMPtr<nsIDOMRange> startFindRange; selection->GetRangeAt(0, getter_AddRefs(startFindRange)); if (startFindRange) startFindRange->CloneRange(getter_AddRefs(mStartFindRange)); } } } else { // Error sound if (mTypeAheadBuffer.Length() > mLastFindLength) PlayNotFoundSound(); } SaveFind(); return NS_OK; }
NS_IMETHODIMP nsFaviconService::ReplaceFaviconDataFromDataURL(nsIURI* aFaviconURI, const nsAString& aDataURL, PRTime aExpiration, nsIPrincipal* aLoadingPrincipal) { NS_ENSURE_ARG(aFaviconURI); NS_ENSURE_TRUE(aDataURL.Length() > 0, NS_ERROR_INVALID_ARG); if (aExpiration == 0) { aExpiration = PR_Now() + MAX_FAVICON_EXPIRATION; } nsCOMPtr<nsIURI> dataURI; nsresult rv = NS_NewURI(getter_AddRefs(dataURI), aDataURL); NS_ENSURE_SUCCESS(rv, rv); // Use the data: protocol handler to convert the data. nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIProtocolHandler> protocolHandler; rv = ioService->GetProtocolHandler("data", getter_AddRefs(protocolHandler)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIPrincipal> loadingPrincipal = aLoadingPrincipal; MOZ_ASSERT(loadingPrincipal, "please provide aLoadingPrincipal for this favicon"); if (!loadingPrincipal) { // Bug 1227289 : Let's default to the systemPrincipal if no loadingPrincipal is provided // so addons not providing a loadingPrincipal do not break in release builds. const char16_t* params[] = { MOZ_UTF16("nsFaviconService::ReplaceFaviconDataFromDataURL()"), MOZ_UTF16("nsFaviconService::ReplaceFaviconDataFromDataURL(..., [optional aLoadingPrincipal])") }; nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Security by Default"), nullptr, // aDocument nsContentUtils::eNECKO_PROPERTIES, "APIDeprecationWarning", params, ArrayLength(params)); loadingPrincipal = nsContentUtils::GetSystemPrincipal(); } NS_ENSURE_TRUE(loadingPrincipal, NS_ERROR_FAILURE); nsCOMPtr<nsILoadInfo> loadInfo = new mozilla::LoadInfo(loadingPrincipal, nullptr, // aTriggeringPrincipal nullptr, // aLoadingNode nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS | nsILoadInfo::SEC_ALLOW_CHROME | nsILoadInfo::SEC_DISALLOW_SCRIPT, nsIContentPolicy::TYPE_INTERNAL_IMAGE); nsCOMPtr<nsIChannel> channel; rv = protocolHandler->NewChannel2(dataURI, loadInfo, getter_AddRefs(channel)); NS_ENSURE_SUCCESS(rv, rv); // Blocking stream is OK for data URIs. nsCOMPtr<nsIInputStream> stream; rv = channel->Open2(getter_AddRefs(stream)); NS_ENSURE_SUCCESS(rv, rv); uint64_t available64; rv = stream->Available(&available64); NS_ENSURE_SUCCESS(rv, rv); if (available64 == 0 || available64 > UINT32_MAX / sizeof(uint8_t)) return NS_ERROR_FILE_TOO_BIG; uint32_t available = (uint32_t)available64; // Read all the decoded data. uint8_t* buffer = static_cast<uint8_t*> (moz_xmalloc(sizeof(uint8_t) * available)); if (!buffer) return NS_ERROR_OUT_OF_MEMORY; uint32_t numRead; rv = stream->Read(TO_CHARBUFFER(buffer), available, &numRead); if (NS_FAILED(rv) || numRead != available) { free(buffer); return rv; } nsAutoCString mimeType; rv = channel->GetContentType(mimeType); if (NS_FAILED(rv)) { free(buffer); return rv; } // ReplaceFaviconData can now do the dirty work. rv = ReplaceFaviconData(aFaviconURI, buffer, available, mimeType, aExpiration); free(buffer); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
void nsHTMLContentSerializer::AppendAndTranslateEntities(const nsAString& aStr, nsAString& aOutputStr) { if (mBodyOnly && !mInBody) { return; } if (mDisableEntityEncoding) { aOutputStr.Append(aStr); return; } bool nonBasicEntities = !!(mFlags & (nsIDocumentEncoder::OutputEncodeLatin1Entities | nsIDocumentEncoder::OutputEncodeHTMLEntities | nsIDocumentEncoder::OutputEncodeW3CEntities)); if (!nonBasicEntities && (mFlags & (nsIDocumentEncoder::OutputEncodeBasicEntities))) { const char **entityTable = mInAttribute ? kAttrEntities : kEntities; PRUint32 start = 0; const PRUint32 len = aStr.Length(); for (PRUint32 i = 0; i < len; ++i) { const char* entity = nsnull; i = FindNextBasicEntity(aStr, len, i, entityTable, &entity); PRUint32 normalTextLen = i - start; if (normalTextLen) { aOutputStr.Append(Substring(aStr, start, normalTextLen)); } if (entity) { aOutputStr.AppendASCII(entity); start = i + 1; } } return; } else if (nonBasicEntities) { nsIParserService* parserService = nsContentUtils::GetParserService(); if (!parserService) { NS_ERROR("Can't get parser service"); return; } nsReadingIterator<PRUnichar> done_reading; aStr.EndReading(done_reading); // for each chunk of |aString|... PRUint32 advanceLength = 0; nsReadingIterator<PRUnichar> iter; const char **entityTable = mInAttribute ? kAttrEntities : kEntities; nsCAutoString entityReplacement; for (aStr.BeginReading(iter); iter != done_reading; iter.advance(PRInt32(advanceLength))) { PRUint32 fragmentLength = iter.size_forward(); PRUint32 lengthReplaced = 0; // the number of UTF-16 codepoints // replaced by a particular entity const PRUnichar* c = iter.get(); const PRUnichar* fragmentStart = c; const PRUnichar* fragmentEnd = c + fragmentLength; const char* entityText = nsnull; const char* fullConstEntityText = nsnull; char* fullEntityText = nsnull; advanceLength = 0; // for each character in this chunk, check if it // needs to be replaced for (; c < fragmentEnd; c++, advanceLength++) { PRUnichar val = *c; if (val <= kValNBSP && entityTable[val]) { fullConstEntityText = entityTable[val]; break; } else if (val > 127 && ((val < 256 && mFlags & nsIDocumentEncoder::OutputEncodeLatin1Entities) || mFlags & nsIDocumentEncoder::OutputEncodeHTMLEntities)) { entityReplacement.Truncate(); parserService->HTMLConvertUnicodeToEntity(val, entityReplacement); if (!entityReplacement.IsEmpty()) { entityText = entityReplacement.get(); break; } } else if (val > 127 && mFlags & nsIDocumentEncoder::OutputEncodeW3CEntities && mEntityConverter) { if (NS_IS_HIGH_SURROGATE(val) && c + 1 < fragmentEnd && NS_IS_LOW_SURROGATE(*(c + 1))) { PRUint32 valUTF32 = SURROGATE_TO_UCS4(val, *(++c)); if (NS_SUCCEEDED(mEntityConverter->ConvertUTF32ToEntity(valUTF32, nsIEntityConverter::entityW3C, &fullEntityText))) { lengthReplaced = 2; break; } else { advanceLength++; } } else if (NS_SUCCEEDED(mEntityConverter->ConvertToEntity(val, nsIEntityConverter::entityW3C, &fullEntityText))) { lengthReplaced = 1; break; } } } aOutputStr.Append(fragmentStart, advanceLength); if (entityText) { aOutputStr.Append(PRUnichar('&')); AppendASCIItoUTF16(entityText, aOutputStr); aOutputStr.Append(PRUnichar(';')); advanceLength++; } else if (fullConstEntityText) { aOutputStr.AppendASCII(fullConstEntityText); ++advanceLength; } // if it comes from nsIEntityConverter, it already has '&' and ';' else if (fullEntityText) { AppendASCIItoUTF16(fullEntityText, aOutputStr); nsMemory::Free(fullEntityText); advanceLength += lengthReplaced; } } } else { nsXMLContentSerializer::AppendAndTranslateEntities(aStr, aOutputStr); } }
NS_IMETHODIMP mozSpellChecker::Replace(const nsAString &aOldWord, const nsAString &aNewWord, bool aAllOccurrences) { if(!mConverter) return NS_ERROR_NULL_POINTER; nsAutoString newWord(aNewWord); // sigh if(aAllOccurrences){ int32_t selOffset; int32_t startBlock,currentBlock,currOffset; int32_t begin,end; bool done; nsresult result; nsAutoString str; // find out where we are result = SetupDoc(&selOffset); if(NS_FAILED(result)) return result; result = GetCurrentBlockIndex(mTextServicesDocument,&startBlock); if(NS_FAILED(result)) return result; //start at the beginning result = mTextServicesDocument->FirstBlock(); currOffset=0; currentBlock = 0; while (NS_SUCCEEDED(mTextServicesDocument->IsDone(&done)) && !done) { result = mTextServicesDocument->GetCurrentTextBlock(&str); do { result = mConverter->FindNextWord(str.get(),str.Length(),currOffset,&begin,&end); if (NS_SUCCEEDED(result) && (begin != -1)) { if (aOldWord.Equals(Substring(str, begin, end-begin))) { // if we are before the current selection point but in the same // block move the selection point forwards if (currentBlock == startBlock && begin < selOffset) { selOffset += int32_t(aNewWord.Length()) - int32_t(aOldWord.Length()); if (selOffset < begin) { selOffset=begin; } } mTextServicesDocument->SetSelection(begin, end-begin); mTextServicesDocument->InsertText(&newWord); mTextServicesDocument->GetCurrentTextBlock(&str); end += (aNewWord.Length() - aOldWord.Length()); // recursion was cute in GEB, not here. } } currOffset = end; } while(currOffset != -1); mTextServicesDocument->NextBlock(); currentBlock++; currOffset=0; } // We are done replacing. Put the selection point back where we found it (or equivalent); result = mTextServicesDocument->FirstBlock(); currentBlock = 0; while(NS_SUCCEEDED(mTextServicesDocument->IsDone(&done)) && !done && currentBlock < startBlock) { mTextServicesDocument->NextBlock(); } //After we have moved to the block where the first occurrence of replace was done, put the //selection to the next word following it. In case there is no word following it i.e if it happens //to be the last word in that block, then move to the next block and put the selection to the //first word in that block, otherwise when the Setupdoc() is called, it queries the LastSelectedBlock() //and the selection offset of the last occurrence of the replaced word is taken instead of the first //occurrence and things get messed up as reported in the bug 244969 if (NS_SUCCEEDED(mTextServicesDocument->IsDone(&done)) && !done){ nsString str; result = mTextServicesDocument->GetCurrentTextBlock(&str); result = mConverter->FindNextWord(str.get(),str.Length(),selOffset,&begin,&end); if (end == -1) { mTextServicesDocument->NextBlock(); selOffset=0; result = mTextServicesDocument->GetCurrentTextBlock(&str); result = mConverter->FindNextWord(str.get(),str.Length(),selOffset,&begin,&end); mTextServicesDocument->SetSelection(begin, 0); } else { mTextServicesDocument->SetSelection(begin, 0); } } } else { mTextServicesDocument->InsertText(&newWord); } return NS_OK; }
NS_IMETHODIMP nsFaviconService::ReplaceFaviconDataFromDataURL(nsIURI* aFaviconURI, const nsAString& aDataURL, PRTime aExpiration) { NS_ENSURE_ARG(aFaviconURI); NS_ENSURE_TRUE(aDataURL.Length() > 0, NS_ERROR_INVALID_ARG); if (aExpiration == 0) { aExpiration = PR_Now() + MAX_FAVICON_EXPIRATION; } nsCOMPtr<nsIURI> dataURI; nsresult rv = NS_NewURI(getter_AddRefs(dataURI), aDataURL); NS_ENSURE_SUCCESS(rv, rv); // Use the data: protocol handler to convert the data. nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIProtocolHandler> protocolHandler; rv = ioService->GetProtocolHandler("data", getter_AddRefs(protocolHandler)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsILoadInfo> loadInfo = new mozilla::LoadInfo(nsContentUtils::GetSystemPrincipal(), nullptr, // aTriggeringPrincipal nullptr, // aLoadingNode nsILoadInfo::SEC_NORMAL, nsIContentPolicy::TYPE_IMAGE); nsCOMPtr<nsIChannel> channel; rv = protocolHandler->NewChannel2(dataURI, loadInfo, getter_AddRefs(channel)); NS_ENSURE_SUCCESS(rv, rv); // Blocking stream is OK for data URIs. nsCOMPtr<nsIInputStream> stream; rv = channel->Open(getter_AddRefs(stream)); NS_ENSURE_SUCCESS(rv, rv); uint64_t available64; rv = stream->Available(&available64); NS_ENSURE_SUCCESS(rv, rv); if (available64 == 0 || available64 > UINT32_MAX / sizeof(uint8_t)) return NS_ERROR_FILE_TOO_BIG; uint32_t available = (uint32_t)available64; // Read all the decoded data. uint8_t* buffer = static_cast<uint8_t*> (moz_xmalloc(sizeof(uint8_t) * available)); if (!buffer) return NS_ERROR_OUT_OF_MEMORY; uint32_t numRead; rv = stream->Read(TO_CHARBUFFER(buffer), available, &numRead); if (NS_FAILED(rv) || numRead != available) { free(buffer); return rv; } nsAutoCString mimeType; rv = channel->GetContentType(mimeType); if (NS_FAILED(rv)) { free(buffer); return rv; } // ReplaceFaviconData can now do the dirty work. rv = ReplaceFaviconData(aFaviconURI, buffer, available, mimeType, aExpiration); free(buffer); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
/* static */ void SVGPathSegUtils::GetValueAsString(const float* aSeg, nsAString& aValue) { // Adding new seg type? Is the formatting below acceptable for the new types? PR_STATIC_ASSERT(NS_SVG_PATH_SEG_LAST_VALID_TYPE == nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL); PR_STATIC_ASSERT(NS_SVG_PATH_SEG_MAX_ARGS == 7); PRUint32 type = DecodeType(aSeg[0]); PRUnichar typeAsChar = GetPathSegTypeAsLetter(type); // Special case arcs: if (IsArcType(type)) { bool largeArcFlag = aSeg[4] != 0.0f; bool sweepFlag = aSeg[5] != 0.0f; nsTextFormatter::ssprintf(aValue, NS_LITERAL_STRING("%c%g,%g %g %d,%d %g,%g").get(), typeAsChar, aSeg[1], aSeg[2], aSeg[3], largeArcFlag, sweepFlag, aSeg[6], aSeg[7]); } else { switch (ArgCountForType(type)) { case 0: aValue = typeAsChar; break; case 1: nsTextFormatter::ssprintf(aValue, NS_LITERAL_STRING("%c%g").get(), typeAsChar, aSeg[1]); break; case 2: nsTextFormatter::ssprintf(aValue, NS_LITERAL_STRING("%c%g,%g").get(), typeAsChar, aSeg[1], aSeg[2]); break; case 4: nsTextFormatter::ssprintf(aValue, NS_LITERAL_STRING("%c%g,%g %g,%g").get(), typeAsChar, aSeg[1], aSeg[2], aSeg[3], aSeg[4]); break; case 6: nsTextFormatter::ssprintf(aValue, NS_LITERAL_STRING("%c%g,%g %g,%g %g,%g").get(), typeAsChar, aSeg[1], aSeg[2], aSeg[3], aSeg[4], aSeg[5], aSeg[6]); break; default: NS_ABORT_IF_FALSE(false, "Unknown segment type"); aValue = NS_LITERAL_STRING("<unknown-segment-type>").get(); return; } } // nsTextFormatter::ssprintf is one of the nsTextFormatter methods that // randomly appends '\0' to its output string, which means that the length // of the output string is one too long. We need to manually remove that '\0' // until nsTextFormatter is fixed. // if (aValue[aValue.Length() - 1] == PRUnichar('\0')) { aValue.SetLength(aValue.Length() - 1); } }
/* static */ nsresult SRICheck::IntegrityMetadata(const nsAString& aMetadataList, const nsIDocument* aDocument, SRIMetadata* outMetadata) { NS_ENSURE_ARG_POINTER(outMetadata); NS_ENSURE_ARG_POINTER(aDocument); MOZ_ASSERT(outMetadata->IsEmpty()); // caller must pass empty metadata if (!Preferences::GetBool("security.sri.enable", false)) { SRILOG(("SRICheck::IntegrityMetadata, sri is disabled (pref)")); return NS_ERROR_SRI_DISABLED; } // put a reasonable bound on the length of the metadata NS_ConvertUTF16toUTF8 metadataList(aMetadataList); if (metadataList.Length() > SRICheck::MAX_METADATA_LENGTH) { metadataList.Truncate(SRICheck::MAX_METADATA_LENGTH); } MOZ_ASSERT(metadataList.Length() <= aMetadataList.Length()); // the integrity attribute is a list of whitespace-separated hashes // and options so we need to look at them one by one and pick the // strongest (valid) one nsCWhitespaceTokenizer tokenizer(metadataList); nsAutoCString token; for (uint32_t i=0; tokenizer.hasMoreTokens() && i < SRICheck::MAX_METADATA_TOKENS; ++i) { token = tokenizer.nextToken(); SRIMetadata metadata(token); if (metadata.IsMalformed()) { NS_ConvertUTF8toUTF16 tokenUTF16(token); const char16_t* params[] = { tokenUTF16.get() }; nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Sub-resource Integrity"), aDocument, nsContentUtils::eSECURITY_PROPERTIES, "MalformedIntegrityHash", params, ArrayLength(params)); } else if (!metadata.IsAlgorithmSupported()) { nsAutoCString alg; metadata.GetAlgorithm(&alg); NS_ConvertUTF8toUTF16 algUTF16(alg); const char16_t* params[] = { algUTF16.get() }; nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Sub-resource Integrity"), aDocument, nsContentUtils::eSECURITY_PROPERTIES, "UnsupportedHashAlg", params, ArrayLength(params)); } nsAutoCString alg1, alg2; if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) { outMetadata->GetAlgorithm(&alg1); metadata.GetAlgorithm(&alg2); } if (*outMetadata == metadata) { SRILOG(("SRICheck::IntegrityMetadata, alg '%s' is the same as '%s'", alg1.get(), alg2.get())); *outMetadata += metadata; // add new hash to strongest metadata } else if (*outMetadata < metadata) { SRILOG(("SRICheck::IntegrityMetadata, alg '%s' is weaker than '%s'", alg1.get(), alg2.get())); *outMetadata = metadata; // replace strongest metadata with current } } if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) { if (outMetadata->IsValid()) { nsAutoCString alg; outMetadata->GetAlgorithm(&alg); SRILOG(("SRICheck::IntegrityMetadata, using a '%s' hash", alg.get())); } else if (outMetadata->IsEmpty()) { SRILOG(("SRICheck::IntegrityMetadata, no metadata")); } else { SRILOG(("SRICheck::IntegrityMetadata, no valid metadata found")); } } return NS_OK; }
explicit StringUnicharInputStream(const nsAString& aString) : mString(aString), mPos(0), mLen(aString.Length()) { }
NS_IMETHODIMP nsRecentBadCertsService::GetRecentBadCert(const nsAString & aHostNameWithPort, nsISSLStatus **aStatus) { NS_ENSURE_ARG_POINTER(aStatus); if (!aHostNameWithPort.Length()) return NS_ERROR_INVALID_ARG; *aStatus = nullptr; nsRefPtr<nsSSLStatus> status = new nsSSLStatus(); if (!status) return NS_ERROR_OUT_OF_MEMORY; SECItem foundDER; foundDER.len = 0; foundDER.data = nullptr; bool isDomainMismatch = false; bool isNotValidAtThisTime = false; bool isUntrusted = false; { ReentrantMonitorAutoEnter lock(monitor); for (size_t i=0; i<const_recently_seen_list_size; ++i) { if (mCerts[i].mHostWithPort.Equals(aHostNameWithPort)) { SECStatus srv = SECITEM_CopyItem(nullptr, &foundDER, &mCerts[i].mDERCert); if (srv != SECSuccess) return NS_ERROR_OUT_OF_MEMORY; isDomainMismatch = mCerts[i].isDomainMismatch; isNotValidAtThisTime = mCerts[i].isNotValidAtThisTime; isUntrusted = mCerts[i].isUntrusted; } } } if (foundDER.len) { CERTCertificate *nssCert; CERTCertDBHandle *certdb = CERT_GetDefaultCertDB(); nssCert = CERT_FindCertByDERCert(certdb, &foundDER); if (!nssCert) nssCert = CERT_NewTempCertificate(certdb, &foundDER, nullptr, // no nickname false, // not perm true); // copy der SECITEM_FreeItem(&foundDER, false); if (!nssCert) return NS_ERROR_FAILURE; status->mServerCert = nsNSSCertificate::Create(nssCert); CERT_DestroyCertificate(nssCert); status->mHaveCertErrorBits = true; status->mIsDomainMismatch = isDomainMismatch; status->mIsNotValidAtThisTime = isNotValidAtThisTime; status->mIsUntrusted = isUntrusted; *aStatus = status; NS_IF_ADDREF(*aStatus); } return NS_OK; }
bool nsTextAddress::GetField(const nsAString &aLine, int32_t index, nsString &field, char16_t delim) { bool result = false; int32_t pos = 0; int32_t maxLen = aLine.Length(); char16_t tab = char16_t('\t'); char16_t doubleQuote = char16_t('"'); field.Truncate(); if (delim == tab) tab = 0; while (index && (pos < maxLen)) { while (((aLine[pos] == char16_t(' ')) || (aLine[pos] == tab)) && (pos < maxLen)) { pos++; } if (pos >= maxLen) break; if (aLine[pos] == doubleQuote) { do { pos++; if (((pos + 1) < maxLen) && (aLine[pos] == doubleQuote) && (aLine[pos + 1] == doubleQuote)) { pos += 2; } } while ((pos < maxLen) && (aLine[pos] != doubleQuote)); if (pos < maxLen) pos++; } if (pos >= maxLen) break; while ((pos < maxLen) && (aLine[pos] != delim)) pos++; if (pos >= maxLen) break; index--; pos++; } if (pos >= maxLen) return result; result = true; while ((pos < maxLen) && ((aLine[pos] == ' ') || (aLine[pos] == tab))) pos++; int32_t fLen = 0; int32_t startPos = pos; bool quoted = false; if (aLine[pos] == '"') { startPos++; fLen = -1; do { pos++; fLen++; if (((pos + 1) < maxLen) && (aLine[pos] == doubleQuote) && (aLine[pos + 1] == doubleQuote)) { quoted = true; pos += 2; fLen += 2; } } while ((pos < maxLen) && (aLine[pos] != doubleQuote)); } else { while ((pos < maxLen) && (aLine[pos] != delim)) { pos++; fLen++; } } if (!fLen) { return result; } field.Append(nsDependentSubstring(aLine, startPos, fLen)); field.Trim(kWhitespace); if (quoted) { int32_t offset = field.Find("\"\""); while (offset != -1) { field.Cut(offset, 1); offset = MsgFind(field, "\"\"", false, offset + 1); } } return result; }
NS_IMETHODIMP nsDOMOfflineResourceList::MozAdd(const nsAString& aURI) { if (IS_CHILD_PROCESS()) return NS_ERROR_NOT_IMPLEMENTED; nsresult rv = Init(); NS_ENSURE_SUCCESS(rv, rv); if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) { return NS_ERROR_DOM_SECURITY_ERR; } nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache(); if (!appCache) { return NS_ERROR_DOM_INVALID_STATE_ERR; } if (aURI.Length() > MAX_URI_LENGTH) return NS_ERROR_DOM_BAD_URI; // this will fail if the URI is not absolute nsCOMPtr<nsIURI> requestedURI; rv = NS_NewURI(getter_AddRefs(requestedURI), aURI); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString scheme; rv = requestedURI->GetScheme(scheme); NS_ENSURE_SUCCESS(rv, rv); bool match; rv = mManifestURI->SchemeIs(scheme.get(), &match); NS_ENSURE_SUCCESS(rv, rv); if (!match) { return NS_ERROR_DOM_SECURITY_ERR; } uint32_t length; rv = GetMozLength(&length); NS_ENSURE_SUCCESS(rv, rv); uint32_t maxEntries = Preferences::GetUint(kMaxEntriesPref, DEFAULT_MAX_ENTRIES); if (length > maxEntries) return NS_ERROR_NOT_AVAILABLE; ClearCachedKeys(); nsCOMPtr<nsIOfflineCacheUpdate> update = do_CreateInstance(NS_OFFLINECACHEUPDATE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString clientID; rv = appCache->GetClientID(clientID); NS_ENSURE_SUCCESS(rv, rv); rv = update->InitPartial(mManifestURI, clientID, mDocumentURI); NS_ENSURE_SUCCESS(rv, rv); rv = update->AddDynamicURI(requestedURI); NS_ENSURE_SUCCESS(rv, rv); rv = update->Schedule(); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
NS_IMETHODIMP nsHtml5Parser::ParseHtml5Fragment(const nsAString& aSourceBuffer, nsIContent* aTargetNode, nsIAtom* aContextLocalName, PRInt32 aContextNamespace, PRBool aQuirks, PRBool aPreventScriptExecution) { nsIDocument* doc = aTargetNode->GetOwnerDoc(); NS_ENSURE_TRUE(doc, NS_ERROR_NOT_AVAILABLE); nsIURI* uri = doc->GetDocumentURI(); NS_ENSURE_TRUE(uri, NS_ERROR_NOT_AVAILABLE); mExecutor->EnableFragmentMode(aPreventScriptExecution); Initialize(doc, uri, nsnull, nsnull); mExecutor->SetParser(this); mExecutor->SetNodeInfoManager(doc->NodeInfoManager()); nsIContent* target = aTargetNode; mTreeBuilder->setFragmentContext(aContextLocalName, aContextNamespace, &target, aQuirks); #ifdef DEBUG if (!aPreventScriptExecution) { nsCOMPtr<nsIDOMDocumentFragment> domFrag = do_QueryInterface(aTargetNode); NS_ASSERTION(domFrag, "If script execution isn't prevented, must parse to DOM fragment."); } #endif NS_PRECONDITION(!mExecutor->HasStarted(), "Tried to start parse without initializing the parser."); mTreeBuilder->setScriptingEnabled(mExecutor->IsScriptEnabled()); mTokenizer->start(); mExecutor->Start(); // Don't call WillBuildModel in fragment case if (!aSourceBuffer.IsEmpty()) { PRBool lastWasCR = PR_FALSE; nsHtml5UTF16Buffer buffer(aSourceBuffer.Length()); memcpy(buffer.getBuffer(), aSourceBuffer.BeginReading(), aSourceBuffer.Length() * sizeof(PRUnichar)); buffer.setEnd(aSourceBuffer.Length()); while (buffer.hasMore()) { buffer.adjust(lastWasCR); lastWasCR = PR_FALSE; if (buffer.hasMore()) { lastWasCR = mTokenizer->tokenizeBuffer(&buffer); if (mTreeBuilder->HasScript()) { // Flush on each script, because the execution prevention code // can handle at most one script per flush. mTreeBuilder->Flush(); // Move ops to the executor mExecutor->FlushDocumentWrite(); // run the ops } } } } mTokenizer->eof(); mTreeBuilder->StreamEnded(); mTreeBuilder->Flush(); mExecutor->FlushDocumentWrite(); mTokenizer->end(); mExecutor->DropParserAndPerfHint(); mExecutor->DropHeldElements(); mTreeBuilder->DropHandles(); mAtomTable.Clear(); return NS_OK; }
RangedPtr<const char16_t> SVGContentUtils::GetEndRangedPtr(const nsAString& aString) { return RangedPtr<const char16_t>(aString.Data() + aString.Length(), aString.Data(), aString.Length()); }
nsresult nsXHTMLContentSerializer::EscapeURI(nsIContent* aContent, const nsAString& aURI, nsAString& aEscapedURI) { // URL escape %xx cannot be used in JS. // No escaping if the scheme is 'javascript'. if (IsJavaScript(aContent, nsGkAtoms::href, kNameSpaceID_None, aURI)) { aEscapedURI = aURI; return NS_OK; } // nsITextToSubURI does charset convert plus uri escape // This is needed to convert to a document charset which is needed to support existing browsers. // But we eventually want to use UTF-8 instead of a document charset, then the code would be much simpler. // See HTML 4.01 spec, "Appendix B.2.1 Non-ASCII characters in URI attribute values" nsCOMPtr<nsITextToSubURI> textToSubURI; nsAutoString uri(aURI); // in order to use FindCharInSet() nsresult rv = NS_OK; if (!mCharset.IsEmpty() && !IsASCII(uri)) { textToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); } PRInt32 start = 0; PRInt32 end; nsAutoString part; nsXPIDLCString escapedURI; aEscapedURI.Truncate(0); // Loop and escape parts by avoiding escaping reserved characters // (and '%', '#', as well as '[' and ']' for IPv6 address literals). while ((end = uri.FindCharInSet("%#;/?:@&=+$,[]", start)) != -1) { part = Substring(aURI, start, (end-start)); if (textToSubURI && !IsASCII(part)) { rv = textToSubURI->ConvertAndEscape(mCharset.get(), part.get(), getter_Copies(escapedURI)); NS_ENSURE_SUCCESS(rv, rv); } else { escapedURI.Adopt(nsEscape(NS_ConvertUTF16toUTF8(part).get(), url_Path)); } AppendASCIItoUTF16(escapedURI, aEscapedURI); // Append a reserved character without escaping. part = Substring(aURI, end, 1); aEscapedURI.Append(part); start = end + 1; } if (start < (PRInt32) aURI.Length()) { // Escape the remaining part. part = Substring(aURI, start, aURI.Length()-start); if (textToSubURI) { rv = textToSubURI->ConvertAndEscape(mCharset.get(), part.get(), getter_Copies(escapedURI)); NS_ENSURE_SUCCESS(rv, rv); } else { escapedURI.Adopt(nsEscape(NS_ConvertUTF16toUTF8(part).get(), url_Path)); } AppendASCIItoUTF16(escapedURI, aEscapedURI); } return rv; }
/* * Converts the value of the given double to a String, and places * The result into the destination String. * @return the given dest string */ void Double::toString(double aValue, nsAString& aDest) { // check for special cases if (isNaN(aValue)) { aDest.AppendLiteral("NaN"); return; } if (isInfinite(aValue)) { if (aValue < 0) aDest.Append(PRUnichar('-')); aDest.AppendLiteral("Infinity"); return; } // Mantissa length is 17, so this is plenty const int buflen = 20; char buf[buflen]; PRIntn intDigits, sign; char* endp; PR_dtoa(aValue, 0, 0, &intDigits, &sign, &endp, buf, buflen - 1); // compute length PRInt32 length = endp - buf; if (length > intDigits) { // decimal point needed ++length; if (intDigits < 1) { // leading zeros, -intDigits + 1 length += 1 - intDigits; } } else { // trailing zeros, total length given by intDigits length = intDigits; } if (aValue < 0) ++length; // grow the string PRUint32 oldlength = aDest.Length(); if (!EnsureStringLength(aDest, oldlength + length)) return; // out of memory nsAString::iterator dest; aDest.BeginWriting(dest).advance(PRInt32(oldlength)); if (aValue < 0) { *dest = '-'; ++dest; } int i; // leading zeros if (intDigits < 1) { *dest = '0'; ++dest; *dest = '.'; ++dest; for (i = 0; i > intDigits; --i) { *dest = '0'; ++dest; } } // mantissa int firstlen = PR_MIN(intDigits, endp - buf); for (i = 0; i < firstlen; i++) { *dest = buf[i]; ++dest; } if (i < endp - buf) { if (i > 0) { *dest = '.'; ++dest; } for (; i < endp - buf; i++) { *dest = buf[i]; ++dest; } } // trailing zeros for (; i < intDigits; i++) { *dest = '0'; ++dest; } }
nsresult nsIndexedToHTML::FormatInputStream(nsIRequest* aRequest, nsISupports *aContext, const nsAString &aBuffer) { nsresult rv = NS_OK; // set up unicode encoder if (!mUnicodeEncoder) { nsXPIDLCString encoding; rv = mParser->GetEncoding(getter_Copies(encoding)); if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsICharsetConverterManager> charsetConverterManager; charsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); rv = charsetConverterManager->GetUnicodeEncoder(encoding.get(), getter_AddRefs(mUnicodeEncoder)); if (NS_SUCCEEDED(rv)) rv = mUnicodeEncoder->SetOutputErrorBehavior(nsIUnicodeEncoder::kOnError_Replace, nullptr, (char16_t)'?'); } } // convert the data with unicode encoder char *buffer = nullptr; int32_t dstLength; if (NS_SUCCEEDED(rv)) { int32_t unicharLength = aBuffer.Length(); rv = mUnicodeEncoder->GetMaxLength(PromiseFlatString(aBuffer).get(), unicharLength, &dstLength); if (NS_SUCCEEDED(rv)) { buffer = (char *) moz_malloc(dstLength); NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY); rv = mUnicodeEncoder->Convert(PromiseFlatString(aBuffer).get(), &unicharLength, buffer, &dstLength); if (NS_SUCCEEDED(rv)) { int32_t finLen = 0; rv = mUnicodeEncoder->Finish(buffer + dstLength, &finLen); if (NS_SUCCEEDED(rv)) dstLength += finLen; } } } // if conversion error then fallback to UTF-8 if (NS_FAILED(rv)) { rv = NS_OK; if (buffer) { nsMemory::Free(buffer); buffer = nullptr; } } nsCOMPtr<nsIInputStream> inputData; if (buffer) { rv = NS_NewCStringInputStream(getter_AddRefs(inputData), Substring(buffer, dstLength)); nsMemory::Free(buffer); NS_ENSURE_SUCCESS(rv, rv); rv = mListener->OnDataAvailable(aRequest, aContext, inputData, 0, dstLength); } else { NS_ConvertUTF16toUTF8 utf8Buffer(aBuffer); rv = NS_NewCStringInputStream(getter_AddRefs(inputData), utf8Buffer); NS_ENSURE_SUCCESS(rv, rv); rv = mListener->OnDataAvailable(aRequest, aContext, inputData, 0, utf8Buffer.Length()); } return (rv); }
bool TruncateComments(const nsAString& src, nsAString* const out) { const size_t dstByteCount = src.Length() * sizeof(src[0]); const UniqueBuffer dst(malloc(dstByteCount)); if (!dst) return false; auto srcItr = src.BeginReading(); const auto srcEnd = src.EndReading(); const auto dstBegin = (decltype(src[0])*)dst.get(); auto dstItr = dstBegin; const auto fnEmitUntil = [&](const decltype(srcItr)& nextSrcItr) { while (srcItr != nextSrcItr) { *dstItr = *srcItr; ++srcItr; ++dstItr; } }; const auto fnFindSoonestOf = [&](const nsString* needles, size_t needleCount, size_t* const out_foundId) { auto foundItr = srcItr; while (foundItr != srcEnd) { const auto haystack = Substring(foundItr, srcEnd); for (size_t i = 0; i < needleCount; i++) { if (StringBeginsWith(haystack, needles[i])) { *out_foundId = i; return foundItr; } } ++foundItr; } *out_foundId = needleCount; return foundItr; }; //// const nsString commentBeginnings[] = { NS_LITERAL_STRING("//"), NS_LITERAL_STRING("/*"), nsString() }; // Final empty string for "found // nothing". const nsString lineCommentEndings[] = { NS_LITERAL_STRING("\\\n"), NS_LITERAL_STRING("\n"), nsString() }; const nsString blockCommentEndings[] = { NS_LITERAL_STRING("\n"), NS_LITERAL_STRING("*/"), nsString() }; while (srcItr != srcEnd) { size_t foundId; fnEmitUntil( fnFindSoonestOf(commentBeginnings, 2, &foundId) ); fnEmitUntil(srcItr + commentBeginnings[foundId].Length()); // Final empty string // allows us to skip // forward here // unconditionally. switch (foundId) { case 0: // line comment while (true) { size_t endId; srcItr = fnFindSoonestOf(lineCommentEndings, 2, &endId); fnEmitUntil(srcItr + lineCommentEndings[endId].Length()); if (endId == 0) continue; break; } break; case 1: // block comment while (true) { size_t endId; srcItr = fnFindSoonestOf(blockCommentEndings, 2, &endId); fnEmitUntil(srcItr + blockCommentEndings[endId].Length()); if (endId == 0) continue; break; } break; default: // not found break; } } MOZ_ASSERT((dstBegin+1) - dstBegin == 1); const uint32_t dstCharLen = dstItr - dstBegin; if (!out->Assign(dstBegin, dstCharLen, mozilla::fallible)) return false; return true; }