void ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode, const nsTArray<ReadbackProcessor::Update>& aReadbackUpdates) { HRESULT hr; nsIntRect visibleRect = mVisibleRegion.GetBounds(); nsRefPtr<gfxASurface> destinationSurface; nsIntRect bounds = aRegion.GetBounds(); nsRefPtr<IDirect3DTexture9> tmpTexture; OpaqueRenderer opaqueRenderer(aRegion); OpaqueRenderer opaqueRendererOnWhite(aRegion); switch (aMode) { case SurfaceMode::SURFACE_OPAQUE: destinationSurface = opaqueRenderer.Begin(this); break; case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: { hr = device()->CreateTexture(bounds.width, bounds.height, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), nullptr); if (FAILED(hr)) { ReportFailure(NS_LITERAL_CSTRING("Failed to create temporary texture in system memory."), hr); return; } // XXX - We may consider retaining a SYSTEMMEM texture texture the size // of our DEFAULT texture and then use UpdateTexture and add dirty rects // to update in a single call. nsRefPtr<gfxWindowsSurface> dest = new gfxWindowsSurface( gfxIntSize(bounds.width, bounds.height), gfxImageFormat::ARGB32); // If the contents of this layer don't require component alpha in the // end of rendering, it's safe to enable Cleartype since all the Cleartype // glyphs must be over (or under) opaque pixels. dest->SetSubpixelAntialiasingEnabled(!(mContentFlags & CONTENT_COMPONENT_ALPHA)); destinationSurface = dest.forget(); break; } case SurfaceMode::SURFACE_COMPONENT_ALPHA: { nsRefPtr<gfxWindowsSurface> onBlack = opaqueRenderer.Begin(this); nsRefPtr<gfxWindowsSurface> onWhite = opaqueRendererOnWhite.Begin(this); if (onBlack && onWhite) { FillSurface(onBlack, aRegion, bounds.TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0)); FillSurface(onWhite, aRegion, bounds.TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0)); gfxASurface* surfaces[2] = { onBlack.get(), onWhite.get() }; destinationSurface = new gfxTeeSurface(surfaces, ArrayLength(surfaces)); // Using this surface as a source will likely go horribly wrong, since // only the onBlack surface will really be used, so alpha information will // be incorrect. destinationSurface->SetAllowUseAsSource(false); } break; } } if (!destinationSurface) return; nsRefPtr<gfxContext> context; if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO)) { RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface, IntSize(destinationSurface->GetSize().width, destinationSurface->GetSize().height)); context = new gfxContext(dt); } else { context = new gfxContext(destinationSurface); } context->Translate(gfxPoint(-bounds.x, -bounds.y)); LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); cbInfo.Callback(this, context, aRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), cbInfo.CallbackData); for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) { NS_ASSERTION(aMode == SurfaceMode::SURFACE_OPAQUE, "Transparent surfaces should not be used for readback"); const ReadbackProcessor::Update& update = aReadbackUpdates[i]; nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset(); nsRefPtr<gfxContext> ctx = update.mLayer->GetSink()->BeginUpdate(update.mUpdateRect + offset, update.mSequenceCounter); if (ctx) { ctx->Translate(gfxPoint(offset.x, offset.y)); ctx->SetSource(destinationSurface, gfxPoint(bounds.x, bounds.y)); ctx->Paint(); update.mLayer->GetSink()->EndUpdate(ctx, update.mUpdateRect + offset); } } // Release the cairo d3d9 surface before we try to composite it context = nullptr; nsAutoTArray<IDirect3DTexture9*,2> srcTextures; nsAutoTArray<IDirect3DTexture9*,2> destTextures; switch (aMode) { case SurfaceMode::SURFACE_OPAQUE: // Must release reference to dest surface before ending drawing destinationSurface = nullptr; opaqueRenderer.End(); srcTextures.AppendElement(opaqueRenderer.GetTexture()); destTextures.AppendElement(mTexture); break; case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: { LockTextureRectD3D9 textureLock(tmpTexture); if (!textureLock.HasLock()) { NS_WARNING("Failed to lock ThebesLayer tmpTexture texture."); return; } D3DLOCKED_RECT r = textureLock.GetLockRect(); nsRefPtr<gfxImageSurface> imgSurface = new gfxImageSurface((unsigned char *)r.pBits, bounds.Size(), r.Pitch, gfxImageFormat::ARGB32); if (destinationSurface) { nsRefPtr<gfxContext> context = new gfxContext(imgSurface); context->SetSource(destinationSurface); context->SetOperator(gfxContext::OPERATOR_SOURCE); context->Paint(); } // Must release reference to dest surface before ending drawing destinationSurface = nullptr; imgSurface = nullptr; srcTextures.AppendElement(tmpTexture); destTextures.AppendElement(mTexture); break; } case SurfaceMode::SURFACE_COMPONENT_ALPHA: { // Must release reference to dest surface before ending drawing destinationSurface = nullptr; opaqueRenderer.End(); opaqueRendererOnWhite.End(); srcTextures.AppendElement(opaqueRenderer.GetTexture()); destTextures.AppendElement(mTexture); srcTextures.AppendElement(opaqueRendererOnWhite.GetTexture()); destTextures.AppendElement(mTextureOnWhite); break; } } NS_ASSERTION(srcTextures.Length() == destTextures.Length(), "Mismatched lengths"); // Copy to the texture. for (uint32_t i = 0; i < srcTextures.Length(); ++i) { nsRefPtr<IDirect3DSurface9> srcSurface; nsRefPtr<IDirect3DSurface9> dstSurface; destTextures[i]->GetSurfaceLevel(0, getter_AddRefs(dstSurface)); srcTextures[i]->GetSurfaceLevel(0, getter_AddRefs(srcSurface)); nsIntRegionRectIterator iter(aRegion); const nsIntRect *iterRect; while ((iterRect = iter.Next())) { RECT rect; rect.left = iterRect->x - bounds.x; rect.top = iterRect->y - bounds.y; rect.right = iterRect->XMost() - bounds.x; rect.bottom = iterRect->YMost() - bounds.y; POINT point; point.x = iterRect->x - visibleRect.x; point.y = iterRect->y - visibleRect.y; device()->UpdateSurface(srcSurface, &rect, dstSurface, &point); } } }
bool JavaScriptChild::AnswerCall(const ObjectId &objId, const nsTArray<JSParam> &argv, ReturnStatus *rs, JSVariant *result, nsTArray<JSParam> *outparams) { AutoSafeJSContext cx; JSAutoRequest request(cx); // The outparam will be written to the buffer, so it must be set even if // the parent won't read it. *result = void_t(); RootedObject obj(cx, findObject(objId)); if (!obj) return false; MOZ_ASSERT(argv.Length() >= 2); RootedValue objv(cx); if (!toValue(cx, argv[0], &objv)) return fail(cx, rs); JSAutoCompartment comp(cx, &objv.toObject()); *result = JSVariant(void_t()); AutoValueVector vals(cx); AutoValueVector outobjects(cx); for (size_t i = 0; i < argv.Length(); i++) { if (argv[i].type() == JSParam::Tvoid_t) { // This is an outparam. JSCompartment *compartment = js::GetContextCompartment(cx); RootedObject global(cx, JS_GetGlobalForCompartmentOrNull(cx, compartment)); RootedObject obj(cx, xpc::NewOutObject(cx, global)); if (!obj) return fail(cx, rs); if (!outobjects.append(ObjectValue(*obj))) return fail(cx, rs); if (!vals.append(ObjectValue(*obj))) return fail(cx, rs); } else { RootedValue v(cx); if (!toValue(cx, argv[i].get_JSVariant(), &v)) return fail(cx, rs); if (!vals.append(v)) return fail(cx, rs); } } uint32_t oldOpts = JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_DONT_REPORT_UNCAUGHT); RootedValue rval(cx); bool success = JS::Call(cx, vals[1], vals[0], vals.length() - 2, vals.begin() + 2, &rval); JS_SetOptions(cx, oldOpts); if (!success) return fail(cx, rs); if (!toVariant(cx, rval, result)) return fail(cx, rs); // Prefill everything with a dummy jsval. for (size_t i = 0; i < outobjects.length(); i++) outparams->AppendElement(JSParam(void_t())); // Go through each argument that was an outparam, retrieve the "value" // field, and add it to a temporary list. We need to do this separately // because the outparams vector is not rooted. vals.clear(); for (size_t i = 0; i < outobjects.length(); i++) { RootedObject obj(cx, &outobjects[i].toObject()); jsval v; JSBool found; if (JS_HasProperty(cx, obj, "value", &found)) { if (!JS_GetProperty(cx, obj, "value", &v)) return fail(cx, rs); } else { v = UndefinedValue(); } if (!vals.append(v)) return fail(cx, rs); } // Copy the outparams. If any outparam is already set to a void_t, we // treat this as the outparam never having been set. for (size_t i = 0; i < vals.length(); i++) { JSVariant variant; if (!toVariant(cx, vals[i], &variant)) return fail(cx, rs); outparams->ReplaceElementAt(i, JSParam(variant)); } return ok(rs); }
nsCString ToHexString(const nsTArray<uint8_t>& aBytes) { return ToHexString(aBytes.Elements(), aBytes.Length()); }
bool WrapperAnswer::AnswerCallOrConstruct(const ObjectId &objId, const nsTArray<JSParam> &argv, const bool &construct, ReturnStatus *rs, JSVariant *result, nsTArray<JSParam> *outparams) { AutoSafeJSContext cx; JSAutoRequest request(cx); // The outparam will be written to the buffer, so it must be set even if // the parent won't read it. *result = UndefinedVariant(); RootedObject obj(cx, findObjectById(cx, objId)); if (!obj) return fail(cx, rs); JSAutoCompartment comp(cx, obj); MOZ_ASSERT(argv.Length() >= 2); RootedValue objv(cx); if (!fromVariant(cx, argv[0], &objv)) return fail(cx, rs); *result = JSVariant(UndefinedVariant()); AutoValueVector vals(cx); AutoValueVector outobjects(cx); for (size_t i = 0; i < argv.Length(); i++) { if (argv[i].type() == JSParam::Tvoid_t) { // This is an outparam. JSCompartment *compartment = js::GetContextCompartment(cx); RootedObject global(cx, JS_GetGlobalForCompartmentOrNull(cx, compartment)); RootedObject obj(cx, xpc::NewOutObject(cx, global)); if (!obj) return fail(cx, rs); if (!outobjects.append(ObjectValue(*obj))) return fail(cx, rs); if (!vals.append(ObjectValue(*obj))) return fail(cx, rs); } else { RootedValue v(cx); if (!fromVariant(cx, argv[i].get_JSVariant(), &v)) return fail(cx, rs); if (!vals.append(v)) return fail(cx, rs); } } RootedValue rval(cx); { AutoSaveContextOptions asco(cx); ContextOptionsRef(cx).setDontReportUncaught(true); HandleValueArray args = HandleValueArray::subarray(vals, 2, vals.length() - 2); bool success; if (construct) success = JS::Construct(cx, vals[0], args, &rval); else success = JS::Call(cx, vals[1], vals[0], args, &rval); if (!success) return fail(cx, rs); } if (!toVariant(cx, rval, result)) return fail(cx, rs); // Prefill everything with a dummy jsval. for (size_t i = 0; i < outobjects.length(); i++) outparams->AppendElement(JSParam(void_t())); // Go through each argument that was an outparam, retrieve the "value" // field, and add it to a temporary list. We need to do this separately // because the outparams vector is not rooted. vals.clear(); for (size_t i = 0; i < outobjects.length(); i++) { RootedObject obj(cx, &outobjects[i].toObject()); RootedValue v(cx); bool found; if (JS_HasProperty(cx, obj, "value", &found)) { if (!JS_GetProperty(cx, obj, "value", &v)) return fail(cx, rs); } else { v = UndefinedValue(); } if (!vals.append(v)) return fail(cx, rs); } // Copy the outparams. If any outparam is already set to a void_t, we // treat this as the outparam never having been set. for (size_t i = 0; i < vals.length(); i++) { JSVariant variant; if (!toVariant(cx, vals[i], &variant)) return fail(cx, rs); outparams->ReplaceElementAt(i, JSParam(variant)); } LOG("%s.call(%s) = %s", ReceiverObj(objId), argv, OutVariant(*result)); return ok(rs); }
nsresult HTMLFormControlsCollection::GetSortedControls( nsTArray<nsGenericHTMLFormElement*>& aControls) const { #ifdef DEBUG HTMLFormElement::AssertDocumentOrder(mElements, mForm); HTMLFormElement::AssertDocumentOrder(mNotInElements, mForm); #endif aControls.Clear(); // Merge the elements list and the not in elements list. Both lists are // already sorted. uint32_t elementsLen = mElements.Length(); uint32_t notInElementsLen = mNotInElements.Length(); aControls.SetCapacity(elementsLen + notInElementsLen); uint32_t elementsIdx = 0; uint32_t notInElementsIdx = 0; while (elementsIdx < elementsLen || notInElementsIdx < notInElementsLen) { // Check whether we're done with mElements if (elementsIdx == elementsLen) { NS_ASSERTION(notInElementsIdx < notInElementsLen, "Should have remaining not-in-elements"); // Append the remaining mNotInElements elements if (!aControls.AppendElements(mNotInElements.Elements() + notInElementsIdx, notInElementsLen - notInElementsIdx)) { return NS_ERROR_OUT_OF_MEMORY; } break; } // Check whether we're done with mNotInElements if (notInElementsIdx == notInElementsLen) { NS_ASSERTION(elementsIdx < elementsLen, "Should have remaining in-elements"); // Append the remaining mElements elements if (!aControls.AppendElements(mElements.Elements() + elementsIdx, elementsLen - elementsIdx)) { return NS_ERROR_OUT_OF_MEMORY; } break; } // Both lists have elements left. NS_ASSERTION(mElements[elementsIdx] && mNotInElements[notInElementsIdx], "Should have remaining elements"); // Determine which of the two elements should be ordered // first and add it to the end of the list. nsGenericHTMLFormElement* elementToAdd; if (HTMLFormElement::CompareFormControlPosition( mElements[elementsIdx], mNotInElements[notInElementsIdx], mForm) < 0) { elementToAdd = mElements[elementsIdx]; ++elementsIdx; } else { elementToAdd = mNotInElements[notInElementsIdx]; ++notInElementsIdx; } // Add the first element to the list. if (!aControls.AppendElement(elementToAdd)) { return NS_ERROR_OUT_OF_MEMORY; } } NS_ASSERTION(aControls.Length() == elementsLen + notInElementsLen, "Not all form controls were added to the sorted list"); #ifdef DEBUG HTMLFormElement::AssertDocumentOrder(aControls, mForm); #endif return NS_OK; }
nsresult nsTextAttrsMgr::GetRange(const nsTArray<nsITextAttr*>& aTextAttrArray, PRInt32 *aStartHTOffset, PRInt32 *aEndHTOffset) { PRUint32 attrLen = aTextAttrArray.Length(); // Navigate backward from anchor accessible to find start offset. for (PRInt32 childIdx = mOffsetAccIdx - 1; childIdx >= 0; childIdx--) { nsAccessible *currAcc = mHyperTextAcc->GetChildAt(childIdx); // Stop on embedded accessible since embedded accessibles are combined into // own range. if (nsAccUtils::IsEmbeddedObject(currAcc)) break; nsIContent *currElm = nsCoreUtils::GetDOMElementFor(currAcc->GetContent()); NS_ENSURE_STATE(currElm); bool offsetFound = false; for (PRUint32 attrIdx = 0; attrIdx < attrLen; attrIdx++) { nsITextAttr *textAttr = aTextAttrArray[attrIdx]; if (!textAttr->Equal(currElm)) { offsetFound = true; break; } } if (offsetFound) break; *(aStartHTOffset) -= nsAccUtils::TextLength(currAcc); } // Navigate forward from anchor accessible to find end offset. PRInt32 childLen = mHyperTextAcc->GetChildCount(); for (PRInt32 childIdx = mOffsetAccIdx + 1; childIdx < childLen; childIdx++) { nsAccessible *currAcc = mHyperTextAcc->GetChildAt(childIdx); if (nsAccUtils::IsEmbeddedObject(currAcc)) break; nsIContent *currElm = nsCoreUtils::GetDOMElementFor(currAcc->GetContent()); NS_ENSURE_STATE(currElm); bool offsetFound = false; for (PRUint32 attrIdx = 0; attrIdx < attrLen; attrIdx++) { nsITextAttr *textAttr = aTextAttrArray[attrIdx]; // Alter the end offset when text attribute changes its value and stop // the search. if (!textAttr->Equal(currElm)) { offsetFound = true; break; } } if (offsetFound) break; (*aEndHTOffset) += nsAccUtils::TextLength(currAcc); } return NS_OK; }
bool nsCaseTransformTextRunFactory::TransformString( const nsAString& aString, nsString& aConvertedString, bool aAllUppercase, const nsIAtom* aLanguage, nsTArray<bool>& aCharsToMergeArray, nsTArray<bool>& aDeletedCharsArray, nsTransformedTextRun* aTextRun, nsTArray<uint8_t>* aCanBreakBeforeArray, nsTArray<nsStyleContext*>* aStyleArray) { NS_PRECONDITION(!aTextRun || (aCanBreakBeforeArray && aStyleArray), "either none or all three optional parameters required"); uint32_t length = aString.Length(); const char16_t* str = aString.BeginReading(); bool mergeNeeded = false; bool capitalizeDutchIJ = false; bool prevIsLetter = false; bool ntPrefix = false; // true immediately after a word-initial 'n' or 't' // when doing Irish lowercasing uint32_t sigmaIndex = uint32_t(-1); nsIUGenCategory::nsUGenCategory cat; uint8_t style = aAllUppercase ? NS_STYLE_TEXT_TRANSFORM_UPPERCASE : 0; const nsIAtom* lang = aLanguage; LanguageSpecificCasingBehavior languageSpecificCasing = GetCasingFor(lang); mozilla::GreekCasing::State greekState; mozilla::IrishCasing::State irishState; uint32_t irishMark = uint32_t(-1); // location of possible prefix letter(s) for (uint32_t i = 0; i < length; ++i) { uint32_t ch = str[i]; nsStyleContext* styleContext; if (aTextRun) { styleContext = aTextRun->mStyles[i]; style = aAllUppercase ? NS_STYLE_TEXT_TRANSFORM_UPPERCASE : styleContext->StyleText()->mTextTransform; const nsStyleFont* styleFont = styleContext->StyleFont(); nsIAtom* newLang = styleFont->mExplicitLanguage ? styleFont->mLanguage : nullptr; if (lang != newLang) { lang = newLang; languageSpecificCasing = GetCasingFor(lang); greekState.Reset(); irishState.Reset(); irishMark = uint32_t(-1); } } int extraChars = 0; const mozilla::unicode::MultiCharMapping *mcm; bool inhibitBreakBefore = false; // have we just deleted preceding hyphen? if (NS_IS_HIGH_SURROGATE(ch) && i < length - 1 && NS_IS_LOW_SURROGATE(str[i + 1])) { ch = SURROGATE_TO_UCS4(ch, str[i + 1]); } switch (style) { case NS_STYLE_TEXT_TRANSFORM_LOWERCASE: if (languageSpecificCasing == eLSCB_Turkish) { if (ch == 'I') { ch = LATIN_SMALL_LETTER_DOTLESS_I; prevIsLetter = true; sigmaIndex = uint32_t(-1); break; } if (ch == LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE) { ch = 'i'; prevIsLetter = true; sigmaIndex = uint32_t(-1); break; } } cat = mozilla::unicode::GetGenCategory(ch); if (languageSpecificCasing == eLSCB_Irish && cat == nsIUGenCategory::kLetter) { // See bug 1018805 for Irish lowercasing requirements if (!prevIsLetter && (ch == 'n' || ch == 't')) { ntPrefix = true; } else { if (ntPrefix && mozilla::IrishCasing::IsUpperVowel(ch)) { aConvertedString.Append('-'); ++extraChars; } ntPrefix = false; } } else { ntPrefix = false; } // Special lowercasing behavior for Greek Sigma: note that this is listed // as context-sensitive in Unicode's SpecialCasing.txt, but is *not* a // language-specific mapping; it applies regardless of the language of // the element. // // The lowercase mapping for CAPITAL SIGMA should be to SMALL SIGMA (i.e. // the non-final form) whenever there is a following letter, or when the // CAPITAL SIGMA occurs in isolation (neither preceded nor followed by a // LETTER); and to FINAL SIGMA when it is preceded by another letter but // not followed by one. // // To implement the context-sensitive nature of this mapping, we keep // track of whether the previous character was a letter. If not, CAPITAL // SIGMA will map directly to SMALL SIGMA. If the previous character // was a letter, CAPITAL SIGMA maps to FINAL SIGMA and we record the // position in the converted string; if we then encounter another letter, // that FINAL SIGMA is replaced with a standard SMALL SIGMA. // If sigmaIndex is not -1, it marks where we have provisionally mapped // a CAPITAL SIGMA to FINAL SIGMA; if we now find another letter, we // need to change it to SMALL SIGMA. if (sigmaIndex != uint32_t(-1)) { if (cat == nsIUGenCategory::kLetter) { aConvertedString.SetCharAt(GREEK_SMALL_LETTER_SIGMA, sigmaIndex); } } if (ch == GREEK_CAPITAL_LETTER_SIGMA) { // If preceding char was a letter, map to FINAL instead of SMALL, // and note where it occurred by setting sigmaIndex; we'll change it // to standard SMALL SIGMA later if another letter follows if (prevIsLetter) { ch = GREEK_SMALL_LETTER_FINAL_SIGMA; sigmaIndex = aConvertedString.Length(); } else { // CAPITAL SIGMA not preceded by a letter is unconditionally mapped // to SMALL SIGMA ch = GREEK_SMALL_LETTER_SIGMA; sigmaIndex = uint32_t(-1); } prevIsLetter = true; break; } // ignore diacritics for the purpose of contextual sigma mapping; // otherwise, reset prevIsLetter appropriately and clear the // sigmaIndex marker if (cat != nsIUGenCategory::kMark) { prevIsLetter = (cat == nsIUGenCategory::kLetter); sigmaIndex = uint32_t(-1); } mcm = mozilla::unicode::SpecialLower(ch); if (mcm) { int j = 0; while (j < 2 && mcm->mMappedChars[j + 1]) { aConvertedString.Append(mcm->mMappedChars[j]); ++extraChars; ++j; } ch = mcm->mMappedChars[j]; break; } ch = ToLowerCase(ch); break; case NS_STYLE_TEXT_TRANSFORM_UPPERCASE: if (languageSpecificCasing == eLSCB_Turkish && ch == 'i') { ch = LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE; break; } if (languageSpecificCasing == eLSCB_Greek) { ch = mozilla::GreekCasing::UpperCase(ch, greekState); break; } if (languageSpecificCasing == eLSCB_Irish) { bool mark; uint8_t action; ch = mozilla::IrishCasing::UpperCase(ch, irishState, mark, action); if (mark) { irishMark = aConvertedString.Length(); break; } else if (action) { nsString& str = aConvertedString; // shorthand switch (action) { case 1: // lowercase a single prefix letter NS_ASSERTION(str.Length() > 0 && irishMark < str.Length(), "bad irishMark!"); str.SetCharAt(ToLowerCase(str[irishMark]), irishMark); irishMark = uint32_t(-1); break; case 2: // lowercase two prefix letters (immediately before current pos) NS_ASSERTION(str.Length() >= 2 && irishMark == str.Length() - 2, "bad irishMark!"); str.SetCharAt(ToLowerCase(str[irishMark]), irishMark); str.SetCharAt(ToLowerCase(str[irishMark + 1]), irishMark + 1); irishMark = uint32_t(-1); break; case 3: // lowercase one prefix letter, and delete following hyphen // (which must be the immediately-preceding char) NS_ASSERTION(str.Length() >= 2 && irishMark == str.Length() - 2, "bad irishMark!"); str.Replace(irishMark, 2, ToLowerCase(str[irishMark])); aDeletedCharsArray[irishMark + 1] = true; // Remove the trailing entries (corresponding to the deleted hyphen) // from the auxiliary arrays. aCharsToMergeArray.SetLength(aCharsToMergeArray.Length() - 1); if (aTextRun) { aStyleArray->SetLength(aStyleArray->Length() - 1); aCanBreakBeforeArray->SetLength(aCanBreakBeforeArray->Length() - 1); inhibitBreakBefore = true; } mergeNeeded = true; irishMark = uint32_t(-1); break; } // ch has been set to the uppercase for current char; // No need to check for SpecialUpper here as none of the characters // that could trigger an Irish casing action have special mappings. break; } // If we didn't have any special action to perform, fall through // to check for special uppercase (ß) } mcm = mozilla::unicode::SpecialUpper(ch); if (mcm) { int j = 0; while (j < 2 && mcm->mMappedChars[j + 1]) { aConvertedString.Append(mcm->mMappedChars[j]); ++extraChars; ++j; } ch = mcm->mMappedChars[j]; break; } ch = ToUpperCase(ch); break; case NS_STYLE_TEXT_TRANSFORM_CAPITALIZE: if (aTextRun) { if (capitalizeDutchIJ && ch == 'j') { ch = 'J'; capitalizeDutchIJ = false; break; } capitalizeDutchIJ = false; if (i < aTextRun->mCapitalize.Length() && aTextRun->mCapitalize[i]) { if (languageSpecificCasing == eLSCB_Turkish && ch == 'i') { ch = LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE; break; } if (languageSpecificCasing == eLSCB_Dutch && ch == 'i') { ch = 'I'; capitalizeDutchIJ = true; break; } mcm = mozilla::unicode::SpecialTitle(ch); if (mcm) { int j = 0; while (j < 2 && mcm->mMappedChars[j + 1]) { aConvertedString.Append(mcm->mMappedChars[j]); ++extraChars; ++j; } ch = mcm->mMappedChars[j]; break; } ch = ToTitleCase(ch); } } break; case NS_STYLE_TEXT_TRANSFORM_FULLWIDTH: ch = mozilla::unicode::GetFullWidth(ch); break; default: break; } if (ch == uint32_t(-1)) { aDeletedCharsArray.AppendElement(true); mergeNeeded = true; } else { aDeletedCharsArray.AppendElement(false); aCharsToMergeArray.AppendElement(false); if (aTextRun) { aStyleArray->AppendElement(styleContext); aCanBreakBeforeArray->AppendElement(inhibitBreakBefore ? false : aTextRun->CanBreakLineBefore(i)); } if (IS_IN_BMP(ch)) { aConvertedString.Append(ch); } else { aConvertedString.Append(H_SURROGATE(ch)); aConvertedString.Append(L_SURROGATE(ch)); ++i; aDeletedCharsArray.AppendElement(true); // not exactly deleted, but the // trailing surrogate is skipped ++extraChars; } while (extraChars-- > 0) { mergeNeeded = true; aCharsToMergeArray.AppendElement(true); if (aTextRun) { aStyleArray->AppendElement(styleContext); aCanBreakBeforeArray->AppendElement(false); } } } } return mergeNeeded; }
HRESULT STDMETHODCALLTYPE DWriteFontFileStream::GetFileSize(UINT64* fileSize) { *fileSize = mData.Length(); return S_OK; }
void nsEventTargetChainItem::HandleEventTargetChain( nsTArray<nsEventTargetChainItem>& aChain, nsEventChainPostVisitor& aVisitor, nsDispatchingCallback* aCallback, ELMCreationDetector& aCd) { // Save the target so that it can be restored later. nsCOMPtr<EventTarget> firstTarget = aVisitor.mEvent->target; uint32_t chainLength = aChain.Length(); // Capture aVisitor.mEvent->mFlags.mInCapturePhase = true; aVisitor.mEvent->mFlags.mInBubblingPhase = false; for (uint32_t i = chainLength - 1; i > 0; --i) { nsEventTargetChainItem& item = aChain[i]; if ((!aVisitor.mEvent->mFlags.mNoContentDispatch || item.ForceContentDispatch()) && !aVisitor.mEvent->mFlags.mPropagationStopped) { item.HandleEvent(aVisitor, aCd); } if (item.GetNewTarget()) { // item is at anonymous boundary. Need to retarget for the child items. for (uint32_t j = i; j > 0; --j) { uint32_t childIndex = j - 1; EventTarget* newTarget = aChain[childIndex].GetNewTarget(); if (newTarget) { aVisitor.mEvent->target = newTarget; break; } } } } // Target aVisitor.mEvent->mFlags.mInBubblingPhase = true; nsEventTargetChainItem& targetItem = aChain[0]; if (!aVisitor.mEvent->mFlags.mPropagationStopped && (!aVisitor.mEvent->mFlags.mNoContentDispatch || targetItem.ForceContentDispatch())) { targetItem.HandleEvent(aVisitor, aCd); } if (aVisitor.mEvent->mFlags.mInSystemGroup) { targetItem.PostHandleEvent(aVisitor); } // Bubble aVisitor.mEvent->mFlags.mInCapturePhase = false; for (uint32_t i = 1; i < chainLength; ++i) { nsEventTargetChainItem& item = aChain[i]; EventTarget* newTarget = item.GetNewTarget(); if (newTarget) { // Item is at anonymous boundary. Need to retarget for the current item // and for parent items. aVisitor.mEvent->target = newTarget; } if (aVisitor.mEvent->mFlags.mBubbles || newTarget) { if ((!aVisitor.mEvent->mFlags.mNoContentDispatch || item.ForceContentDispatch()) && !aVisitor.mEvent->mFlags.mPropagationStopped) { item.HandleEvent(aVisitor, aCd); } if (aVisitor.mEvent->mFlags.mInSystemGroup) { item.PostHandleEvent(aVisitor); } } } aVisitor.mEvent->mFlags.mInBubblingPhase = false; if (!aVisitor.mEvent->mFlags.mInSystemGroup) { // Dispatch to the system event group. Make sure to clear the // STOP_DISPATCH flag since this resets for each event group. aVisitor.mEvent->mFlags.mPropagationStopped = false; aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false; // Setting back the original target of the event. aVisitor.mEvent->target = aVisitor.mEvent->originalTarget; // Special handling if PresShell (or some other caller) // used a callback object. if (aCallback) { aCallback->HandleEvent(aVisitor); } // Retarget for system event group (which does the default handling too). // Setting back the target which was used also for default event group. aVisitor.mEvent->target = firstTarget; aVisitor.mEvent->mFlags.mInSystemGroup = true; HandleEventTargetChain(aChain, aVisitor, aCallback, aCd); aVisitor.mEvent->mFlags.mInSystemGroup = false; // After dispatch, clear all the propagation flags so that // system group listeners don't affect to the event. aVisitor.mEvent->mFlags.mPropagationStopped = false; aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false; } }
nsresult AppleATDecoder::GetInputAudioDescription(AudioStreamBasicDescription& aDesc, const nsTArray<uint8_t>& aExtraData) { // Request the properties from CoreAudio using the codec magic cookie AudioFormatInfo formatInfo; PodZero(&formatInfo.mASBD); formatInfo.mASBD.mFormatID = mFormatID; if (mFormatID == kAudioFormatMPEG4AAC) { formatInfo.mASBD.mFormatFlags = mConfig.extended_profile; } formatInfo.mMagicCookieSize = aExtraData.Length(); formatInfo.mMagicCookie = aExtraData.Elements(); UInt32 formatListSize; // Attempt to retrieve the default format using // kAudioFormatProperty_FormatInfo method. // This method only retrieves the FramesPerPacket information required // by the decoder, which depends on the codec type and profile. aDesc.mFormatID = mFormatID; aDesc.mChannelsPerFrame = mConfig.channel_count; aDesc.mSampleRate = mConfig.samples_per_second; UInt32 inputFormatSize = sizeof(aDesc); OSStatus rv = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &inputFormatSize, &aDesc); if (NS_WARN_IF(rv)) { return NS_ERROR_FAILURE; } // If any of the methods below fail, we will return the default format as // created using kAudioFormatProperty_FormatInfo above. rv = AudioFormatGetPropertyInfo(kAudioFormatProperty_FormatList, sizeof(formatInfo), &formatInfo, &formatListSize); if (rv || (formatListSize % sizeof(AudioFormatListItem))) { return NS_OK; } size_t listCount = formatListSize / sizeof(AudioFormatListItem); nsAutoArrayPtr<AudioFormatListItem> formatList( new AudioFormatListItem[listCount]); rv = AudioFormatGetProperty(kAudioFormatProperty_FormatList, sizeof(formatInfo), &formatInfo, &formatListSize, formatList); if (rv) { return NS_OK; } LOG("found %u available audio stream(s)", formatListSize / sizeof(AudioFormatListItem)); // Get the index number of the first playable format. // This index number will be for the highest quality layer the platform // is capable of playing. UInt32 itemIndex; UInt32 indexSize = sizeof(itemIndex); rv = AudioFormatGetProperty(kAudioFormatProperty_FirstPlayableFormatFromList, formatListSize, formatList, &indexSize, &itemIndex); if (rv) { return NS_OK; } aDesc = formatList[itemIndex].mASBD; return NS_OK; }
NS_IMETHODIMP nsDOMMultipartBlob::MozSlice(PRInt64 aStart, PRInt64 aEnd, const nsAString& aContentType, PRUint8 optional_argc, nsIDOMBlob **aBlob) { nsresult rv; *aBlob = nsnull; // Truncate aStart and aEnd so that we stay within this file. PRUint64 thisLength; rv = GetSize(&thisLength); NS_ENSURE_SUCCESS(rv, rv); if (!optional_argc) { aEnd = (PRInt64)thisLength; } // Modifies aStart and aEnd. ParseSize((PRInt64)thisLength, aStart, aEnd); // If we clamped to nothing we create an empty blob nsTArray<nsCOMPtr<nsIDOMBlob> > blobs; PRUint64 length = aEnd - aStart; PRUint64 skipStart = aStart; NS_ABORT_IF_FALSE(PRUint64(aStart) + length <= thisLength, "Er, what?"); // Prune the list of blobs if we can PRUint32 i; for (i = 0; length && skipStart && i < mBlobs.Length(); i++) { nsIDOMBlob* blob = mBlobs[i].get(); PRUint64 l; rv = blob->GetSize(&l); NS_ENSURE_SUCCESS(rv, rv); if (skipStart < l) { PRUint64 upperBound = NS_MIN<PRUint64>(l - skipStart, length); nsCOMPtr<nsIDOMBlob> firstBlob; rv = mBlobs.ElementAt(i)->MozSlice(skipStart, skipStart + upperBound, aContentType, 2, getter_AddRefs(firstBlob)); NS_ENSURE_SUCCESS(rv, rv); // Avoid wrapping a single blob inside an nsDOMMultipartBlob if (length == upperBound) { firstBlob.forget(aBlob); return NS_OK; } blobs.AppendElement(firstBlob); length -= upperBound; i++; break; } skipStart -= l; } // Now append enough blobs until we're done for (; length && i < mBlobs.Length(); i++) { nsIDOMBlob* blob = mBlobs[i].get(); PRUint64 l; rv = blob->GetSize(&l); NS_ENSURE_SUCCESS(rv, rv); if (length < l) { nsCOMPtr<nsIDOMBlob> lastBlob; rv = mBlobs.ElementAt(i)->MozSlice(0, length, aContentType, 2, getter_AddRefs(lastBlob)); NS_ENSURE_SUCCESS(rv, rv); blobs.AppendElement(lastBlob); } else { blobs.AppendElement(blob); } length -= NS_MIN<PRUint64>(l, length); } // we can create our blob now nsCOMPtr<nsIDOMBlob> blob = new nsDOMMultipartBlob(blobs, aContentType); blob.forget(aBlob); return NS_OK; }
int32_t GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray<GfxDriverInfo>& info, nsAString& aSuggestedVersion, int32_t aFeature, OperatingSystem os) { int32_t status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; nsAutoString adapterVendorID; nsAutoString adapterDeviceID; nsAutoString adapterDriverVersionString; if (NS_FAILED(GetAdapterVendorID(adapterVendorID)) || NS_FAILED(GetAdapterDeviceID(adapterDeviceID)) || NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString))) { return 0; } uint64_t driverVersion; ParseDriverVersion(adapterDriverVersionString, &driverVersion); uint32_t i = 0; for (; i < info.Length(); i++) { if (info[i].mOperatingSystem != DRIVER_OS_ALL && info[i].mOperatingSystem != os) { continue; } if (info[i].mOperatingSystemVersion && info[i].mOperatingSystemVersion != OperatingSystemVersion()) { continue; } if (!info[i].mAdapterVendor.Equals(GfxDriverInfo::GetDeviceVendor(VendorAll), nsCaseInsensitiveStringComparator()) && !info[i].mAdapterVendor.Equals(adapterVendorID, nsCaseInsensitiveStringComparator())) { continue; } if (info[i].mDevices != GfxDriverInfo::allDevices && info[i].mDevices->Length()) { bool deviceMatches = false; for (uint32_t j = 0; j < info[i].mDevices->Length(); j++) { if ((*info[i].mDevices)[j].Equals(adapterDeviceID, nsCaseInsensitiveStringComparator())) { deviceMatches = true; break; } } if (!deviceMatches) { continue; } } bool match = false; if (!info[i].mHardware.IsEmpty() && !info[i].mHardware.Equals(Hardware())) { continue; } if (!info[i].mModel.IsEmpty() && !info[i].mModel.Equals(Model())) { continue; } if (!info[i].mProduct.IsEmpty() && !info[i].mProduct.Equals(Product())) { continue; } if (!info[i].mManufacturer.IsEmpty() && !info[i].mManufacturer.Equals(Manufacturer())) { continue; } #if defined(XP_WIN) || defined(ANDROID) switch (info[i].mComparisonOp) { case DRIVER_LESS_THAN: match = driverVersion < info[i].mDriverVersion; break; case DRIVER_LESS_THAN_OR_EQUAL: match = driverVersion <= info[i].mDriverVersion; break; case DRIVER_GREATER_THAN: match = driverVersion > info[i].mDriverVersion; break; case DRIVER_GREATER_THAN_OR_EQUAL: match = driverVersion >= info[i].mDriverVersion; break; case DRIVER_EQUAL: match = driverVersion == info[i].mDriverVersion; break; case DRIVER_NOT_EQUAL: match = driverVersion != info[i].mDriverVersion; break; case DRIVER_BETWEEN_EXCLUSIVE: match = driverVersion > info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax; break; case DRIVER_BETWEEN_INCLUSIVE: match = driverVersion >= info[i].mDriverVersion && driverVersion <= info[i].mDriverVersionMax; break; case DRIVER_BETWEEN_INCLUSIVE_START: match = driverVersion >= info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax; break; case DRIVER_COMPARISON_IGNORED: // We don't have a comparison op, so we match everything. match = true; break; default: NS_WARNING("Bogus op in GfxDriverInfo"); break; } #else // We don't care what driver version it was. We only check OS version and if // the device matches. match = true; #endif if (match || info[i].mDriverVersion == GfxDriverInfo::allDriverVersions) { if (info[i].mFeature == GfxDriverInfo::allFeatures || info[i].mFeature == aFeature) { status = info[i].mFeatureStatus; break; } } } // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object // back to the Windows handler, so we must handle this here. #if defined(XP_WIN) if (status == FEATURE_BLOCKED_DRIVER_VERSION) { if (info[i].mSuggestedVersion) { aSuggestedVersion.AppendPrintf("%s", info[i].mSuggestedVersion); } else if (info[i].mComparisonOp == DRIVER_LESS_THAN && info[i].mDriverVersion != GfxDriverInfo::allDriverVersions) { aSuggestedVersion.AppendPrintf("%lld.%lld.%lld.%lld", (info[i].mDriverVersion & 0xffff000000000000) >> 48, (info[i].mDriverVersion & 0x0000ffff00000000) >> 32, (info[i].mDriverVersion & 0x00000000ffff0000) >> 16, (info[i].mDriverVersion & 0x000000000000ffff)); } }
nsresult nsDOMStoragePersistentDB::RemoveOwners(const nsTArray<nsString> &aOwners, bool aIncludeSubDomains, bool aMatch) { if (aOwners.Length() == 0) { if (aMatch) { return NS_OK; } return RemoveAll(); } // Using nsString here because it is going to be very long nsCString expression; if (aMatch) { expression.AppendLiteral("DELETE FROM webappsstore2_view WHERE scope IN ("); } else { expression.AppendLiteral("DELETE FROM webappsstore2_view WHERE scope NOT IN ("); } for (PRUint32 i = 0; i < aOwners.Length(); i++) { if (i) expression.AppendLiteral(" UNION "); expression.AppendLiteral( "SELECT DISTINCT scope FROM webappsstore2_temp WHERE scope GLOB :scope"); expression.AppendInt(i); expression.AppendLiteral(" UNION "); expression.AppendLiteral( "SELECT DISTINCT scope FROM webappsstore2 WHERE scope GLOB :scope"); expression.AppendInt(i); } expression.AppendLiteral(");"); nsCOMPtr<mozIStorageStatement> statement; nsresult rv; rv = MaybeCommitInsertTransaction(); NS_ENSURE_SUCCESS(rv, rv); rv = mConnection->CreateStatement(expression, getter_AddRefs(statement)); NS_ENSURE_SUCCESS(rv, rv); for (PRUint32 i = 0; i < aOwners.Length(); i++) { nsCAutoString quotaKey; rv = nsDOMStorageDBWrapper::CreateDomainScopeDBKey( NS_ConvertUTF16toUTF8(aOwners[i]), quotaKey); if (DomainMaybeCached(quotaKey)) { mCachedUsage = 0; mCachedOwner.Truncate(); } if (!aIncludeSubDomains) quotaKey.AppendLiteral(":"); quotaKey.AppendLiteral("*"); nsCAutoString paramName; paramName.Assign("scope"); paramName.AppendInt(i); rv = statement->BindUTF8StringByName(paramName, quotaKey); NS_ENSURE_SUCCESS(rv, rv); } rv = statement->Execute(); NS_ENSURE_SUCCESS(rv, rv); MarkAllScopesDirty(); return NS_OK; }
nsresult nsSVGFilterInstance::BuildPrimitives(nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs, nsTArray<RefPtr<SourceSurface>>& aInputImages) { mSourceGraphicIndex = GetLastResultIndex(aPrimitiveDescrs); // Clip previous filter's output to this filter's filter region. if (mSourceGraphicIndex >= 0) { FilterPrimitiveDescription& sourceDescr = aPrimitiveDescrs[mSourceGraphicIndex]; sourceDescr.SetPrimitiveSubregion(sourceDescr.PrimitiveSubregion().Intersect(mFilterSpaceBounds)); } // Get the filter primitive elements. nsTArray<RefPtr<nsSVGFE> > primitives; for (nsIContent* child = mFilterElement->nsINode::GetFirstChild(); child; child = child->GetNextSibling()) { RefPtr<nsSVGFE> primitive; CallQueryInterface(child, (nsSVGFE**)getter_AddRefs(primitive)); if (primitive) { primitives.AppendElement(primitive); } } // Maps source image name to source index. nsDataHashtable<nsStringHashKey, int32_t> imageTable(8); // The principal that we check principals of any loaded images against. nsCOMPtr<nsIPrincipal> principal = mTargetContent->NodePrincipal(); bool filterInputIsTainted = IsFilterInputTainted(mTargetContent); for (uint32_t primitiveElementIndex = 0; primitiveElementIndex < primitives.Length(); ++primitiveElementIndex) { nsSVGFE* filter = primitives[primitiveElementIndex]; AutoTArray<int32_t,2> sourceIndices; nsresult rv = GetSourceIndices(filter, aPrimitiveDescrs, imageTable, sourceIndices); if (NS_FAILED(rv)) { return rv; } IntRect primitiveSubregion = ComputeFilterPrimitiveSubregion(filter, aPrimitiveDescrs, sourceIndices); nsTArray<bool> sourcesAreTainted; GetInputsAreTainted(aPrimitiveDescrs, sourceIndices, filterInputIsTainted, sourcesAreTainted); FilterPrimitiveDescription descr = filter->GetPrimitiveDescription(this, primitiveSubregion, sourcesAreTainted, aInputImages); descr.SetIsTainted(filter->OutputIsTainted(sourcesAreTainted, principal)); descr.SetFilterSpaceBounds(mFilterSpaceBounds); descr.SetPrimitiveSubregion(primitiveSubregion.Intersect(descr.FilterSpaceBounds())); for (uint32_t i = 0; i < sourceIndices.Length(); i++) { int32_t inputIndex = sourceIndices[i]; descr.SetInputPrimitive(i, inputIndex); ColorSpace inputColorSpace = inputIndex >= 0 ? aPrimitiveDescrs[inputIndex].OutputColorSpace() : ColorSpace(ColorSpace::SRGB); ColorSpace desiredInputColorSpace = filter->GetInputColorSpace(i, inputColorSpace); descr.SetInputColorSpace(i, desiredInputColorSpace); if (i == 0) { // the output color space is whatever in1 is if there is an in1 descr.SetOutputColorSpace(desiredInputColorSpace); } } if (sourceIndices.Length() == 0) { descr.SetOutputColorSpace(filter->GetOutputColorSpace()); } aPrimitiveDescrs.AppendElement(descr); uint32_t primitiveDescrIndex = aPrimitiveDescrs.Length() - 1; nsAutoString str; filter->GetResultImageName().GetAnimValue(str, filter); imageTable.Put(str, primitiveDescrIndex); } return NS_OK; }
// A U2F Sign operation creates a signature over the "param" arguments (plus // some other stuff) using the private key indicated in the key handle argument. // // The format of the signed data is as follows: // // 32 Application parameter // 1 User presence (0x01) // 4 Counter // 32 Challenge parameter // // The format of the signature data is as follows: // // 1 User presence // 4 Counter // * Signature // nsresult U2FSoftTokenManager::Sign(nsTArray<uint8_t>& aApplication, nsTArray<uint8_t>& aChallenge, nsTArray<uint8_t>& aKeyHandle, nsTArray<uint8_t>& aSignature) { nsNSSShutDownPreventionLock locker; if (NS_WARN_IF(isAlreadyShutDown())) { return NS_ERROR_NOT_AVAILABLE; } MOZ_ASSERT(mInitialized); if (NS_WARN_IF(!mInitialized)) { nsresult rv = Init(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } MOZ_ASSERT(mWrappingKey); UniquePK11SlotInfo slot(PK11_GetInternalSlot()); MOZ_ASSERT(slot.get()); if (NS_WARN_IF((aChallenge.Length() != kParamLen) || (aApplication.Length() != kParamLen))) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Parameter lengths are wrong! challenge=%d app=%d expected=%d", (uint32_t)aChallenge.Length(), (uint32_t)aApplication.Length(), kParamLen)); return NS_ERROR_ILLEGAL_VALUE; } // Decode the key handle UniqueSECKEYPrivateKey privKey = PrivateKeyFromKeyHandle(slot, mWrappingKey, aKeyHandle.Elements(), aKeyHandle.Length(), aApplication.Elements(), aApplication.Length(), locker); if (NS_WARN_IF(!privKey.get())) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Couldn't get the priv key!")); return NS_ERROR_FAILURE; } // Increment the counter and turn it into a SECItem mCounter += 1; ScopedAutoSECItem counterItem(4); counterItem.data[0] = (mCounter >> 24) & 0xFF; counterItem.data[1] = (mCounter >> 16) & 0xFF; counterItem.data[2] = (mCounter >> 8) & 0xFF; counterItem.data[3] = (mCounter >> 0) & 0xFF; uint32_t counter = mCounter; AbstractThread::MainThread()->Dispatch(NS_NewRunnableFunction( [counter] () { MOZ_ASSERT(NS_IsMainThread()); Preferences::SetUint(PREF_U2F_NSSTOKEN_COUNTER, counter); })); // Compute the signature mozilla::dom::CryptoBuffer signedDataBuf; if (NS_WARN_IF(!signedDataBuf.SetCapacity(1 + 4 + (2 * kParamLen), mozilla::fallible))) { return NS_ERROR_OUT_OF_MEMORY; } // It's OK to ignore the return values here because we're writing into // pre-allocated space signedDataBuf.AppendElements(aApplication.Elements(), aApplication.Length(), mozilla::fallible); signedDataBuf.AppendElement(0x01, mozilla::fallible); signedDataBuf.AppendSECItem(counterItem); signedDataBuf.AppendElements(aChallenge.Elements(), aChallenge.Length(), mozilla::fallible); if (MOZ_LOG_TEST(gNSSTokenLog, LogLevel::Debug)) { nsAutoCString base64; nsresult rv = Base64URLEncode(signedDataBuf.Length(), signedDataBuf.Elements(), Base64URLEncodePaddingPolicy::Omit, base64); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; } MOZ_LOG(gNSSTokenLog, LogLevel::Debug, ("U2F Token signing bytes (base64): %s", base64.get())); } ScopedAutoSECItem signatureItem; SECStatus srv = SEC_SignData(&signatureItem, signedDataBuf.Elements(), signedDataBuf.Length(), privKey.get(), SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE); if (NS_WARN_IF(srv != SECSuccess)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Signature failure: %d", PORT_GetError())); return NS_ERROR_FAILURE; } // Assemble the signature data into a buffer for return mozilla::dom::CryptoBuffer signatureBuf; if (NS_WARN_IF(!signatureBuf.SetCapacity(1 + counterItem.len + signatureItem.len, mozilla::fallible))) { return NS_ERROR_OUT_OF_MEMORY; } // It's OK to ignore the return values here because we're writing into // pre-allocated space signatureBuf.AppendElement(0x01, mozilla::fallible); signatureBuf.AppendSECItem(counterItem); signatureBuf.AppendSECItem(signatureItem); aSignature = signatureBuf; return NS_OK; }
void SortLayersBy3DZOrder(nsTArray<Layer*>& aLayers) { uint32_t nodeCount = aLayers.Length(); if (nodeCount > MAX_SORTABLE_LAYERS) { return; } DirectedGraph<Layer*> graph; #ifdef DEBUG if (gDumpLayerSortList) { for (uint32_t i = 0; i < nodeCount; i++) { if (aLayers.ElementAt(i)->GetDebugColorIndex() == 0) { aLayers.ElementAt(i)->SetDebugColorIndex(gColorIndex++); if (gColorIndex > 7) { gColorIndex = 1; } } } fprintf(stderr, " --- Layers before sorting: --- \n"); DumpLayerList(aLayers); } #endif // Iterate layers and determine edges. for (uint32_t i = 0; i < nodeCount; i++) { for (uint32_t j = i + 1; j < nodeCount; j++) { Layer* a = aLayers.ElementAt(i); Layer* b = aLayers.ElementAt(j); LayerSortOrder order = CompareDepth(a, b); if (order == ABeforeB) { graph.AddEdge(a, b); } else if (order == BBeforeA) { graph.AddEdge(b, a); } } } #ifdef DEBUG if (gDumpLayerSortList) { fprintf(stderr, " --- Edge List: --- \n"); DumpEdgeList(graph); } #endif // Build a new array using the graph. nsTArray<Layer*> noIncoming; nsTArray<Layer*> sortedList; // Make a list of all layers with no incoming edges. noIncoming.AppendElements(aLayers); const nsTArray<DirectedGraph<Layer*>::Edge>& edges = graph.GetEdgeList(); for (uint32_t i = 0; i < edges.Length(); i++) { noIncoming.RemoveElement(edges.ElementAt(i).mTo); } // Move each item without incoming edges into the sorted list, // and remove edges from it. do { if (!noIncoming.IsEmpty()) { uint32_t last = noIncoming.Length() - 1; Layer* layer = noIncoming.ElementAt(last); MOZ_ASSERT(layer); // don't let null layer pointers sneak into sortedList noIncoming.RemoveElementAt(last); sortedList.AppendElement(layer); nsTArray<DirectedGraph<Layer*>::Edge> outgoing; graph.GetEdgesFrom(layer, outgoing); for (uint32_t i = 0; i < outgoing.Length(); i++) { DirectedGraph<Layer*>::Edge edge = outgoing.ElementAt(i); graph.RemoveEdge(edge); if (!graph.NumEdgesTo(edge.mTo)) { // If this node also has no edges now, add it to the list noIncoming.AppendElement(edge.mTo); } } } // If there are no nodes without incoming edges, but there // are still edges, then we have a cycle. if (noIncoming.IsEmpty() && graph.GetEdgeCount()) { // Find the node with the least incoming edges. uint32_t minEdges = UINT_MAX; Layer* minNode = nullptr; for (uint32_t i = 0; i < aLayers.Length(); i++) { uint32_t edgeCount = graph.NumEdgesTo(aLayers.ElementAt(i)); if (edgeCount && edgeCount < minEdges) { minEdges = edgeCount; minNode = aLayers.ElementAt(i); if (minEdges == 1) { break; } } } if (minNode) { // Remove all of them! graph.RemoveEdgesTo(minNode); noIncoming.AppendElement(minNode); } } } while (!noIncoming.IsEmpty()); NS_ASSERTION(!graph.GetEdgeCount(), "Cycles detected!"); #ifdef DEBUG if (gDumpLayerSortList) { fprintf(stderr, " --- Layers after sorting: --- \n"); DumpLayerList(sortedList); } #endif aLayers.Clear(); aLayers.AppendElements(sortedList); }
bool DBusWatcher::Poll() { int res = TEMP_FAILURE_RETRY(poll(mPollData.Elements(), mPollData.Length(), -1)); NS_ENSURE_TRUE(res > 0, false); bool continueThread = true; nsTArray<pollfd>::size_type i = 0; while (i < mPollData.Length()) { if (mPollData[i].revents == POLLIN) { if (mPollData[i].fd == mControlFdR.get()) { char data; res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &data, sizeof(data))); NS_ENSURE_TRUE(res > 0, false); switch (data) { case DBUS_EVENT_LOOP_EXIT: continueThread = false; break; case DBUS_EVENT_LOOP_ADD: HandleWatchAdd(); break; case DBUS_EVENT_LOOP_REMOVE: HandleWatchRemove(); // don't increment i, or we'll skip one element continue; case DBUS_EVENT_LOOP_WAKEUP: NS_ProcessPendingEvents(NS_GetCurrentThread(), PR_INTERVAL_NO_TIMEOUT); break; default: #if DEBUG nsCString warning("unknown command "); warning.AppendInt(data); NS_WARNING(warning.get()); #endif break; } } else { short events = mPollData[i].revents; mPollData[i].revents = 0; dbus_watch_handle(mWatchData[i], UnixEventsToDBusFlags(events)); DBusDispatchStatus dbusDispatchStatus; do { dbusDispatchStatus = dbus_connection_dispatch(GetConnection()); } while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS); // Break at this point since we don't know if the operation // was destructive break; } } ++i; } return continueThread; }
NS_IMETHODIMP nsCommandLine::GetLength(int32_t *aResult) { *aResult = int32_t(mArgs.Length()); return NS_OK; }
int32_t GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray<GfxDriverInfo>& info, nsAString& aSuggestedVersion, int32_t aFeature, nsACString& aFailureId, OperatingSystem os) { int32_t status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; uint32_t i = 0; for (; i < info.Length(); i++) { // Do the operating system check first, no point in getting the driver // info if we won't need to use it. If the OS of the system we are running // on is unknown, we still let DRIVER_OS_ALL catch and disable it; // if the OS of the downloadable entry is unknown, we skip the entry // as invalid. if (info[i].mOperatingSystem == DRIVER_OS_UNKNOWN || (info[i].mOperatingSystem != DRIVER_OS_ALL && info[i].mOperatingSystem != os)) { continue; } if (info[i].mOperatingSystemVersion && info[i].mOperatingSystemVersion != OperatingSystemVersion()) { continue; } // XXX: it would be better not to do this everytime round the loop nsAutoString adapterVendorID; nsAutoString adapterDeviceID; nsAutoString adapterDriverVersionString; if (info[i].mGpu2) { if (NS_FAILED(GetAdapterVendorID2(adapterVendorID)) || NS_FAILED(GetAdapterDeviceID2(adapterDeviceID)) || NS_FAILED(GetAdapterDriverVersion2(adapterDriverVersionString))) { return 0; } } else { if (NS_FAILED(GetAdapterVendorID(adapterVendorID)) || NS_FAILED(GetAdapterDeviceID(adapterDeviceID)) || NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString))) { return 0; } } #if defined(XP_WIN) || defined(ANDROID) uint64_t driverVersion; ParseDriverVersion(adapterDriverVersionString, &driverVersion); #endif if (!info[i].mAdapterVendor.Equals(GfxDriverInfo::GetDeviceVendor(VendorAll), nsCaseInsensitiveStringComparator()) && !info[i].mAdapterVendor.Equals(adapterVendorID, nsCaseInsensitiveStringComparator())) { continue; } if (info[i].mDevices != GfxDriverInfo::allDevices && info[i].mDevices->Length()) { bool deviceMatches = false; for (uint32_t j = 0; j < info[i].mDevices->Length(); j++) { if ((*info[i].mDevices)[j].Equals(adapterDeviceID, nsCaseInsensitiveStringComparator())) { deviceMatches = true; break; } } if (!deviceMatches) { continue; } } bool match = false; if (!info[i].mHardware.IsEmpty() && !info[i].mHardware.Equals(Hardware())) { continue; } if (!info[i].mModel.IsEmpty() && !info[i].mModel.Equals(Model())) { continue; } if (!info[i].mProduct.IsEmpty() && !info[i].mProduct.Equals(Product())) { continue; } if (!info[i].mManufacturer.IsEmpty() && !info[i].mManufacturer.Equals(Manufacturer())) { continue; } #if defined(XP_WIN) || defined(ANDROID) switch (info[i].mComparisonOp) { case DRIVER_LESS_THAN: match = driverVersion < info[i].mDriverVersion; break; case DRIVER_LESS_THAN_OR_EQUAL: match = driverVersion <= info[i].mDriverVersion; break; case DRIVER_GREATER_THAN: match = driverVersion > info[i].mDriverVersion; break; case DRIVER_GREATER_THAN_OR_EQUAL: match = driverVersion >= info[i].mDriverVersion; break; case DRIVER_EQUAL: match = driverVersion == info[i].mDriverVersion; break; case DRIVER_NOT_EQUAL: match = driverVersion != info[i].mDriverVersion; break; case DRIVER_BETWEEN_EXCLUSIVE: match = driverVersion > info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax; break; case DRIVER_BETWEEN_INCLUSIVE: match = driverVersion >= info[i].mDriverVersion && driverVersion <= info[i].mDriverVersionMax; break; case DRIVER_BETWEEN_INCLUSIVE_START: match = driverVersion >= info[i].mDriverVersion && driverVersion < info[i].mDriverVersionMax; break; case DRIVER_COMPARISON_IGNORED: // We don't have a comparison op, so we match everything. match = true; break; default: NS_WARNING("Bogus op in GfxDriverInfo"); break; } #else // We don't care what driver version it was. We only check OS version and if // the device matches. match = true; #endif if (match || info[i].mDriverVersion == GfxDriverInfo::allDriverVersions) { if (info[i].mFeature == GfxDriverInfo::allFeatures || info[i].mFeature == aFeature) { status = info[i].mFeatureStatus; if (!info[i].mRuleId.IsEmpty()) { aFailureId = info[i].mRuleId.get(); } else { aFailureId = "FEATURE_FAILURE_DL_BLACKLIST_NO_ID"; } break; } } } #if defined(XP_WIN) // As a very special case, we block D2D on machines with an NVidia 310M GPU // as either the primary or secondary adapter. D2D is also blocked when the // NV 310M is the primary adapter (using the standard blocklisting mechanism). // If the primary GPU already matched something in the blocklist then we // ignore this special rule. See bug 1008759. if (status == nsIGfxInfo::FEATURE_STATUS_UNKNOWN && (aFeature == nsIGfxInfo::FEATURE_DIRECT2D)) { nsAutoString adapterVendorID2; nsAutoString adapterDeviceID2; if ((!NS_FAILED(GetAdapterVendorID2(adapterVendorID2))) && (!NS_FAILED(GetAdapterDeviceID2(adapterDeviceID2)))) { nsAString &nvVendorID = (nsAString &)GfxDriverInfo::GetDeviceVendor(VendorNVIDIA); const nsString nv310mDeviceId = NS_LITERAL_STRING("0x0A70"); if (nvVendorID.Equals(adapterVendorID2, nsCaseInsensitiveStringComparator()) && nv310mDeviceId.Equals(adapterDeviceID2, nsCaseInsensitiveStringComparator())) { status = nsIGfxInfo::FEATURE_BLOCKED_DEVICE; aFailureId = "FEATURE_FAILURE_D2D_NV310M_BLOCK"; } } } // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object // back to the Windows handler, so we must handle this here. if (status == FEATURE_BLOCKED_DRIVER_VERSION) { if (info[i].mSuggestedVersion) { aSuggestedVersion.AppendPrintf("%s", info[i].mSuggestedVersion); } else if (info[i].mComparisonOp == DRIVER_LESS_THAN && info[i].mDriverVersion != GfxDriverInfo::allDriverVersions) { aSuggestedVersion.AppendPrintf("%lld.%lld.%lld.%lld", (info[i].mDriverVersion & 0xffff000000000000) >> 48, (info[i].mDriverVersion & 0x0000ffff00000000) >> 32, (info[i].mDriverVersion & 0x00000000ffff0000) >> 16, (info[i].mDriverVersion & 0x000000000000ffff)); } }
nsresult nsDOMWorkerScriptLoader::LoadScripts(JSContext* aCx, const nsTArray<nsString>& aURLs, PRBool aForWorker) { NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); NS_ASSERTION(aCx, "Null context!"); mTarget = NS_GetCurrentThread(); NS_ASSERTION(mTarget, "This should never be null!"); if (mCanceled) { return NS_ERROR_ABORT; } mForWorker = aForWorker; mScriptCount = aURLs.Length(); if (!mScriptCount) { return NS_ERROR_INVALID_ARG; } // Do all the memory work for these arrays now rather than checking for // failures all along the way. PRBool success = mLoadInfos.SetCapacity(mScriptCount); NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY); // Need one runnable per script and then an extra for the finished // notification. success = mPendingRunnables.SetCapacity(mScriptCount + 1); NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY); for (PRUint32 index = 0; index < mScriptCount; index++) { ScriptLoadInfo* newInfo = mLoadInfos.AppendElement(); NS_ASSERTION(newInfo, "Shouldn't fail if SetCapacity succeeded above!"); newInfo->url.Assign(aURLs[index]); if (newInfo->url.IsEmpty()) { return NS_ERROR_INVALID_ARG; } success = newInfo->scriptObj.Hold(aCx); NS_ENSURE_TRUE(success, NS_ERROR_FAILURE); } // Don't want timeouts, etc., from queuing up while we're waiting on the // network or compiling. AutoSuspendWorkerEvents aswe(this); nsresult rv = DoRunLoop(aCx); if (NS_FAILED(rv)) { return rv; } // Verify that all scripts downloaded and compiled. rv = VerifyScripts(aCx); if (NS_FAILED(rv)) { return rv; } rv = ExecuteScripts(aCx); if (NS_FAILED(rv)) { return rv; } return NS_OK; }
nsresult nsHyphenator::Hyphenate(const nsAString& aString, nsTArray<bool>& aHyphens) { if (!aHyphens.SetLength(aString.Length())) { return NS_ERROR_OUT_OF_MEMORY; } memset(aHyphens.Elements(), false, aHyphens.Length()); bool inWord = false; uint32_t wordStart = 0, wordLimit = 0; uint32_t chLen; for (uint32_t i = 0; i < aString.Length(); i += chLen) { uint32_t 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 = mozilla::unicode::GetGenCategory(ch); if (cat == nsIUGenCategory::kLetter || cat == nsIUGenCategory::kMark) { if (!inWord) { inWord = 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 = nullptr; int *pos = nullptr; int *cut = nullptr; int err = hnj_hyphen_hyphenate2((HyphenDict*)mDict, utf8.BeginReading(), utf8.Length(), utf8hyphens.Elements(), nullptr, &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] = true; } cur++; if (cur < end && NS_IS_LOW_SURROGATE(*cur) && NS_IS_HIGH_SURROGATE(*(cur-1))) { cur++; } hyphPtr++; } } } inWord = false; } return NS_OK; }
static void ValidateTreePointers(nsTArray<RefPtr<Layer> >& aLayers) { for (uint32_t i = 0; i < aLayers.Length(); i++) { ValidateTreePointers(aLayers[i]); } }
// NOTE: This method represents a theoretical way to use a U2F-compliant token // to produce the result of the WebAuthn MakeCredential method. The exact // mapping of U2F data fields to WebAuthn data fields is still a matter of // ongoing discussion, and this should not be taken as anything but a point-in- // time possibility. void WebAuthentication::U2FAuthMakeCredential( const RefPtr<CredentialRequest>& aRequest, const Authenticator& aToken, CryptoBuffer& aRpIdHash, const nsACString& aClientData, CryptoBuffer& aClientDataHash, const Account& aAccount, const nsTArray<ScopedCredentialParameters>& aNormalizedParams, const Optional<Sequence<ScopedCredentialDescriptor>>& aExcludeList, const WebAuthnExtensions& aExtensions) { MOZ_LOG(gWebauthLog, LogLevel::Debug, ("U2FAuthMakeCredential")); aRequest->AddActiveToken(__func__); // 5.1.1 When this operation is invoked, the authenticator must perform the // following procedure: // 5.1.1.a Check if all the supplied parameters are syntactically well- // formed and of the correct length. If not, return an error code equivalent // to UnknownError and terminate the operation. if ((aRpIdHash.Length() != SHA256_LENGTH) || (aClientDataHash.Length() != SHA256_LENGTH)) { aRequest->SetFailure(NS_ERROR_DOM_UNKNOWN_ERR); return; } // 5.1.1.b Check if at least one of the specified combinations of // ScopedCredentialType and cryptographic parameters is supported. If not, // return an error code equivalent to NotSupportedError and terminate the // operation. bool isValidCombination = false; for (size_t a = 0; a < aNormalizedParams.Length(); ++a) { if (aNormalizedParams[a].mType == ScopedCredentialType::ScopedCred && aNormalizedParams[a].mAlgorithm.IsString() && aNormalizedParams[a].mAlgorithm.GetAsString().EqualsLiteral( WEBCRYPTO_NAMED_CURVE_P256)) { isValidCombination = true; break; } } if (!isValidCombination) { aRequest->SetFailure(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return; } // 5.1.1.c Check if a credential matching any of the supplied // ScopedCredential identifiers is present on this authenticator. If so, // return an error code equivalent to NotAllowedError and terminate the // operation. if (aExcludeList.WasPassed()) { const Sequence<ScopedCredentialDescriptor>& list = aExcludeList.Value(); for (const ScopedCredentialDescriptor& scd : list) { bool isRegistered = false; uint8_t *data; uint32_t len; // data is owned by the Descriptor, do don't free it here. if (NS_FAILED(ScopedCredentialGetData(scd, &data, &len))) { aRequest->SetFailure(NS_ERROR_DOM_UNKNOWN_ERR); return; } nsresult rv = aToken->IsRegistered(data, len, &isRegistered); if (NS_WARN_IF(NS_FAILED(rv))) { aRequest->SetFailure(rv); return; } if (isRegistered) { aRequest->SetFailure(NS_ERROR_DOM_NOT_ALLOWED_ERR); return; } } } // 5.1.1.d Prompt the user for consent to create a new credential. The // prompt for obtaining this consent is shown by the authenticator if it has // its own output capability, or by the user agent otherwise. If the user // denies consent, return an error code equivalent to NotAllowedError and // terminate the operation. // 5.1.1.d Once user consent has been obtained, generate a new credential // object // 5.1.1.e If any error occurred while creating the new credential object, // return an error code equivalent to UnknownError and terminate the // operation. // 5.1.1.f Process all the supported extensions requested by the client, and // generate an attestation statement. If no authority key is available to // sign such an attestation statement, then the authenticator performs self // attestation of the credential with its own private key. For more details // on attestation, see §5.3 Credential Attestation Statements. // No extensions are supported // 4.1.1.11 While issuedRequests is not empty, perform the following actions // depending upon the adjustedTimeout timer and responses from the // authenticators: // 4.1.1.11.a If the adjustedTimeout timer expires, then for each entry in // issuedRequests invoke the authenticatorCancel operation on that // authenticator and remove its entry from the list. uint8_t* buffer; uint32_t bufferlen; nsresult rv = aToken->Register(aRpIdHash.Elements(), aRpIdHash.Length(), aClientDataHash.Elements(), aClientDataHash.Length(), &buffer, &bufferlen); // 4.1.1.11.b If any authenticator returns a status indicating that the user // cancelled the operation, delete that authenticator’s entry from // issuedRequests. For each remaining entry in issuedRequests invoke the // authenticatorCancel operation on that authenticator and remove its entry // from the list. // 4.1.1.11.c If any authenticator returns an error status, delete the // corresponding entry from issuedRequests. if (NS_WARN_IF(NS_FAILED(rv))) { aRequest->SetFailure(NS_ERROR_DOM_UNKNOWN_ERR); return; } MOZ_ASSERT(buffer); CryptoBuffer regData; if (NS_WARN_IF(!regData.Assign(buffer, bufferlen))) { free(buffer); aRequest->SetFailure(NS_ERROR_OUT_OF_MEMORY); return; } free(buffer); // Decompose the U2F registration packet CryptoBuffer pubKeyBuf; CryptoBuffer keyHandleBuf; CryptoBuffer attestationCertBuf; CryptoBuffer signatureBuf; rv = U2FDecomposeRegistrationResponse(regData, pubKeyBuf, keyHandleBuf, attestationCertBuf, signatureBuf); if (NS_WARN_IF(NS_FAILED(rv))) { aRequest->SetFailure(rv); return; } // Sign the aClientDataHash explicitly to get the format needed for // the AuthenticatorData parameter of WebAuthnAttestation. This might // be temporary while the spec settles down how to incorporate U2F. rv = aToken->Sign(aRpIdHash.Elements(), aRpIdHash.Length(), aClientDataHash.Elements(), aClientDataHash.Length(), keyHandleBuf.Elements(), keyHandleBuf.Length(), &buffer, &bufferlen); if (NS_WARN_IF(NS_FAILED(rv))) { aRequest->SetFailure(rv); return; } MOZ_ASSERT(buffer); CryptoBuffer signatureData; if (NS_WARN_IF(!signatureData.Assign(buffer, bufferlen))) { free(buffer); aRequest->SetFailure(NS_ERROR_OUT_OF_MEMORY); return; } free(buffer); CryptoBuffer clientDataBuf; if (!clientDataBuf.Assign(aClientData)) { aRequest->SetFailure(NS_ERROR_OUT_OF_MEMORY); return; } CryptoBuffer authenticatorDataBuf; rv = U2FAssembleAuthenticatorData(authenticatorDataBuf, aRpIdHash, signatureData); if (NS_WARN_IF(NS_FAILED(rv))) { aRequest->SetFailure(rv); return; } // 4.1.1.11.d If any authenticator indicates success: // 4.1.1.11.d.1 Remove this authenticator’s entry from issuedRequests. // 4.1.1.11.d.2 Create a new ScopedCredentialInfo object named value and // populate its fields with the values returned from the authenticator as well // as the clientDataJSON computed earlier. RefPtr<ScopedCredential> credential = new ScopedCredential(this); credential->SetType(ScopedCredentialType::ScopedCred); credential->SetId(keyHandleBuf); RefPtr<WebAuthnAttestation> attestation = new WebAuthnAttestation(this); attestation->SetFormat(NS_LITERAL_STRING("u2f")); attestation->SetClientData(clientDataBuf); attestation->SetAuthenticatorData(authenticatorDataBuf); attestation->SetAttestation(regData); CredentialPtr info = new ScopedCredentialInfo(this); info->SetCredential(credential); info->SetAttestation(attestation); // 4.1.1.11.d.3 For each remaining entry in issuedRequests invoke the // authenticatorCancel operation on that authenticator and remove its entry // from the list. // 4.1.1.11.d.4 Resolve promise with value and terminate this algorithm. aRequest->SetSuccess(info); }
nsresult nsCORSPreflightListener::CheckPreflightRequestApproved(nsIRequest* aRequest) { nsresult status; nsresult rv = aRequest->GetStatus(&status); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(status, status); // Test that things worked on a HTTP level nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest); nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(aRequest); NS_ENSURE_STATE(internal); bool succeedded; rv = http->GetRequestSucceeded(&succeedded); if (NS_FAILED(rv) || !succeedded) { LogBlockedRequest(aRequest, "CORSPreflightDidNotSucceed", nullptr); return NS_ERROR_DOM_BAD_URI; } nsAutoCString headerVal; // The "Access-Control-Allow-Methods" header contains a comma separated // list of method names. http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Allow-Methods"), headerVal); bool foundMethod = mPreflightMethod.EqualsLiteral("GET") || mPreflightMethod.EqualsLiteral("HEAD") || mPreflightMethod.EqualsLiteral("POST"); nsCCharSeparatedTokenizer methodTokens(headerVal, ','); while(methodTokens.hasMoreTokens()) { const nsDependentCSubstring& method = methodTokens.nextToken(); if (method.IsEmpty()) { continue; } if (!NS_IsValidHTTPToken(method)) { LogBlockedRequest(aRequest, "CORSInvalidAllowMethod", NS_ConvertUTF8toUTF16(method).get()); return NS_ERROR_DOM_BAD_URI; } foundMethod |= mPreflightMethod.Equals(method); } if (!foundMethod) { LogBlockedRequest(aRequest, "CORSMethodNotFound", nullptr); return NS_ERROR_DOM_BAD_URI; } // The "Access-Control-Allow-Headers" header contains a comma separated // list of header names. http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Allow-Headers"), headerVal); nsTArray<nsCString> headers; nsCCharSeparatedTokenizer headerTokens(headerVal, ','); while(headerTokens.hasMoreTokens()) { const nsDependentCSubstring& header = headerTokens.nextToken(); if (header.IsEmpty()) { continue; } if (!NS_IsValidHTTPToken(header)) { LogBlockedRequest(aRequest, "CORSInvalidAllowHeader", NS_ConvertUTF8toUTF16(header).get()); return NS_ERROR_DOM_BAD_URI; } headers.AppendElement(header); } for (uint32_t i = 0; i < mPreflightHeaders.Length(); ++i) { if (!headers.Contains(mPreflightHeaders[i], nsCaseInsensitiveCStringArrayComparator())) { LogBlockedRequest(aRequest, "CORSMissingAllowHeaderFromPreflight", NS_ConvertUTF8toUTF16(mPreflightHeaders[i]).get()); return NS_ERROR_DOM_BAD_URI; } } return NS_OK; }
nsresult GfxInfo::GetFeatureStatusImpl(int32_t aFeature, int32_t *aStatus, nsAString & aSuggestedDriverVersion, const nsTArray<GfxDriverInfo>& aDriverInfo, OperatingSystem* aOS /* = nullptr */) { NS_ENSURE_ARG_POINTER(aStatus); aSuggestedDriverVersion.SetIsVoid(true); OperatingSystem os = WindowsVersionToOperatingSystem(mWindowsVersion); *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN; if (aOS) *aOS = os; // Don't evaluate special cases if we're checking the downloaded blocklist. if (!aDriverInfo.Length()) { nsAutoString adapterVendorID; nsAutoString adapterDeviceID; nsAutoString adapterDriverVersionString; if (NS_FAILED(GetAdapterVendorID(adapterVendorID)) || NS_FAILED(GetAdapterDeviceID(adapterDeviceID)) || NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString))) { return NS_ERROR_FAILURE; } if (!adapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorIntel), nsCaseInsensitiveStringComparator()) && !adapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), nsCaseInsensitiveStringComparator()) && !adapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorAMD), nsCaseInsensitiveStringComparator()) && !adapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorATI), nsCaseInsensitiveStringComparator()) && !adapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorMicrosoft), nsCaseInsensitiveStringComparator()) && // FIXME - these special hex values are currently used in xpcshell tests introduced by // bug 625160 patch 8/8. Maybe these tests need to be adjusted now that we're only whitelisting // intel/ati/nvidia. !adapterVendorID.LowerCaseEqualsLiteral("0xabcd") && !adapterVendorID.LowerCaseEqualsLiteral("0xdcba") && !adapterVendorID.LowerCaseEqualsLiteral("0xabab") && !adapterVendorID.LowerCaseEqualsLiteral("0xdcdc")) { *aStatus = FEATURE_BLOCKED_DEVICE; return NS_OK; } uint64_t driverVersion; if (!ParseDriverVersion(adapterDriverVersionString, &driverVersion)) { return NS_ERROR_FAILURE; } // special-case the WinXP test slaves: they have out-of-date drivers, but we still want to // whitelist them, actually we do know that this combination of device and driver version // works well. if (mWindowsVersion == kWindowsXP && adapterVendorID.Equals(GfxDriverInfo::GetDeviceVendor(VendorNVIDIA), nsCaseInsensitiveStringComparator()) && adapterDeviceID.LowerCaseEqualsLiteral("0x0861") && // GeForce 9400 driverVersion == V(6,14,11,7756)) { *aStatus = FEATURE_STATUS_OK; return NS_OK; } // Windows Server 2003 should be just like Windows XP for present purpose, but still has a different version number. // OTOH Windows Server 2008 R1 and R2 already have the same version numbers as Vista and Seven respectively if (os == DRIVER_OS_WINDOWS_SERVER_2003) os = DRIVER_OS_WINDOWS_XP; if (mHasDriverVersionMismatch) { if (aFeature == nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS || aFeature == nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS || aFeature == nsIGfxInfo::FEATURE_DIRECT2D || aFeature == nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS) { *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION; return NS_OK; } } } return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, &os); }
nsresult nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel, nsICorsPreflightCallback* aCallback, nsTArray<nsCString>& aUnsafeHeaders, nsIChannel** aPreflightChannel) { *aPreflightChannel = nullptr; if (gDisableCORS) { LogBlockedRequest(aRequestChannel, "CORSDisabled", nullptr); return NS_ERROR_DOM_BAD_URI; } nsAutoCString method; nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequestChannel)); NS_ENSURE_TRUE(httpChannel, NS_ERROR_UNEXPECTED); httpChannel->GetRequestMethod(method); nsCOMPtr<nsIURI> uri; nsresult rv = NS_GetFinalChannelURI(aRequestChannel, getter_AddRefs(uri)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsILoadInfo> originalLoadInfo = aRequestChannel->GetLoadInfo(); MOZ_ASSERT(originalLoadInfo, "can not perform CORS preflight without a loadInfo"); if (!originalLoadInfo) { return NS_ERROR_FAILURE; } MOZ_ASSERT(originalLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS, "how did we end up here?"); nsCOMPtr<nsIPrincipal> principal = originalLoadInfo->LoadingPrincipal(); bool withCredentials = originalLoadInfo->GetCookiePolicy() == nsILoadInfo::SEC_COOKIES_INCLUDE; nsPreflightCache::CacheEntry* entry = sPreflightCache ? sPreflightCache->GetEntry(uri, principal, withCredentials, false) : nullptr; if (entry && entry->CheckRequest(method, aUnsafeHeaders)) { aCallback->OnPreflightSucceeded(); return NS_OK; } // Either it wasn't cached or the cached result has expired. Build a // channel for the OPTIONS request. nsCOMPtr<nsILoadInfo> loadInfo = static_cast<mozilla::LoadInfo*> (originalLoadInfo.get())->CloneForNewRequest(); static_cast<mozilla::LoadInfo*>(loadInfo.get())->SetIsPreflight(); nsCOMPtr<nsILoadGroup> loadGroup; rv = aRequestChannel->GetLoadGroup(getter_AddRefs(loadGroup)); NS_ENSURE_SUCCESS(rv, rv); nsLoadFlags loadFlags; rv = aRequestChannel->GetLoadFlags(&loadFlags); NS_ENSURE_SUCCESS(rv, rv); // Preflight requests should never be intercepted by service workers and // are always anonymous. // NOTE: We ignore CORS checks on synthesized responses (see the CORS // preflights, then we need to extend the GetResponseSynthesized() check in // nsCORSListenerProxy::CheckRequestApproved()). If we change our behavior // here and allow service workers to intercept CORS preflights, then that // check won't be safe any more. loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER | nsIRequest::LOAD_ANONYMOUS; nsCOMPtr<nsIChannel> preflightChannel; rv = NS_NewChannelInternal(getter_AddRefs(preflightChannel), uri, loadInfo, loadGroup, nullptr, // aCallbacks loadFlags); NS_ENSURE_SUCCESS(rv, rv); // Set method and headers nsCOMPtr<nsIHttpChannel> preHttp = do_QueryInterface(preflightChannel); NS_ASSERTION(preHttp, "Failed to QI to nsIHttpChannel!"); rv = preHttp->SetRequestMethod(NS_LITERAL_CSTRING("OPTIONS")); NS_ENSURE_SUCCESS(rv, rv); rv = preHttp-> SetRequestHeader(NS_LITERAL_CSTRING("Access-Control-Request-Method"), method, false); NS_ENSURE_SUCCESS(rv, rv); nsTArray<nsCString> preflightHeaders; if (!aUnsafeHeaders.IsEmpty()) { for (uint32_t i = 0; i < aUnsafeHeaders.Length(); ++i) { preflightHeaders.AppendElement(); ToLowerCase(aUnsafeHeaders[i], preflightHeaders[i]); } preflightHeaders.Sort(); nsAutoCString headers; for (uint32_t i = 0; i < preflightHeaders.Length(); ++i) { if (i != 0) { headers += ','; } headers += preflightHeaders[i]; } rv = preHttp-> SetRequestHeader(NS_LITERAL_CSTRING("Access-Control-Request-Headers"), headers, false); NS_ENSURE_SUCCESS(rv, rv); } // Set up listener which will start the original channel RefPtr<nsCORSPreflightListener> preflightListener = new nsCORSPreflightListener(principal, aCallback, withCredentials, method, preflightHeaders); rv = preflightChannel->SetNotificationCallbacks(preflightListener); NS_ENSURE_SUCCESS(rv, rv); // Start preflight rv = preflightChannel->AsyncOpen2(preflightListener); NS_ENSURE_SUCCESS(rv, rv); // Return newly created preflight channel preflightChannel.forget(aPreflightChannel); return NS_OK; }
void nsCSSExpandedDataBlock::Compress(nsCSSCompressedDataBlock **aNormalBlock, nsCSSCompressedDataBlock **aImportantBlock, const nsTArray<uint32_t>& aOrder) { nsAutoPtr<nsCSSCompressedDataBlock> result_normal, result_important; uint32_t i_normal = 0, i_important = 0; uint32_t numPropsNormal, numPropsImportant; ComputeNumProps(&numPropsNormal, &numPropsImportant); result_normal = new(numPropsNormal) nsCSSCompressedDataBlock(numPropsNormal); if (numPropsImportant != 0) { result_important = new(numPropsImportant) nsCSSCompressedDataBlock(numPropsImportant); } else { result_important = nullptr; } /* * Save needless copying and allocation by copying the memory * corresponding to the stored data in the expanded block, and then * clearing the data in the expanded block. */ for (size_t i = 0; i < aOrder.Length(); i++) { nsCSSProperty iProp = static_cast<nsCSSProperty>(aOrder[i]); if (iProp >= eCSSProperty_COUNT) { // a custom property continue; } MOZ_ASSERT(mPropertiesSet.HasProperty(iProp), "aOrder identifies a property not in the expanded " "data block"); MOZ_ASSERT(!nsCSSProps::IsShorthand(iProp), "out of range"); bool important = mPropertiesImportant.HasProperty(iProp); nsCSSCompressedDataBlock *result = important ? result_important : result_normal; uint32_t* ip = important ? &i_important : &i_normal; nsCSSValue* val = PropertyAt(iProp); MOZ_ASSERT(val->GetUnit() != eCSSUnit_Null, "Null value while compressing"); result->SetPropertyAtIndex(*ip, iProp); result->RawCopyValueToIndex(*ip, val); new (val) nsCSSValue(); (*ip)++; result->mStyleBits |= nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]); } MOZ_ASSERT(numPropsNormal == i_normal, "bad numProps"); if (result_important) { MOZ_ASSERT(numPropsImportant == i_important, "bad numProps"); } #ifdef DEBUG { // assert that we didn't have any other properties on this expanded data // block that we didn't find in aOrder uint32_t numPropsInSet = 0; for (size_t iHigh = 0; iHigh < nsCSSPropertySet::kChunkCount; iHigh++) { if (!mPropertiesSet.HasPropertyInChunk(iHigh)) { continue; } for (size_t iLow = 0; iLow < nsCSSPropertySet::kBitsInChunk; iLow++) { if (mPropertiesSet.HasPropertyAt(iHigh, iLow)) { numPropsInSet++; } } } MOZ_ASSERT(numPropsNormal + numPropsImportant == numPropsInSet, "aOrder missing properties from the expanded data block"); } #endif ClearSets(); AssertInitialState(); *aNormalBlock = result_normal.forget(); *aImportantBlock = result_important.forget(); }
// A U2F Register operation causes a new key pair to be generated by the token. // The token then returns the public key of the key pair, and a handle to the // private key, which is a fancy way of saying "key wrapped private key", as // well as the generated attestation certificate and a signature using that // certificate's private key. // // The KeyHandleFromPrivateKey and PrivateKeyFromKeyHandle methods perform // the actual key wrap/unwrap operations. // // The format of the return registration data is as follows: // // Bytes Value // 1 0x05 // 65 public key // 1 key handle length // * key handle // ASN.1 attestation certificate // * attestation signature // nsresult U2FSoftTokenManager::Register(nsTArray<uint8_t>& aApplication, nsTArray<uint8_t>& aChallenge, /* out */ nsTArray<uint8_t>& aRegistration, /* out */ nsTArray<uint8_t>& aSignature) { nsNSSShutDownPreventionLock locker; if (NS_WARN_IF(isAlreadyShutDown())) { return NS_ERROR_NOT_AVAILABLE; } if (!mInitialized) { nsresult rv = Init(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } // We should already have a wrapping key MOZ_ASSERT(mWrappingKey); UniquePK11SlotInfo slot(PK11_GetInternalSlot()); MOZ_ASSERT(slot.get()); // Construct a one-time-use Attestation Certificate UniqueSECKEYPrivateKey attestPrivKey; UniqueCERTCertificate attestCert; nsresult rv = GetAttestationCertificate(slot, attestPrivKey, attestCert, locker); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; } MOZ_ASSERT(attestCert); MOZ_ASSERT(attestPrivKey); // Generate a new keypair; the private will be wrapped into a Key Handle UniqueSECKEYPrivateKey privKey; UniqueSECKEYPublicKey pubKey; rv = GenEcKeypair(slot, privKey, pubKey, locker); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; } // The key handle will be the result of keywrap(privKey, key=mWrappingKey) UniqueSECItem keyHandleItem = KeyHandleFromPrivateKey(slot, mWrappingKey, aApplication.Elements(), aApplication.Length(), privKey, locker); if (NS_WARN_IF(!keyHandleItem.get())) { return NS_ERROR_FAILURE; } // Sign the challenge using the Attestation privkey (from attestCert) mozilla::dom::CryptoBuffer signedDataBuf; if (NS_WARN_IF(!signedDataBuf.SetCapacity(1 + aApplication.Length() + aChallenge.Length() + keyHandleItem->len + kPublicKeyLen, mozilla::fallible))) { return NS_ERROR_OUT_OF_MEMORY; } // // It's OK to ignore the return values here because we're writing into // // pre-allocated space signedDataBuf.AppendElement(0x00, mozilla::fallible); signedDataBuf.AppendElements(aApplication, mozilla::fallible); signedDataBuf.AppendElements(aChallenge, mozilla::fallible); signedDataBuf.AppendSECItem(keyHandleItem.get()); signedDataBuf.AppendSECItem(pubKey->u.ec.publicValue); ScopedAutoSECItem signatureItem; SECStatus srv = SEC_SignData(&signatureItem, signedDataBuf.Elements(), signedDataBuf.Length(), attestPrivKey.get(), SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE); if (NS_WARN_IF(srv != SECSuccess)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Signature failure: %d", PORT_GetError())); return NS_ERROR_FAILURE; } // Serialize the registration data mozilla::dom::CryptoBuffer registrationBuf; if (NS_WARN_IF(!registrationBuf.SetCapacity(1 + kPublicKeyLen + 1 + keyHandleItem->len + attestCert.get()->derCert.len + signatureItem.len, mozilla::fallible))) { return NS_ERROR_OUT_OF_MEMORY; } registrationBuf.AppendElement(0x05, mozilla::fallible); registrationBuf.AppendSECItem(pubKey->u.ec.publicValue); registrationBuf.AppendElement(keyHandleItem->len, mozilla::fallible); registrationBuf.AppendSECItem(keyHandleItem.get()); registrationBuf.AppendSECItem(attestCert.get()->derCert); registrationBuf.AppendSECItem(signatureItem); aRegistration = registrationBuf; return NS_OK; }
/** * This Init method should only be called by C++ consumers. */ NS_IMETHODIMP nsWebSocket::Init(nsIPrincipal* aPrincipal, nsIScriptContext* aScriptContext, nsPIDOMWindow* aOwnerWindow, const nsAString& aURL, nsTArray<nsString> & protocolArray) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); nsresult rv; NS_ENSURE_ARG(aPrincipal); if (!PrefEnabled()) { return NS_ERROR_DOM_SECURITY_ERR; } mPrincipal = aPrincipal; mScriptContext = aScriptContext; if (aOwnerWindow) { mOwner = aOwnerWindow->IsOuterWindow() ? aOwnerWindow->GetCurrentInnerWindow() : aOwnerWindow; } else { mOwner = nsnull; } nsCOMPtr<nsIJSContextStack> stack = do_GetService("@mozilla.org/js/xpc/ContextStack;1"); JSContext* cx = nsnull; if (stack && NS_SUCCEEDED(stack->Peek(&cx)) && cx) { JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL); if (fp) { JSScript *script = JS_GetFrameScript(cx, fp); if (script) { mScriptFile = JS_GetScriptFilename(cx, script); } jsbytecode *pc = JS_GetFramePC(cx, fp); if (script && pc) { mScriptLine = JS_PCToLineNumber(cx, script, pc); } } mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx); } // parses the url rv = ParseURL(PromiseFlatString(aURL)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIDocument> originDoc = nsContentUtils::GetDocumentFromScriptContext(mScriptContext); // Don't allow https:// to open ws:// if (!mSecure && !Preferences::GetBool("network.websocket.allowInsecureFromHTTPS", false)) { // Confirmed we are opening plain ws:// and want to prevent this from a // secure context (e.g. https). Check the security context of the document // associated with this script, which is the same as associated with mOwner. if (originDoc && originDoc->GetSecurityInfo()) return NS_ERROR_DOM_SECURITY_ERR; } // Assign the sub protocol list and scan it for illegal values for (PRUint32 index = 0; index < protocolArray.Length(); ++index) { for (PRUint32 i = 0; i < protocolArray[index].Length(); ++i) { if (protocolArray[index][i] < static_cast<PRUnichar>(0x0021) || protocolArray[index][i] > static_cast<PRUnichar>(0x007E)) return NS_ERROR_DOM_SYNTAX_ERR; } if (!mRequestedProtocolList.IsEmpty()) mRequestedProtocolList.Append(NS_LITERAL_CSTRING(", ")); AppendUTF16toUTF8(protocolArray[index], mRequestedProtocolList); } // Check content policy. PRInt16 shouldLoad = nsIContentPolicy::ACCEPT; rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_WEBSOCKET, mURI, mPrincipal, originDoc, EmptyCString(), nsnull, &shouldLoad, nsContentUtils::GetContentPolicy(), nsContentUtils::GetSecurityManager()); NS_ENSURE_SUCCESS(rv, rv); if (NS_CP_REJECTED(shouldLoad)) { // Disallowed by content policy. return NS_ERROR_CONTENT_BLOCKED; } // the constructor should throw a SYNTAX_ERROR only if it fails to parse the // url parameter, so we don't care about the EstablishConnection result. EstablishConnection(); return NS_OK; }
void nsMsgLocalStoreUtils::ChangeKeywordsHelper( nsIMsgDBHdr *message, uint64_t desiredOffset, nsLineBuffer<char> *lineBuffer, nsTArray<nsCString> &keywordArray, bool aAdd, nsIOutputStream *outputStream, nsISeekableStream *seekableStream, nsIInputStream *inputStream) { uint32_t bytesWritten; for (uint32_t i = 0; i < keywordArray.Length(); i++) { nsAutoCString header; nsAutoCString keywords; bool done = false; uint32_t len = 0; nsAutoCString keywordToWrite(" "); keywordToWrite.Append(keywordArray[i]); seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, desiredOffset); // need to reset lineBuffer, which is cheaper than creating a new one. lineBuffer->start = lineBuffer->end = lineBuffer->buf; bool inKeywordHeader = false; bool foundKeyword = false; int64_t offsetToAddKeyword = 0; bool more; message->GetMessageSize(&len); // loop through while (!done) { int64_t lineStartPos; seekableStream->Tell(&lineStartPos); // we need to adjust the linestart pos by how much extra the line // buffer has read from the stream. lineStartPos -= (lineBuffer->end - lineBuffer->start); // NS_ReadLine doesn't return line termination chars. nsCString keywordHeaders; nsresult rv = NS_ReadLine(inputStream, lineBuffer, keywordHeaders, &more); if (NS_SUCCEEDED(rv)) { if (keywordHeaders.IsEmpty()) break; // passed headers; no x-mozilla-keywords header; give up. if (StringBeginsWith(keywordHeaders, NS_LITERAL_CSTRING(HEADER_X_MOZILLA_KEYWORDS))) inKeywordHeader = true; else if (inKeywordHeader && (keywordHeaders.CharAt(0) == ' ' || keywordHeaders.CharAt(0) == '\t')) ; // continuation header line else if (inKeywordHeader) break; else continue; uint32_t keywordHdrLength = keywordHeaders.Length(); int32_t startOffset, keywordLength; // check if we have the keyword if (MsgFindKeyword(keywordArray[i], keywordHeaders, &startOffset, &keywordLength)) { foundKeyword = true; if (!aAdd) // if we're removing, remove it, and break; { keywordHeaders.Cut(startOffset, keywordLength); for (int32_t j = keywordLength; j > 0; j--) keywordHeaders.Append(' '); seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, lineStartPos); outputStream->Write(keywordHeaders.get(), keywordHeaders.Length(), &bytesWritten); } offsetToAddKeyword = 0; // if adding and we already have the keyword, done done = true; break; } // argh, we need to check all the lines to see if we already have the // keyword, but if we don't find it, we want to remember the line and // position where we have room to add the keyword. if (aAdd) { nsAutoCString curKeywordHdr(keywordHeaders); // strip off line ending spaces. curKeywordHdr.Trim(" ", false, true); if (!offsetToAddKeyword && curKeywordHdr.Length() + keywordToWrite.Length() < keywordHdrLength) offsetToAddKeyword = lineStartPos + curKeywordHdr.Length(); } } } if (aAdd && !foundKeyword) { if (!offsetToAddKeyword) message->SetUint32Property("growKeywords", 1); else { seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offsetToAddKeyword); outputStream->Write(keywordToWrite.get(), keywordToWrite.Length(), &bytesWritten); } } } }