Merge inbound to mozilla-central. a=merge

This commit is contained in:
Coroiu Cristina 2018-01-28 12:40:33 +02:00
Родитель c4a0cebf58 c84d4c1cac
Коммит 11d0ff9f36
88 изменённых файлов: 5610 добавлений и 1436 удалений

Просмотреть файл

@ -506,7 +506,8 @@ var gEditItemOverlay = {
(this._paneInfo.isURI || this._paneInfo.bulkTagging)) {
this._updateTags().then(
anyChanges => {
if (anyChanges)
// Check _paneInfo here as we might be closing the dialog.
if (anyChanges && this._paneInfo)
this._mayUpdateFirstEditField("tagsField");
}, Components.utils.reportError);
}

Просмотреть файл

@ -15,6 +15,8 @@ support-files =
[browser_addBookmarkForFrame.js]
[browser_bookmark_folder_moveability.js]
skip-if = (os == 'win' && ccov) # Bug 1423667
[browser_bookmark_remove_tags.js]
skip-if = (os == 'win' && ccov) # Bug 1423667
[browser_bookmarklet_windowOpen.js]
[browser_bookmarks_change_title.js]
skip-if = (os == 'win' && ccov) # Bug 1423667

Просмотреть файл

@ -0,0 +1,146 @@
/**
* Tests that the bookmark tags can be removed from the bookmark star, toolbar and sidebar.
*/
"use strict";
const TEST_URL = "about:buildconfig";
const TEST_URI = Services.io.newURI(TEST_URL);
// Setup.
add_task(async function setup() {
let toolbar = document.getElementById("PersonalToolbar");
let wasCollapsed = toolbar.collapsed;
// Uncollapse the personal toolbar if needed.
if (wasCollapsed) {
await promiseSetToolbarVisibility(toolbar, true);
}
// Cleanup.
registerCleanupFunction(async () => {
// Collapse the personal toolbar if needed.
if (wasCollapsed) {
await promiseSetToolbarVisibility(toolbar, false);
}
await PlacesUtils.bookmarks.eraseEverything();
});
});
add_task(async function test_remove_tags_from_BookmarkStar() {
await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
url: TEST_URL,
title: TEST_URL,
});
PlacesUtils.tagging.tagURI(TEST_URI, ["tag1, tag2, tag3, tag4"]);
let tab = await BrowserTestUtils.openNewForegroundTab({
gBrowser,
opening: TEST_URL,
waitForStateStop: true
});
registerCleanupFunction(async () => {
await BrowserTestUtils.removeTab(tab);
});
let bookmarkPanel = document.getElementById("editBookmarkPanel");
let shownPromise = promisePopupShown(bookmarkPanel);
let bookmarkStar = BookmarkingUI.star;
bookmarkStar.click();
await shownPromise;
// Check if the "Edit This Bookmark" panel is open.
let bookmarkPanelTitle = document.getElementById("editBookmarkPanelTitle");
Assert.equal(bookmarkPanelTitle.value, gNavigatorBundle.getString("editBookmarkPanel.editBookmarkTitle"), "Bookmark panel title is correct.");
let promiseTagsChange = PlacesTestUtils.waitForNotification("onItemChanged", (id, property) => property === "tags");
// Update the "tags" field.
fillBookmarkTextField("editBMPanel_tagsField", "tag1, tag2, tag3", window);
let tagspicker = document.getElementById("editBMPanel_tagsField");
await waitForCondition(() => tagspicker.value === "tag1, tag2, tag3", "Tags are correct after update.");
let doneButton = document.getElementById("editBookmarkPanelDoneButton");
doneButton.click();
await promiseTagsChange;
let tags = PlacesUtils.tagging.getTagsForURI(TEST_URI);
Assert.deepEqual(tags, ["tag1", "tag2", "tag3"], "Should have updated the bookmark tags in the database.");
});
add_task(async function test_remove_tags_from_Toolbar() {
let toolbarBookmark = await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.toolbarGuid,
title: TEST_URL,
url: TEST_URL
});
let toolbarNode = getToolbarNodeForItemGuid(toolbarBookmark.guid);
await withBookmarksDialog(
false,
async function openPropertiesDialog() {
let placesContext = document.getElementById("placesContext");
let promisePopup = BrowserTestUtils.waitForEvent(placesContext, "popupshown");
EventUtils.synthesizeMouseAtCenter(toolbarNode, {
button: 2,
type: "contextmenu"
});
await promisePopup;
let properties = document.getElementById("placesContext_show:info");
EventUtils.synthesizeMouseAtCenter(properties, {});
},
async function test(dialogWin) {
let tagspicker = dialogWin.document.getElementById("editBMPanel_tagsField");
Assert.equal(tagspicker.value, "tag1, tag2, tag3", "Tags are correct before update.");
let promiseTagsChange = PlacesTestUtils.waitForNotification("onItemChanged", (id, property) => property === "tags");
// Update the "tags" field.
fillBookmarkTextField("editBMPanel_tagsField", "tag1, tag2", dialogWin, false);
await waitForCondition(() => tagspicker.value === "tag1, tag2", "Tags are correct after update.");
// Confirm and close the dialog.
EventUtils.synthesizeKey("VK_RETURN", {}, dialogWin);
await promiseTagsChange;
let tags = PlacesUtils.tagging.getTagsForURI(TEST_URI);
Assert.deepEqual(tags, ["tag1", "tag2"], "Should have updated the bookmark tags in the database.");
}
);
});
add_task(async function test_remove_tags_from_Sidebar() {
let bookmarks = [];
await PlacesUtils.bookmarks.fetch({ url: TEST_URL }, bm => bookmarks.push(bm));
await withSidebarTree("bookmarks", async function(tree) {
tree.selectItems([bookmarks[0].guid]);
await withBookmarksDialog(
false,
function openPropertiesDialog() {
tree.controller.doCommand("placesCmd_show:info");
},
async function test(dialogWin) {
let tagspicker = dialogWin.document.getElementById("editBMPanel_tagsField");
Assert.equal(tagspicker.value, "tag1, tag2", "Tags are correct before update.");
let promiseTagsChange = PlacesTestUtils.waitForNotification("onItemChanged", (id, property) => property === "tags");
// Update the "tags" field.
fillBookmarkTextField("editBMPanel_tagsField", "tag1", dialogWin, false);
await waitForCondition(() => tagspicker.value === "tag1", "Tags are correct after update.");
// Confirm and close the dialog.
EventUtils.synthesizeKey("VK_RETURN", {}, dialogWin);
await promiseTagsChange;
let tags = PlacesUtils.tagging.getTagsForURI(TEST_URI);
Assert.deepEqual(tags, ["tag1"], "Should have updated the bookmark tags in the database.");
}
);
});
});

Просмотреть файл

@ -457,3 +457,14 @@ function promisePopupHidden(popup) {
popup.addEventListener("popuphidden", onPopupHidden);
});
}
// Identify a bookmark node in the Bookmarks Toolbar by its guid.
function getToolbarNodeForItemGuid(itemGuid) {
let children = document.getElementById("PlacesToolbarItems").childNodes;
for (let child of children) {
if (itemGuid === child._placesNode.bookmarkGuid) {
return child;
}
}
return null;
}

Просмотреть файл

@ -5,7 +5,7 @@ code, and optionally help with indentation.
# Upgrade
Currently used version is 5.32.0. To upgrade: download a new version of
Currently used version is 5.33.0. To upgrade: download a new version of
CodeMirror from the project's page [1] and replace all JavaScript and
CSS files inside the codemirror directory [2].

Просмотреть файл

@ -53,13 +53,14 @@
function autoCloseGT(cm) {
if (cm.getOption("disableInput")) return CodeMirror.Pass;
var ranges = cm.listSelections(), replacements = [];
var opt = cm.getOption("autoCloseTags");
for (var i = 0; i < ranges.length; i++) {
if (!ranges[i].empty()) return CodeMirror.Pass;
var pos = ranges[i].head, tok = cm.getTokenAt(pos);
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;
var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html";
var html = inner.mode.configuration == "html";
var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
@ -81,13 +82,14 @@
newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)};
}
var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnAutoClose);
for (var i = ranges.length - 1; i >= 0; i--) {
var info = replacements[i];
cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert");
var sel = cm.listSelections().slice(0);
sel[i] = {head: info.newPos, anchor: info.newPos};
cm.setSelections(sel);
if (info.indent) {
if (!dontIndentOnAutoClose && info.indent) {
cm.indentLine(info.newPos.line, null, true);
cm.indentLine(info.newPos.line + 1, null, true);
}
@ -97,6 +99,8 @@
function autoCloseCurrent(cm, typingSlash) {
var ranges = cm.listSelections(), replacements = [];
var head = typingSlash ? "/" : "</";
var opt = cm.getOption("autoCloseTags");
var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnSlash);
for (var i = 0; i < ranges.length; i++) {
if (!ranges[i].empty()) return CodeMirror.Pass;
var pos = ranges[i].head, tok = cm.getTokenAt(pos);
@ -127,9 +131,11 @@
}
cm.replaceSelections(replacements);
ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++)
if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line)
cm.indentLine(ranges[i].head.line);
if (!dontIndentOnAutoClose) {
for (var i = 0; i < ranges.length; i++)
if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line)
cm.indentLine(ranges[i].head.line);
}
}
function autoCloseSlash(cm) {

Просмотреть файл

@ -39,13 +39,11 @@
replacements[i] = "\n";
} else {
var indent = match[1], after = match[5];
var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0
? match[2].replace("x", " ")
: (parseInt(match[3], 10) + 1) + match[4];
var numbered = !(unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0);
var bullet = numbered ? (parseInt(match[3], 10) + 1) + match[4] : match[2].replace("x", " ");
replacements[i] = "\n" + indent + bullet + after;
incrementRemainingMarkdownListNumbers(cm, pos);
if (numbered) incrementRemainingMarkdownListNumbers(cm, pos);
}
}

Просмотреть файл

@ -614,7 +614,8 @@
var mouseOnTip = false, old = false;
CodeMirror.on(tip, "mousemove", function() { mouseOnTip = true; });
CodeMirror.on(tip, "mouseout", function(e) {
if (!CodeMirror.contains(tip, e.relatedTarget || e.toElement)) {
var related = e.relatedTarget || e.toElement
if (!related || !CodeMirror.contains(tip, related)) {
if (old) clear();
else mouseOnTip = false;
}

Просмотреть файл

@ -7848,6 +7848,7 @@ var CodeMirror =
clearCaches(cm)
regChange(cm)
}, true)
option("lineSeparator", null, function (cm, val) {
cm.doc.lineSep = val
if (!val) { return }
@ -9888,7 +9889,7 @@ var CodeMirror =
addLegacyProps(CodeMirror)
CodeMirror.version = "5.32.0"
CodeMirror.version = "5.33.0"
return CodeMirror;
@ -11055,7 +11056,7 @@ var CodeMirror =
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d");
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
var jsKeywords = {
return {
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
"return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C,
"debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"),
@ -11067,33 +11068,6 @@ var CodeMirror =
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
"await": C
};
// Extend the 'normal' keywords with the TypeScript language extensions
if (isTS) {
var type = {type: "variable", style: "type"};
var tsKeywords = {
// object-like things
"interface": kw("class"),
"implements": C,
"namespace": C,
// scope modifiers
"public": kw("modifier"),
"private": kw("modifier"),
"protected": kw("modifier"),
"abstract": kw("modifier"),
"readonly": kw("modifier"),
// types
"string": type, "number": type, "boolean": type, "any": type
};
for (var attr in tsKeywords) {
jsKeywords[attr] = tsKeywords[attr];
}
}
return jsKeywords;
}();
var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
@ -11339,6 +11313,10 @@ var CodeMirror =
}
}
function isModifier(name) {
return name == "public" || name == "private" || name == "protected" || name == "abstract" || name == "readonly"
}
// Combinators
var defaultVars = {name: "this", next: {name: "arguments"}};
@ -11395,6 +11373,7 @@ var CodeMirror =
}
if (type == "function") return cont(functiondef);
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), className, poplex); }
if (type == "variable") {
if (isTS && value == "type") {
cx.marked = "keyword"
@ -11405,6 +11384,9 @@ var CodeMirror =
} else if (isTS && (value == "module" || value == "enum") && cx.stream.match(/^\s*\w/, false)) {
cx.marked = "keyword"
return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
} else if (isTS && value == "namespace") {
cx.marked = "keyword"
return cont(pushlex("form"), expression, block, poplex)
} else {
return cont(pushlex("stat"), maybelabel);
}
@ -11415,24 +11397,23 @@ var CodeMirror =
if (type == "default") return cont(expect(":"));
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
statement, poplex, popcontext);
if (type == "class") return cont(pushlex("form"), className, poplex);
if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
if (type == "async") return cont(statement)
if (value == "@") return cont(expression, statement)
return pass(pushlex("stat"), expression, expect(";"), poplex);
}
function expression(type) {
return expressionInner(type, false);
function expression(type, value) {
return expressionInner(type, value, false);
}
function expressionNoComma(type) {
return expressionInner(type, true);
function expressionNoComma(type, value) {
return expressionInner(type, value, true);
}
function parenExpr(type) {
if (type != "(") return pass()
return cont(pushlex(")"), expression, expect(")"), poplex)
}
function expressionInner(type, noComma) {
function expressionInner(type, value, noComma) {
if (cx.state.fatArrowAt == cx.stream.start) {
var body = noComma ? arrowBodyNoComma : arrowBody;
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);
@ -11442,7 +11423,7 @@ var CodeMirror =
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
if (type == "function") return cont(functiondef, maybeop);
if (type == "class") return cont(pushlex("form"), classExpression, poplex);
if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); }
if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression);
if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
@ -11540,10 +11521,11 @@ var CodeMirror =
return cont(afterprop);
} else if (type == "jsonld-keyword") {
return cont(afterprop);
} else if (type == "modifier") {
} else if (isTS && isModifier(value)) {
cx.marked = "keyword"
return cont(objprop)
} else if (type == "[") {
return cont(expression, expect("]"), afterprop);
return cont(expression, maybetype, expect("]"), afterprop);
} else if (type == "spread") {
return cont(expressionNoComma, afterprop);
} else if (value == "*") {
@ -11645,7 +11627,7 @@ var CodeMirror =
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
if (value == "|" || type == ".") return cont(typeexpr)
if (type == "[") return cont(expect("]"), afterType)
if (value == "extends") return cont(typeexpr)
if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) }
}
function maybeTypeArgs(_, value) {
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
@ -11660,7 +11642,7 @@ var CodeMirror =
return pass(pattern, maybetype, maybeAssign, vardefCont);
}
function pattern(type, value) {
if (type == "modifier") return cont(pattern)
if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) }
if (type == "variable") { register(value); return cont(); }
if (type == "spread") return cont(pattern);
if (type == "[") return contCommasep(pattern, "]");
@ -11714,7 +11696,8 @@ var CodeMirror =
}
function funarg(type, value) {
if (value == "@") cont(expression, funarg)
if (type == "spread" || type == "modifier") return cont(funarg);
if (type == "spread") return cont(funarg);
if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); }
return pass(pattern, maybetype, maybeAssign);
}
function classExpression(type, value) {
@ -11732,9 +11715,9 @@ var CodeMirror =
if (type == "{") return cont(pushlex("}"), classBody, poplex);
}
function classBody(type, value) {
if (type == "modifier" || type == "async" ||
if (type == "async" ||
(type == "variable" &&
(value == "static" || value == "get" || value == "set") &&
(value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) &&
cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) {
cx.marked = "keyword";
return cont(classBody);
@ -11744,7 +11727,7 @@ var CodeMirror =
return cont(isTS ? classfield : functiondef, classBody);
}
if (type == "[")
return cont(expression, expect("]"), isTS ? classfield : functiondef, classBody)
return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody)
if (value == "*") {
cx.marked = "keyword";
return cont(classBody);
@ -11962,6 +11945,7 @@ var CodeMirror =
doNotIndent: {},
allowUnquoted: false,
allowMissing: false,
allowMissingTagName: false,
caseFold: false
}
@ -12136,6 +12120,9 @@ var CodeMirror =
state.tagName = stream.current();
setStyle = "tag";
return attrState;
} else if (config.allowMissingTagName && type == "endTag") {
setStyle = "tag bracket";
return attrState(type, stream, state);
} else {
setStyle = "error";
return tagNameState;
@ -12154,6 +12141,9 @@ var CodeMirror =
setStyle = "tag error";
return closeStateErr;
}
} else if (config.allowMissingTagName && type == "endTag") {
setStyle = "tag bracket";
return closeState(type, stream, state);
} else {
setStyle = "error";
return closeStateErr;
@ -12387,9 +12377,9 @@ var CodeMirror =
return ret("qualifier", "qualifier");
} else if (/[:;{}\[\]\(\)]/.test(ch)) {
return ret(null, ch);
} else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) ||
(ch == "d" && stream.match("omain(")) ||
(ch == "r" && stream.match("egexp("))) {
} else if (((ch == "u" || ch == "U") && stream.match(/rl(-prefix)?\(/i)) ||
((ch == "d" || ch == "D") && stream.match("omain(", true, true)) ||
((ch == "r" || ch == "R") && stream.match("egexp(", true, true))) {
stream.backUp(1);
state.tokenize = tokenParenthesized;
return ret("property", "word");
@ -12472,16 +12462,16 @@ var CodeMirror =
return pushContext(state, stream, "block");
} else if (type == "}" && state.context.prev) {
return popContext(state);
} else if (supportsAtComponent && /@component/.test(type)) {
} else if (supportsAtComponent && /@component/i.test(type)) {
return pushContext(state, stream, "atComponentBlock");
} else if (/^@(-moz-)?document$/.test(type)) {
} else if (/^@(-moz-)?document$/i.test(type)) {
return pushContext(state, stream, "documentTypes");
} else if (/^@(media|supports|(-moz-)?document|import)$/.test(type)) {
} else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) {
return pushContext(state, stream, "atBlock");
} else if (/^@(font-face|counter-style)/.test(type)) {
} else if (/^@(font-face|counter-style)/i.test(type)) {
state.stateArg = type;
return "restricted_atBlock_before";
} else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
} else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) {
return "keyframes";
} else if (type && type.charAt(0) == "@") {
return pushContext(state, stream, "at");
@ -13103,7 +13093,7 @@ var CodeMirror =
},
"@": function(stream) {
if (stream.eat("{")) return [null, "interpolation"];
if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false;
stream.eatWhile(/[\w\\\-]/);
if (stream.match(/^\s*:/, false))
return ["variable-2", "variable-definition"];
@ -13332,7 +13322,7 @@ var CodeMirror =
}
CodeMirror.defineMode("jsx", function(config, modeConfig) {
var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false})
var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false, allowMissingTagName: true})
var jsMode = CodeMirror.getMode(config, modeConfig && modeConfig.base || "javascript")
function flatXMLIndent(state) {
@ -14525,6 +14515,27 @@ var CodeMirror =
return "string";
}
function tokenNestedComment(depth) {
return function (stream, state) {
var ch
while (ch = stream.next()) {
if (ch == "*" && stream.eat("/")) {
if (depth == 1) {
state.tokenize = null
break
} else {
state.tokenize = tokenNestedComment(depth - 1)
return state.tokenize(stream, state)
}
} else if (ch == "/" && stream.eat("*")) {
state.tokenize = tokenNestedComment(depth + 1)
return state.tokenize(stream, state)
}
}
return "comment"
}
}
def("text/x-scala", {
name: "clike",
keywords: words(
@ -14580,6 +14591,12 @@ var CodeMirror =
} else {
return false
}
},
"/": function(stream, state) {
if (!stream.eat("*")) return false
state.tokenize = tokenNestedComment(1)
return state.tokenize(stream, state)
}
},
modeProps: {closeBrackets: {triples: '"'}}
@ -14614,7 +14631,7 @@ var CodeMirror =
"file import where by get set abstract enum open inner override private public internal " +
"protected catch finally out final vararg reified dynamic companion constructor init " +
"sealed field property receiver param sparam lateinit data inline noinline tailrec " +
"external annotation crossinline const operator infix suspend"
"external annotation crossinline const operator infix suspend actual expect"
),
types: words(
/* package java.lang */
@ -18211,25 +18228,32 @@ var CodeMirror =
incrementNumberToken: function(cm, actionArgs) {
var cur = cm.getCursor();
var lineStr = cm.getLine(cur.line);
var re = /-?\d+/g;
var re = /(-?)(?:(0x)([\da-f]+)|(0b|0|)(\d+))/gi;
var match;
var start;
var end;
var numberStr;
var token;
while ((match = re.exec(lineStr)) !== null) {
token = match[0];
start = match.index;
end = start + token.length;
end = start + match[0].length;
if (cur.ch < end)break;
}
if (!actionArgs.backtrack && (end <= cur.ch))return;
if (token) {
if (match) {
var baseStr = match[2] || match[4]
var digits = match[3] || match[5]
var increment = actionArgs.increase ? 1 : -1;
var number = parseInt(token) + (increment * actionArgs.repeat);
var base = {'0b': 2, '0': 8, '': 10, '0x': 16}[baseStr.toLowerCase()];
var number = parseInt(match[1] + digits, base) + (increment * actionArgs.repeat);
numberStr = number.toString(base);
var zeroPadding = baseStr ? new Array(digits.length - numberStr.length + 1 + match[1].length).join('0') : ''
if (numberStr.charAt(0) === '-') {
numberStr = '-' + baseStr + zeroPadding + numberStr.substr(1);
} else {
numberStr = baseStr + zeroPadding + numberStr;
}
var from = Pos(cur.line, start);
var to = Pos(cur.line, end);
numberStr = number.toString();
cm.replaceRange(numberStr, from, to);
} else {
return;
@ -20975,9 +20999,15 @@ var CodeMirror =
var closing = cm.scanForBracket(pos, 1);
if (!closing) return false;
if (closing.ch == mirror.charAt(mirror.indexOf(opening.ch) + 1)) {
newRanges.push({anchor: Pos(opening.pos.line, opening.pos.ch + 1),
head: closing.pos});
break;
var startPos = Pos(opening.pos.line, opening.pos.ch + 1);
if (CodeMirror.cmpPos(startPos, range.from()) == 0 &&
CodeMirror.cmpPos(closing.pos, range.to()) == 0) {
opening = cm.scanForBracket(opening.pos, -1);
if (!opening) return false;
} else {
newRanges.push({anchor: startPos, head: closing.pos});
break;
}
}
pos = Pos(closing.pos.line, closing.pos.ch + 1);
}
@ -21300,27 +21330,6 @@ var CodeMirror =
cm.scrollTo(null, (pos.top + pos.bottom) / 2 - cm.getScrollInfo().clientHeight / 2);
};
cmds.selectLinesUpward = function(cm) {
cm.operation(function() {
var ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i];
if (range.head.line > cm.firstLine())
cm.addSelection(Pos(range.head.line - 1, range.head.ch));
}
});
};
cmds.selectLinesDownward = function(cm) {
cm.operation(function() {
var ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i];
if (range.head.line < cm.lastLine())
cm.addSelection(Pos(range.head.line + 1, range.head.ch));
}
});
};
function getTarget(cm) {
var from = cm.getCursor("from"), to = cm.getCursor("to");
if (CodeMirror.cmpPos(from, to) == 0) {
@ -21382,8 +21391,6 @@ var CodeMirror =
"Cmd-Enter": "insertLineAfter",
"Shift-Cmd-Enter": "insertLineBefore",
"Cmd-D": "selectNextOccurrence",
"Shift-Cmd-Up": "addCursorToPrevLine",
"Shift-Cmd-Down": "addCursorToNextLine",
"Shift-Cmd-Space": "selectScope",
"Shift-Cmd-M": "selectBetweenBrackets",
"Cmd-M": "goToBracket",
@ -21413,8 +21420,8 @@ var CodeMirror =
"Cmd-K Cmd-Backspace": "delLineLeft",
"Cmd-K Cmd-0": "unfoldAll",
"Cmd-K Cmd-J": "unfoldAll",
"Ctrl-Shift-Up": "selectLinesUpward",
"Ctrl-Shift-Down": "selectLinesDownward",
"Ctrl-Shift-Up": "addCursorToPrevLine",
"Ctrl-Shift-Down": "addCursorToNextLine",
"Cmd-F3": "findUnder",
"Shift-Cmd-F3": "findUnderPrevious",
"Alt-F3": "findAllUnder",
@ -21444,8 +21451,6 @@ var CodeMirror =
"Ctrl-Enter": "insertLineAfter",
"Shift-Ctrl-Enter": "insertLineBefore",
"Ctrl-D": "selectNextOccurrence",
"Alt-CtrlUp": "addCursorToPrevLine",
"Alt-CtrlDown": "addCursorToNextLine",
"Shift-Ctrl-Space": "selectScope",
"Shift-Ctrl-M": "selectBetweenBrackets",
"Ctrl-M": "goToBracket",
@ -21475,8 +21480,8 @@ var CodeMirror =
"Ctrl-K Ctrl-Backspace": "delLineLeft",
"Ctrl-K Ctrl-0": "unfoldAll",
"Ctrl-K Ctrl-J": "unfoldAll",
"Ctrl-Alt-Up": "selectLinesUpward",
"Ctrl-Alt-Down": "selectLinesDownward",
"Ctrl-Alt-Up": "addCursorToPrevLine",
"Ctrl-Alt-Down": "addCursorToNextLine",
"Ctrl-F3": "findUnder",
"Shift-Ctrl-F3": "findUnderPrevious",
"Alt-F3": "findAllUnder",

Просмотреть файл

@ -183,9 +183,15 @@
var closing = cm.scanForBracket(pos, 1);
if (!closing) return false;
if (closing.ch == mirror.charAt(mirror.indexOf(opening.ch) + 1)) {
newRanges.push({anchor: Pos(opening.pos.line, opening.pos.ch + 1),
head: closing.pos});
break;
var startPos = Pos(opening.pos.line, opening.pos.ch + 1);
if (CodeMirror.cmpPos(startPos, range.from()) == 0 &&
CodeMirror.cmpPos(closing.pos, range.to()) == 0) {
opening = cm.scanForBracket(opening.pos, -1);
if (!opening) return false;
} else {
newRanges.push({anchor: startPos, head: closing.pos});
break;
}
}
pos = Pos(closing.pos.line, closing.pos.ch + 1);
}
@ -508,27 +514,6 @@
cm.scrollTo(null, (pos.top + pos.bottom) / 2 - cm.getScrollInfo().clientHeight / 2);
};
cmds.selectLinesUpward = function(cm) {
cm.operation(function() {
var ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i];
if (range.head.line > cm.firstLine())
cm.addSelection(Pos(range.head.line - 1, range.head.ch));
}
});
};
cmds.selectLinesDownward = function(cm) {
cm.operation(function() {
var ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i];
if (range.head.line < cm.lastLine())
cm.addSelection(Pos(range.head.line + 1, range.head.ch));
}
});
};
function getTarget(cm) {
var from = cm.getCursor("from"), to = cm.getCursor("to");
if (CodeMirror.cmpPos(from, to) == 0) {
@ -590,8 +575,6 @@
"Cmd-Enter": "insertLineAfter",
"Shift-Cmd-Enter": "insertLineBefore",
"Cmd-D": "selectNextOccurrence",
"Shift-Cmd-Up": "addCursorToPrevLine",
"Shift-Cmd-Down": "addCursorToNextLine",
"Shift-Cmd-Space": "selectScope",
"Shift-Cmd-M": "selectBetweenBrackets",
"Cmd-M": "goToBracket",
@ -621,8 +604,8 @@
"Cmd-K Cmd-Backspace": "delLineLeft",
"Cmd-K Cmd-0": "unfoldAll",
"Cmd-K Cmd-J": "unfoldAll",
"Ctrl-Shift-Up": "selectLinesUpward",
"Ctrl-Shift-Down": "selectLinesDownward",
"Ctrl-Shift-Up": "addCursorToPrevLine",
"Ctrl-Shift-Down": "addCursorToNextLine",
"Cmd-F3": "findUnder",
"Shift-Cmd-F3": "findUnderPrevious",
"Alt-F3": "findAllUnder",
@ -652,8 +635,6 @@
"Ctrl-Enter": "insertLineAfter",
"Shift-Ctrl-Enter": "insertLineBefore",
"Ctrl-D": "selectNextOccurrence",
"Alt-CtrlUp": "addCursorToPrevLine",
"Alt-CtrlDown": "addCursorToNextLine",
"Shift-Ctrl-Space": "selectScope",
"Shift-Ctrl-M": "selectBetweenBrackets",
"Ctrl-M": "goToBracket",
@ -683,8 +664,8 @@
"Ctrl-K Ctrl-Backspace": "delLineLeft",
"Ctrl-K Ctrl-0": "unfoldAll",
"Ctrl-K Ctrl-J": "unfoldAll",
"Ctrl-Alt-Up": "selectLinesUpward",
"Ctrl-Alt-Down": "selectLinesDownward",
"Ctrl-Alt-Up": "addCursorToPrevLine",
"Ctrl-Alt-Down": "addCursorToNextLine",
"Ctrl-F3": "findUnder",
"Shift-Ctrl-F3": "findUnderPrevious",
"Alt-F3": "findAllUnder",

Просмотреть файл

@ -2637,25 +2637,32 @@
incrementNumberToken: function(cm, actionArgs) {
var cur = cm.getCursor();
var lineStr = cm.getLine(cur.line);
var re = /-?\d+/g;
var re = /(-?)(?:(0x)([\da-f]+)|(0b|0|)(\d+))/gi;
var match;
var start;
var end;
var numberStr;
var token;
while ((match = re.exec(lineStr)) !== null) {
token = match[0];
start = match.index;
end = start + token.length;
end = start + match[0].length;
if (cur.ch < end)break;
}
if (!actionArgs.backtrack && (end <= cur.ch))return;
if (token) {
if (match) {
var baseStr = match[2] || match[4]
var digits = match[3] || match[5]
var increment = actionArgs.increase ? 1 : -1;
var number = parseInt(token) + (increment * actionArgs.repeat);
var base = {'0b': 2, '0': 8, '': 10, '0x': 16}[baseStr.toLowerCase()];
var number = parseInt(match[1] + digits, base) + (increment * actionArgs.repeat);
numberStr = number.toString(base);
var zeroPadding = baseStr ? new Array(digits.length - numberStr.length + 1 + match[1].length).join('0') : ''
if (numberStr.charAt(0) === '-') {
numberStr = '-' + baseStr + zeroPadding + numberStr.substr(1);
} else {
numberStr = baseStr + zeroPadding + numberStr;
}
var from = Pos(cur.line, start);
var to = Pos(cur.line, end);
numberStr = number.toString();
cm.replaceRange(numberStr, from, to);
} else {
return;

Просмотреть файл

@ -270,7 +270,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
overflow: auto;
padding: 0.1px; /* Force widget margins to stay inside of the container */
}
.CodeMirror-widget {}

Просмотреть файл

@ -7606,6 +7606,7 @@ function defineOptions(CodeMirror) {
clearCaches(cm)
regChange(cm)
}, true)
option("lineSeparator", null, function (cm, val) {
cm.doc.lineSep = val
if (!val) { return }
@ -9646,7 +9647,7 @@ CodeMirror.fromTextArea = fromTextArea
addLegacyProps(CodeMirror)
CodeMirror.version = "5.32.0"
CodeMirror.version = "5.33.0"
return CodeMirror;

Просмотреть файл

@ -489,6 +489,27 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
return "string";
}
function tokenNestedComment(depth) {
return function (stream, state) {
var ch
while (ch = stream.next()) {
if (ch == "*" && stream.eat("/")) {
if (depth == 1) {
state.tokenize = null
break
} else {
state.tokenize = tokenNestedComment(depth - 1)
return state.tokenize(stream, state)
}
} else if (ch == "/" && stream.eat("*")) {
state.tokenize = tokenNestedComment(depth + 1)
return state.tokenize(stream, state)
}
}
return "comment"
}
}
def("text/x-scala", {
name: "clike",
keywords: words(
@ -544,6 +565,12 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
} else {
return false
}
},
"/": function(stream, state) {
if (!stream.eat("*")) return false
state.tokenize = tokenNestedComment(1)
return state.tokenize(stream, state)
}
},
modeProps: {closeBrackets: {triples: '"'}}
@ -578,7 +605,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
"file import where by get set abstract enum open inner override private public internal " +
"protected catch finally out final vararg reified dynamic companion constructor init " +
"sealed field property receiver param sparam lateinit data inline noinline tailrec " +
"external annotation crossinline const operator infix suspend"
"external annotation crossinline const operator infix suspend actual expect"
),
types: words(
/* package java.lang */

Просмотреть файл

@ -77,9 +77,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
return ret("qualifier", "qualifier");
} else if (/[:;{}\[\]\(\)]/.test(ch)) {
return ret(null, ch);
} else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) ||
(ch == "d" && stream.match("omain(")) ||
(ch == "r" && stream.match("egexp("))) {
} else if (((ch == "u" || ch == "U") && stream.match(/rl(-prefix)?\(/i)) ||
((ch == "d" || ch == "D") && stream.match("omain(", true, true)) ||
((ch == "r" || ch == "R") && stream.match("egexp(", true, true))) {
stream.backUp(1);
state.tokenize = tokenParenthesized;
return ret("property", "word");
@ -162,16 +162,16 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
return pushContext(state, stream, "block");
} else if (type == "}" && state.context.prev) {
return popContext(state);
} else if (supportsAtComponent && /@component/.test(type)) {
} else if (supportsAtComponent && /@component/i.test(type)) {
return pushContext(state, stream, "atComponentBlock");
} else if (/^@(-moz-)?document$/.test(type)) {
} else if (/^@(-moz-)?document$/i.test(type)) {
return pushContext(state, stream, "documentTypes");
} else if (/^@(media|supports|(-moz-)?document|import)$/.test(type)) {
} else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) {
return pushContext(state, stream, "atBlock");
} else if (/^@(font-face|counter-style)/.test(type)) {
} else if (/^@(font-face|counter-style)/i.test(type)) {
state.stateArg = type;
return "restricted_atBlock_before";
} else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
} else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) {
return "keyframes";
} else if (type && type.charAt(0) == "@") {
return pushContext(state, stream, "at");
@ -793,7 +793,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
},
"@": function(stream) {
if (stream.eat("{")) return [null, "interpolation"];
if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false;
stream.eatWhile(/[\w\\\-]/);
if (stream.match(/^\s*:/, false))
return ["variable-2", "variable-definition"];

Просмотреть файл

@ -26,7 +26,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d");
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
var jsKeywords = {
return {
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
"return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C,
"debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"),
@ -38,33 +38,6 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
"await": C
};
// Extend the 'normal' keywords with the TypeScript language extensions
if (isTS) {
var type = {type: "variable", style: "type"};
var tsKeywords = {
// object-like things
"interface": kw("class"),
"implements": C,
"namespace": C,
// scope modifiers
"public": kw("modifier"),
"private": kw("modifier"),
"protected": kw("modifier"),
"abstract": kw("modifier"),
"readonly": kw("modifier"),
// types
"string": type, "number": type, "boolean": type, "any": type
};
for (var attr in tsKeywords) {
jsKeywords[attr] = tsKeywords[attr];
}
}
return jsKeywords;
}();
var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
@ -310,6 +283,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
}
}
function isModifier(name) {
return name == "public" || name == "private" || name == "protected" || name == "abstract" || name == "readonly"
}
// Combinators
var defaultVars = {name: "this", next: {name: "arguments"}};
@ -366,6 +343,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
}
if (type == "function") return cont(functiondef);
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), className, poplex); }
if (type == "variable") {
if (isTS && value == "type") {
cx.marked = "keyword"
@ -376,6 +354,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
} else if (isTS && (value == "module" || value == "enum") && cx.stream.match(/^\s*\w/, false)) {
cx.marked = "keyword"
return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
} else if (isTS && value == "namespace") {
cx.marked = "keyword"
return cont(pushlex("form"), expression, block, poplex)
} else {
return cont(pushlex("stat"), maybelabel);
}
@ -386,24 +367,23 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "default") return cont(expect(":"));
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
statement, poplex, popcontext);
if (type == "class") return cont(pushlex("form"), className, poplex);
if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
if (type == "async") return cont(statement)
if (value == "@") return cont(expression, statement)
return pass(pushlex("stat"), expression, expect(";"), poplex);
}
function expression(type) {
return expressionInner(type, false);
function expression(type, value) {
return expressionInner(type, value, false);
}
function expressionNoComma(type) {
return expressionInner(type, true);
function expressionNoComma(type, value) {
return expressionInner(type, value, true);
}
function parenExpr(type) {
if (type != "(") return pass()
return cont(pushlex(")"), expression, expect(")"), poplex)
}
function expressionInner(type, noComma) {
function expressionInner(type, value, noComma) {
if (cx.state.fatArrowAt == cx.stream.start) {
var body = noComma ? arrowBodyNoComma : arrowBody;
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);
@ -413,7 +393,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
if (type == "function") return cont(functiondef, maybeop);
if (type == "class") return cont(pushlex("form"), classExpression, poplex);
if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); }
if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression);
if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
@ -511,10 +491,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return cont(afterprop);
} else if (type == "jsonld-keyword") {
return cont(afterprop);
} else if (type == "modifier") {
} else if (isTS && isModifier(value)) {
cx.marked = "keyword"
return cont(objprop)
} else if (type == "[") {
return cont(expression, expect("]"), afterprop);
return cont(expression, maybetype, expect("]"), afterprop);
} else if (type == "spread") {
return cont(expressionNoComma, afterprop);
} else if (value == "*") {
@ -616,7 +597,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
if (value == "|" || type == ".") return cont(typeexpr)
if (type == "[") return cont(expect("]"), afterType)
if (value == "extends") return cont(typeexpr)
if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) }
}
function maybeTypeArgs(_, value) {
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
@ -631,7 +612,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return pass(pattern, maybetype, maybeAssign, vardefCont);
}
function pattern(type, value) {
if (type == "modifier") return cont(pattern)
if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) }
if (type == "variable") { register(value); return cont(); }
if (type == "spread") return cont(pattern);
if (type == "[") return contCommasep(pattern, "]");
@ -685,7 +666,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
}
function funarg(type, value) {
if (value == "@") cont(expression, funarg)
if (type == "spread" || type == "modifier") return cont(funarg);
if (type == "spread") return cont(funarg);
if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); }
return pass(pattern, maybetype, maybeAssign);
}
function classExpression(type, value) {
@ -703,9 +685,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "{") return cont(pushlex("}"), classBody, poplex);
}
function classBody(type, value) {
if (type == "modifier" || type == "async" ||
if (type == "async" ||
(type == "variable" &&
(value == "static" || value == "get" || value == "set") &&
(value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) &&
cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) {
cx.marked = "keyword";
return cont(classBody);
@ -715,7 +697,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return cont(isTS ? classfield : functiondef, classBody);
}
if (type == "[")
return cont(expression, expect("]"), isTS ? classfield : functiondef, classBody)
return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody)
if (value == "*") {
cx.marked = "keyword";
return cont(classBody);

Просмотреть файл

@ -26,7 +26,7 @@
}
CodeMirror.defineMode("jsx", function(config, modeConfig) {
var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false})
var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false, allowMissingTagName: true})
var jsMode = CodeMirror.getMode(config, modeConfig && modeConfig.base || "javascript")
function flatXMLIndent(state) {

Просмотреть файл

@ -52,6 +52,7 @@ var xmlConfig = {
doNotIndent: {},
allowUnquoted: false,
allowMissing: false,
allowMissingTagName: false,
caseFold: false
}
@ -226,6 +227,9 @@ CodeMirror.defineMode("xml", function(editorConf, config_) {
state.tagName = stream.current();
setStyle = "tag";
return attrState;
} else if (config.allowMissingTagName && type == "endTag") {
setStyle = "tag bracket";
return attrState(type, stream, state);
} else {
setStyle = "error";
return tagNameState;
@ -244,6 +248,9 @@ CodeMirror.defineMode("xml", function(editorConf, config_) {
setStyle = "tag error";
return closeStateErr;
}
} else if (config.allowMissingTagName && type == "endTag") {
setStyle = "tag bracket";
return closeState(type, stream, state);
} else {
setStyle = "error";
return closeStateErr;

Просмотреть файл

@ -67,7 +67,7 @@
};
function esc(str) {
return str.replace('&', '&amp;').replace('<', '&lt;').replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
}
function compare(text, expected, mode) {

Просмотреть файл

@ -152,7 +152,9 @@
Pos(0, 8), "selectScope", hasSel(0, 8, 2, 0),
Pos(1, 2), "selectScope", hasSel(0, 8, 2, 0),
Pos(1, 6), "selectScope", hasSel(1, 6, 1, 10),
Pos(1, 9), "selectScope", hasSel(1, 6, 1, 10));
Pos(1, 9), "selectScope", hasSel(1, 6, 1, 10),
"selectScope", hasSel(0, 8, 2, 0),
"selectScope", hasSel(0, 0, 2, 1));
stTest("goToBracket", "foo(a) {\n bar[1, 2];\n}",
Pos(0, 0), "goToBracket", at(0, 0),
@ -219,31 +221,6 @@
2, 4, 2, 6,
2, 7, 2, 7));
stTest("selectLinesUpward", "123\n345\n789\n012",
setSel(0, 1, 0, 1,
1, 1, 1, 3,
2, 0, 2, 0,
3, 0, 3, 0),
"selectLinesUpward",
hasSel(0, 1, 0, 1,
0, 3, 0, 3,
1, 0, 1, 0,
1, 1, 1, 3,
2, 0, 2, 0,
3, 0, 3, 0));
stTest("selectLinesDownward", "123\n345\n789\n012",
setSel(0, 1, 0, 1,
1, 1, 1, 3,
2, 0, 2, 0,
3, 0, 3, 0),
"selectLinesDownward",
hasSel(0, 1, 0, 1,
1, 1, 1, 3,
2, 0, 2, 0,
2, 3, 2, 3,
3, 0, 3, 0));
stTest("sortLines", "c\nb\na\nC\nB\nA",
"sortLines", val("A\nB\nC\na\nb\nc"),
"undo",

Просмотреть файл

@ -4235,4 +4235,250 @@ testVim('beforeSelectionChange', function(cm, vim, helpers) {
eqCursorPos(cm.getCursor('head'), cm.getCursor('anchor'));
}, { value: 'abc' });
testVim('increment_binary', function(cm, vim, helpers) {
cm.setCursor(0, 4);
helpers.doKeys('<C-a>');
eq('0b001', cm.getValue());
helpers.doKeys('<C-a>');
eq('0b010', cm.getValue());
helpers.doKeys('<C-x>');
eq('0b001', cm.getValue());
helpers.doKeys('<C-x>');
eq('0b000', cm.getValue());
cm.setCursor(0, 0);
helpers.doKeys('<C-a>');
eq('0b001', cm.getValue());
helpers.doKeys('<C-a>');
eq('0b010', cm.getValue());
helpers.doKeys('<C-x>');
eq('0b001', cm.getValue());
helpers.doKeys('<C-x>');
eq('0b000', cm.getValue());
}, { value: '0b000' });
testVim('increment_octal', function(cm, vim, helpers) {
cm.setCursor(0, 2);
helpers.doKeys('<C-a>');
eq('001', cm.getValue());
helpers.doKeys('<C-a>');
eq('002', cm.getValue());
helpers.doKeys('<C-a>');
eq('003', cm.getValue());
helpers.doKeys('<C-a>');
eq('004', cm.getValue());
helpers.doKeys('<C-a>');
eq('005', cm.getValue());
helpers.doKeys('<C-a>');
eq('006', cm.getValue());
helpers.doKeys('<C-a>');
eq('007', cm.getValue());
helpers.doKeys('<C-a>');
eq('010', cm.getValue());
helpers.doKeys('<C-x>');
eq('007', cm.getValue());
helpers.doKeys('<C-x>');
eq('006', cm.getValue());
helpers.doKeys('<C-x>');
eq('005', cm.getValue());
helpers.doKeys('<C-x>');
eq('004', cm.getValue());
helpers.doKeys('<C-x>');
eq('003', cm.getValue());
helpers.doKeys('<C-x>');
eq('002', cm.getValue());
helpers.doKeys('<C-x>');
eq('001', cm.getValue());
helpers.doKeys('<C-x>');
eq('000', cm.getValue());
cm.setCursor(0, 0);
helpers.doKeys('<C-a>');
eq('001', cm.getValue());
helpers.doKeys('<C-a>');
eq('002', cm.getValue());
helpers.doKeys('<C-x>');
eq('001', cm.getValue());
helpers.doKeys('<C-x>');
eq('000', cm.getValue());
}, { value: '000' });
testVim('increment_decimal', function(cm, vim, helpers) {
cm.setCursor(0, 2);
helpers.doKeys('<C-a>');
eq('101', cm.getValue());
helpers.doKeys('<C-a>');
eq('102', cm.getValue());
helpers.doKeys('<C-a>');
eq('103', cm.getValue());
helpers.doKeys('<C-a>');
eq('104', cm.getValue());
helpers.doKeys('<C-a>');
eq('105', cm.getValue());
helpers.doKeys('<C-a>');
eq('106', cm.getValue());
helpers.doKeys('<C-a>');
eq('107', cm.getValue());
helpers.doKeys('<C-a>');
eq('108', cm.getValue());
helpers.doKeys('<C-a>');
eq('109', cm.getValue());
helpers.doKeys('<C-a>');
eq('110', cm.getValue());
helpers.doKeys('<C-x>');
eq('109', cm.getValue());
helpers.doKeys('<C-x>');
eq('108', cm.getValue());
helpers.doKeys('<C-x>');
eq('107', cm.getValue());
helpers.doKeys('<C-x>');
eq('106', cm.getValue());
helpers.doKeys('<C-x>');
eq('105', cm.getValue());
helpers.doKeys('<C-x>');
eq('104', cm.getValue());
helpers.doKeys('<C-x>');
eq('103', cm.getValue());
helpers.doKeys('<C-x>');
eq('102', cm.getValue());
helpers.doKeys('<C-x>');
eq('101', cm.getValue());
helpers.doKeys('<C-x>');
eq('100', cm.getValue());
cm.setCursor(0, 0);
helpers.doKeys('<C-a>');
eq('101', cm.getValue());
helpers.doKeys('<C-a>');
eq('102', cm.getValue());
helpers.doKeys('<C-x>');
eq('101', cm.getValue());
helpers.doKeys('<C-x>');
eq('100', cm.getValue());
}, { value: '100' });
testVim('increment_decimal_single_zero', function(cm, vim, helpers) {
helpers.doKeys('<C-a>');
eq('1', cm.getValue());
helpers.doKeys('<C-a>');
eq('2', cm.getValue());
helpers.doKeys('<C-a>');
eq('3', cm.getValue());
helpers.doKeys('<C-a>');
eq('4', cm.getValue());
helpers.doKeys('<C-a>');
eq('5', cm.getValue());
helpers.doKeys('<C-a>');
eq('6', cm.getValue());
helpers.doKeys('<C-a>');
eq('7', cm.getValue());
helpers.doKeys('<C-a>');
eq('8', cm.getValue());
helpers.doKeys('<C-a>');
eq('9', cm.getValue());
helpers.doKeys('<C-a>');
eq('10', cm.getValue());
helpers.doKeys('<C-x>');
eq('9', cm.getValue());
helpers.doKeys('<C-x>');
eq('8', cm.getValue());
helpers.doKeys('<C-x>');
eq('7', cm.getValue());
helpers.doKeys('<C-x>');
eq('6', cm.getValue());
helpers.doKeys('<C-x>');
eq('5', cm.getValue());
helpers.doKeys('<C-x>');
eq('4', cm.getValue());
helpers.doKeys('<C-x>');
eq('3', cm.getValue());
helpers.doKeys('<C-x>');
eq('2', cm.getValue());
helpers.doKeys('<C-x>');
eq('1', cm.getValue());
helpers.doKeys('<C-x>');
eq('0', cm.getValue());
cm.setCursor(0, 0);
helpers.doKeys('<C-a>');
eq('1', cm.getValue());
helpers.doKeys('<C-a>');
eq('2', cm.getValue());
helpers.doKeys('<C-x>');
eq('1', cm.getValue());
helpers.doKeys('<C-x>');
eq('0', cm.getValue());
}, { value: '0' });
testVim('increment_hexadecimal', function(cm, vim, helpers) {
cm.setCursor(0, 2);
helpers.doKeys('<C-a>');
eq('0x1', cm.getValue());
helpers.doKeys('<C-a>');
eq('0x2', cm.getValue());
helpers.doKeys('<C-a>');
eq('0x3', cm.getValue());
helpers.doKeys('<C-a>');
eq('0x4', cm.getValue());
helpers.doKeys('<C-a>');
eq('0x5', cm.getValue());
helpers.doKeys('<C-a>');
eq('0x6', cm.getValue());
helpers.doKeys('<C-a>');
eq('0x7', cm.getValue());
helpers.doKeys('<C-a>');
eq('0x8', cm.getValue());
helpers.doKeys('<C-a>');
eq('0x9', cm.getValue());
helpers.doKeys('<C-a>');
eq('0xa', cm.getValue());
helpers.doKeys('<C-a>');
eq('0xb', cm.getValue());
helpers.doKeys('<C-a>');
eq('0xc', cm.getValue());
helpers.doKeys('<C-a>');
eq('0xd', cm.getValue());
helpers.doKeys('<C-a>');
eq('0xe', cm.getValue());
helpers.doKeys('<C-a>');
eq('0xf', cm.getValue());
helpers.doKeys('<C-a>');
eq('0x10', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x0f', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x0e', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x0d', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x0c', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x0b', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x0a', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x09', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x08', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x07', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x06', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x05', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x04', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x03', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x02', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x01', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x00', cm.getValue());
cm.setCursor(0, 0);
helpers.doKeys('<C-a>');
eq('0x01', cm.getValue());
helpers.doKeys('<C-a>');
eq('0x02', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x01', cm.getValue());
helpers.doKeys('<C-x>');
eq('0x00', cm.getValue());
}, { value: '0x0' });

Просмотреть файл

@ -237,33 +237,25 @@ static bool CanLoadPlugin(char16ptr_t aBinaryPath)
// The file name must be in the form "np*.dll"
bool nsPluginsDir::IsPluginFile(nsIFile* file)
{
nsAutoCString path;
if (NS_FAILED(file->GetNativePath(path)))
nsAutoString path;
if (NS_FAILED(file->GetPath(path)))
return false;
const char *cPath = path.get();
// this is most likely a path, so skip to the filename
const char* filename = PL_strrchr(cPath, '\\');
if (filename)
++filename;
else
filename = cPath;
auto filename = Substring(path, path.RFindChar('\\') + 1);
// The file name must have at least one character between "np" and ".dll".
if (filename.Length() < 7) {
return false;
}
char* extension = PL_strrchr(filename, '.');
if (extension)
++extension;
uint32_t fullLength = strlen(filename);
uint32_t extLength = extension ? strlen(extension) : 0;
if (fullLength >= 7 && extLength == 3) {
if (!PL_strncasecmp(filename, "np", 2) && !PL_strncasecmp(extension, "dll", 3)) {
// don't load OJI-based Java plugins
if (!PL_strncasecmp(filename, "npoji", 5) ||
!PL_strncasecmp(filename, "npjava", 6))
return false;
return true;
}
ToLowerCase(filename);
if (StringBeginsWith(filename, NS_LITERAL_STRING("np")) &&
StringEndsWith(filename, NS_LITERAL_STRING(".dll"))) {
// don't load OJI-based Java plugins
if (StringBeginsWith(filename, NS_LITERAL_STRING("npoji")) ||
StringBeginsWith(filename, NS_LITERAL_STRING("npjava")))
return false;
return true;
}
return false;

Просмотреть файл

@ -0,0 +1,976 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "FunctionBroker.h"
#include "FunctionBrokerParent.h"
#include "PluginQuirks.h"
#if defined(XP_WIN)
#include <commdlg.h>
#include <schannel.h>
#endif // defined(XP_WIN)
using namespace mozilla;
using namespace mozilla::ipc;
using namespace mozilla::plugins;
namespace mozilla {
namespace plugins {
template <int QuirkFlag>
static bool CheckQuirks(int aQuirks)
{
return static_cast<bool>(aQuirks & QuirkFlag);
}
void FreeDestructor(void* aObj) { free(aObj); }
#if defined(XP_WIN)
/* GetKeyState */
typedef FunctionBroker<ID_GetKeyState,
decltype(GetKeyState)> GetKeyStateFB;
template<>
ShouldHookFunc* const
GetKeyStateFB::BaseType::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_GETKEYSTATE>;
/* SetCursorPos */
typedef FunctionBroker<ID_SetCursorPos,
decltype(SetCursorPos)> SetCursorPosFB;
/* GetSaveFileNameW */
typedef FunctionBroker<ID_GetSaveFileNameW,
decltype(GetSaveFileNameW)> GetSaveFileNameWFB;
// Remember files granted access in the chrome process
static void GrantFileAccess(base::ProcessId aClientId, LPOPENFILENAME& aLpofn,
bool isSave)
{
#if defined(MOZ_SANDBOX)
if (aLpofn->Flags & OFN_ALLOWMULTISELECT) {
// We only support multiselect with the OFN_EXPLORER flag.
// This guarantees that ofn.lpstrFile follows the pattern below.
MOZ_ASSERT(aLpofn->Flags & OFN_EXPLORER);
// lpstrFile is one of two things:
// 1. A null terminated full path to a file, or
// 2. A path to a folder, followed by a NULL, followed by a
// list of file names, each NULL terminated, followed by an
// additional NULL (so it is also double-NULL terminated).
std::wstring path = std::wstring(aLpofn->lpstrFile);
MOZ_ASSERT(aLpofn->nFileOffset > 0);
// For condition #1, nFileOffset points to the file name in the path.
// It will be preceeded by a non-NULL character from the path.
if (aLpofn->lpstrFile[aLpofn->nFileOffset-1] != L'\0') {
FunctionBrokerParent::GetSandboxPermissions()->GrantFileAccess(aClientId, path.c_str(), isSave);
}
else {
// This is condition #2
wchar_t* nextFile = aLpofn->lpstrFile + path.size() + 1;
while (*nextFile != L'\0') {
std::wstring nextFileStr(nextFile);
std::wstring fullPath =
path + std::wstring(L"\\") + nextFileStr;
FunctionBrokerParent::GetSandboxPermissions()->GrantFileAccess(aClientId, fullPath.c_str(), isSave);
nextFile += nextFileStr.size() + 1;
}
}
}
else {
FunctionBrokerParent::GetSandboxPermissions()->GrantFileAccess(aClientId, aLpofn->lpstrFile, isSave);
}
#else
MOZ_ASSERT_UNREACHABLE("GetFileName IPC message is only available on "
"Windows builds with sandbox.");
#endif
}
template<> template<>
BOOL GetSaveFileNameWFB::RunFunction(GetSaveFileNameWFB::FunctionType* aOrigFunction,
base::ProcessId aClientId,
LPOPENFILENAMEW& aLpofn) const
{
BOOL result = aOrigFunction(aLpofn);
if (result) {
// Record any file access permission that was just granted.
GrantFileAccess(aClientId, aLpofn, true);
}
return result;
}
template<> template<>
struct GetSaveFileNameWFB::Response::Info::ShouldMarshal<0> { static const bool value = true; };
/* GetOpenFileNameW */
typedef FunctionBroker<ID_GetOpenFileNameW,
decltype(GetOpenFileNameW)> GetOpenFileNameWFB;
template<> template<>
BOOL GetOpenFileNameWFB::RunFunction(GetOpenFileNameWFB::FunctionType* aOrigFunction,
base::ProcessId aClientId,
LPOPENFILENAMEW& aLpofn) const
{
BOOL result = aOrigFunction(aLpofn);
if (result) {
// Record any file access permission that was just granted.
GrantFileAccess(aClientId, aLpofn, false);
}
return result;
}
template<> template<>
struct GetOpenFileNameWFB::Response::Info::ShouldMarshal<0> { static const bool value = true; };
/* InternetOpenA */
typedef FunctionBroker<ID_InternetOpenA,
decltype(InternetOpenA)> InternetOpenAFB;
/* InternetConnectA */
typedef FunctionBroker<ID_InternetConnectA,
decltype(InternetConnectA)> InternetConnectAFB;
typedef InternetConnectAFB::Request ICAReqHandler;
template<>
bool ICAReqHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h,
const LPCSTR& srv, const INTERNET_PORT& port,
const LPCSTR& user, const LPCSTR& pass,
const DWORD& svc, const DWORD& flags,
const DWORD_PTR& cxt)
{
return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
}
/* InternetCloseHandle */
typedef FunctionBroker<ID_InternetCloseHandle,
decltype(InternetCloseHandle)> InternetCloseHandleFB;
typedef InternetCloseHandleFB::Request ICHReqHandler;
template<>
bool ICHReqHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h)
{
// If we are server side then we were already validated since we had to be
// looked up in the "uint64_t <-> HINTERNET" hashtable.
// In the client, we check that this is a dummy handle.
return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
}
/* InternetQueryDataAvailable */
typedef FunctionBroker<ID_InternetQueryDataAvailable,
decltype(InternetQueryDataAvailable)> InternetQueryDataAvailableFB;
typedef InternetQueryDataAvailableFB::Request IQDAReq;
typedef struct RequestHandler<ID_InternetQueryDataAvailable,
BOOL HOOK_CALL (HINTERNET)> IQDADelegateReq;
template<>
void IQDAReq::Marshal(IpdlTuple& aTuple, const HINTERNET& file,
const LPDWORD& nBytes, const DWORD& flags,
const DWORD_PTR& cxt)
{
IQDADelegateReq::Marshal(aTuple, file);
}
template<>
bool IQDAReq::Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, HINTERNET& file,
LPDWORD& nBytes, DWORD& flags, DWORD_PTR& cxt)
{
bool success = IQDADelegateReq::Unmarshal(aScd, aTuple, file);
if (!success) {
return false;
}
flags = 0;
cxt = 0;
nBytes = aScd.Allocate<DWORD>();
return true;
}
template<>
bool IQDAReq::ShouldBroker(Endpoint endpoint, const HINTERNET& file,
const LPDWORD& nBytes, const DWORD& flags,
const DWORD_PTR& cxt)
{
// If we are server side then we were already validated since we had to be
// looked up in the "uint64_t <-> HINTERNET" hashtable.
// In the client, we check that this is a dummy handle.
return (endpoint == SERVER) ||
((flags == 0) && (cxt == 0) &&
IsOdd(reinterpret_cast<uint64_t>(file)));
}
template<> template<>
struct InternetQueryDataAvailableFB::Response::Info::ShouldMarshal<1> { static const bool value = true; };
/* InternetReadFile */
typedef FunctionBroker<ID_InternetReadFile,
decltype(InternetReadFile)> InternetReadFileFB;
typedef InternetReadFileFB::Request IRFRequestHandler;
typedef struct RequestHandler<ID_InternetReadFile,
BOOL HOOK_CALL (HINTERNET, DWORD)> IRFDelegateReq;
template<>
void IRFRequestHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h,
const LPVOID& buf, const DWORD& nBytesToRead,
const LPDWORD& nBytesRead)
{
IRFDelegateReq::Marshal(aTuple, h, nBytesToRead);
}
template<>
bool IRFRequestHandler::Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, HINTERNET& h,
LPVOID& buf, DWORD& nBytesToRead,
LPDWORD& nBytesRead)
{
bool ret = IRFDelegateReq::Unmarshal(aScd, aTuple, h, nBytesToRead);
if (!ret) {
return false;
}
nBytesRead = aScd.Allocate<DWORD>();
MOZ_ASSERT(nBytesToRead > 0);
aScd.AllocateMemory(nBytesToRead, buf);
return true;
}
template<>
bool IRFRequestHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h,
const LPVOID& buf, const DWORD& nBytesToRead,
const LPDWORD& nBytesRead)
{
// For server-side validation, the HINTERNET deserialization will have
// required it to already be looked up in the IdToPtrMap. At that point,
// any call is valid.
return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
}
// Marshal the output parameter that we sent to the response delegate.
template<> template<>
struct InternetReadFileFB::Response::Info::ShouldMarshal<0> { static const bool value = true; };
typedef ResponseHandler<ID_InternetReadFile, decltype(InternetReadFile)> IRFResponseHandler;
typedef ResponseHandler<ID_InternetReadFile,
BOOL HOOK_CALL (nsDependentCSubstring)> IRFDelegateResponseHandler;
template<>
void IRFResponseHandler::Marshal(IpdlTuple& aTuple, const BOOL& ret, const HINTERNET& h,
const LPVOID& buf, const DWORD& nBytesToRead,
const LPDWORD& nBytesRead)
{
nsDependentCSubstring str;
if (*nBytesRead) {
str.Assign(static_cast<const char*>(buf), *nBytesRead);
}
IRFDelegateResponseHandler::Marshal(aTuple, ret, str);
}
template<>
bool IRFResponseHandler::Unmarshal(const IpdlTuple& aTuple, BOOL& ret, HINTERNET& h,
LPVOID& buf, DWORD& nBytesToRead,
LPDWORD& nBytesRead)
{
nsDependentCSubstring str;
bool success =
IRFDelegateResponseHandler::Unmarshal(aTuple, ret, str);
if (!success) {
return false;
}
if (str.Length()) {
memcpy(buf, str.Data(), str.Length());
*nBytesRead = str.Length();
}
return true;
}
/* InternetWriteFile */
typedef FunctionBroker<ID_InternetWriteFile,
decltype(InternetWriteFile)> InternetWriteFileFB;
typedef InternetWriteFileFB::Request IWFReqHandler;
typedef RequestHandler<ID_InternetWriteFile,
int HOOK_CALL (HINTERNET, nsDependentCSubstring)> IWFDelegateReqHandler;
template<>
void IWFReqHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& file, const LPCVOID& buf,
const DWORD& nToWrite, const LPDWORD& nWritten)
{
MOZ_ASSERT(nWritten);
IWFDelegateReqHandler::Marshal(aTuple, file,
nsDependentCSubstring(static_cast<const char*>(buf), nToWrite));
}
template<>
bool IWFReqHandler::Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, HINTERNET& file,
LPCVOID& buf, DWORD& nToWrite, LPDWORD& nWritten)
{
nsDependentCSubstring str;
if (!IWFDelegateReqHandler::Unmarshal(aScd, aTuple, file, str)) {
return false;
}
aScd.AllocateString(str, buf, false);
nToWrite = str.Length();
nWritten = aScd.Allocate<DWORD>();
return true;
}
template<>
bool IWFReqHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& file,
const LPCVOID& buf, const DWORD& nToWrite,
const LPDWORD& nWritten)
{
// For server-side validation, the HINTERNET deserialization will have
// required it to already be looked up in the IdToPtrMap. At that point,
// any call is valid.
return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(file));
}
template<> template<>
struct InternetWriteFileFB::Response::Info::ShouldMarshal<3> { static const bool value = true; };
/* InternetSetOptionA */
typedef FunctionBroker<ID_InternetSetOptionA,
decltype(InternetSetOptionA)> InternetSetOptionAFB;
typedef InternetSetOptionAFB::Request ISOAReqHandler;
typedef RequestHandler<ID_InternetSetOptionA,
BOOL HOOK_CALL (HINTERNET, DWORD, nsDependentCSubstring)> ISOADelegateReqHandler;
template<>
void ISOAReqHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h, const DWORD& opt,
const LPVOID& buf, const DWORD& bufLen)
{
ISOADelegateReqHandler::Marshal(aTuple, h, opt,
nsDependentCSubstring(static_cast<const char*>(buf), bufLen));
}
template<>
bool ISOAReqHandler::Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, HINTERNET& h,
DWORD& opt, LPVOID& buf, DWORD& bufLen)
{
nsDependentCSubstring str;
if (!ISOADelegateReqHandler::Unmarshal(aScd, aTuple, h, opt, str)) {
return false;
}
aScd.AllocateString(str, buf, false);
bufLen = str.Length();
return true;
}
template<>
bool ISOAReqHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h, const DWORD& opt,
const LPVOID& buf, const DWORD& bufLen)
{
// For server-side validation, the HINTERNET deserialization will have
// required it to already be looked up in the IdToPtrMap. At that point,
// any call is valid.
return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
}
/* HttpAddRequestHeadersA */
typedef FunctionBroker<ID_HttpAddRequestHeadersA,
decltype(HttpAddRequestHeadersA)> HttpAddRequestHeadersAFB;
typedef HttpAddRequestHeadersAFB::Request HARHAReqHandler;
template<>
bool HARHAReqHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h,
const LPCSTR& head, const DWORD& headLen,
const DWORD& mods)
{
// For server-side validation, the HINTERNET deserialization will have
// required it to already be looked up in the IdToPtrMap. At that point,
// any call is valid.
return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
}
/* HttpOpenRequestA */
typedef FunctionBroker<ID_HttpOpenRequestA,
decltype(HttpOpenRequestA)> HttpOpenRequestAFB;
typedef HttpOpenRequestAFB::Request HORAReqHandler;
typedef RequestHandler<ID_HttpOpenRequestA,
HINTERNET HOOK_CALL (HINTERNET, LPCSTR, LPCSTR, LPCSTR, LPCSTR,
nsTArray<nsCString>, DWORD, DWORD_PTR)> HORADelegateReqHandler;
template<>
void HORAReqHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h,
const LPCSTR& verb, const LPCSTR& obj,
const LPCSTR& ver, const LPCSTR& ref,
LPCSTR * const & acceptTypes, const DWORD& flags,
const DWORD_PTR& cxt)
{
nsTArray<nsCString> arrayAcceptTypes;
LPCSTR * curAcceptType = acceptTypes;
if (curAcceptType) {
while (*curAcceptType) {
arrayAcceptTypes.AppendElement(nsCString(*curAcceptType));
++curAcceptType;
}
}
HORADelegateReqHandler::Marshal(aTuple, h, verb, obj, ver, ref,
arrayAcceptTypes, flags, cxt);
}
template<>
bool HORAReqHandler::Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, HINTERNET& h,
LPCSTR& verb, LPCSTR& obj, LPCSTR& ver,
LPCSTR& ref, LPCSTR *& acceptTypes,
DWORD& flags, DWORD_PTR& cxt)
{
nsTArray<nsCString> arrayAcceptTypes;
if (!HORADelegateReqHandler::Unmarshal(aScd, aTuple, h, verb, obj, ver, ref, arrayAcceptTypes, flags, cxt)) {
return false;
}
if (arrayAcceptTypes.Length() == 0) {
acceptTypes = nullptr;
} else {
aScd.AllocateMemory((arrayAcceptTypes.Length() + 1) * sizeof(LPCSTR), acceptTypes);
for (size_t i = 0; i < arrayAcceptTypes.Length(); ++i) {
aScd.AllocateString(arrayAcceptTypes[i], acceptTypes[i]);
}
acceptTypes[arrayAcceptTypes.Length()] = nullptr;
}
return true;
}
template<>
bool HORAReqHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h,
const LPCSTR& verb, const LPCSTR& obj,
const LPCSTR& ver, const LPCSTR& ref,
LPCSTR * const & acceptTypes,
const DWORD& flags, const DWORD_PTR& cxt)
{
// For the server-side test, the HINTERNET deserialization will have
// required it to already be looked up in the IdToPtrMap. At that point,
// any call is valid.
return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
}
/* HttpQueryInfoA */
typedef FunctionBroker<ID_HttpQueryInfoA,
decltype(HttpQueryInfoA)> HttpQueryInfoAFB;
typedef HttpQueryInfoAFB::Request HQIARequestHandler;
typedef RequestHandler<ID_HttpQueryInfoA,
BOOL HOOK_CALL (HINTERNET, DWORD, BOOL, DWORD, BOOL,
DWORD)> HQIADelegateRequestHandler;
template<>
void HQIARequestHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h,
const DWORD& lvl, const LPVOID& buf, const LPDWORD& bufLen,
const LPDWORD& idx)
{
HQIADelegateRequestHandler::Marshal(aTuple, h, lvl,
bufLen != nullptr, bufLen ? *bufLen : 0,
idx != nullptr, idx ? *idx : 0);
}
template<>
bool HQIARequestHandler::Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, HINTERNET& h,
DWORD& lvl, LPVOID& buf, LPDWORD& bufLen,
LPDWORD& idx)
{
BOOL hasBufLen, hasIdx;
DWORD tempBufLen, tempIdx;
bool success =
HQIADelegateRequestHandler::Unmarshal(aScd, aTuple, h, lvl, hasBufLen, tempBufLen, hasIdx, tempIdx);
if (!success) {
return false;
}
bufLen = nullptr;
if (hasBufLen) {
aScd.AllocateMemory(tempBufLen, buf, bufLen);
}
idx = nullptr;
if (hasIdx) {
idx = aScd.Allocate<DWORD>(tempIdx);
}
return true;
}
template<>
bool HQIARequestHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h,
const DWORD& lvl, const LPVOID& buf,
const LPDWORD& bufLen, const LPDWORD& idx)
{
return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
}
// Marshal all of the output parameters that we sent to the response delegate.
template<> template<>
struct HttpQueryInfoAFB::Response::Info::ShouldMarshal<0> { static const bool value = true; };
template<> template<>
struct HttpQueryInfoAFB::Response::Info::ShouldMarshal<1> { static const bool value = true; };
template<> template<>
struct HttpQueryInfoAFB::Response::Info::ShouldMarshal<2> { static const bool value = true; };
typedef HttpQueryInfoAFB::Response HQIAResponseHandler;
typedef ResponseHandler<ID_HttpQueryInfoA,
BOOL HOOK_CALL (nsDependentCSubstring,
DWORD, DWORD)> HQIADelegateResponseHandler;
template<>
void HQIAResponseHandler::Marshal(IpdlTuple& aTuple, const BOOL& ret, const HINTERNET& h,
const DWORD& lvl, const LPVOID& buf, const LPDWORD& bufLen,
const LPDWORD& idx)
{
nsDependentCSubstring str;
if (buf && ret) {
MOZ_ASSERT(bufLen);
str.Assign(static_cast<const char*>(buf), *bufLen);
}
// Note that we send the bufLen separately to handle the case where buf wasn't
// allocated or large enough to hold the entire return value. bufLen is then
// the required buffer size.
HQIADelegateResponseHandler::Marshal(aTuple, ret, str,
bufLen ? *bufLen : 0, idx ? *idx : 0);
}
template<>
bool HQIAResponseHandler::Unmarshal(const IpdlTuple& aTuple, BOOL& ret, HINTERNET& h,
DWORD& lvl, LPVOID& buf, LPDWORD& bufLen,
LPDWORD& idx)
{
DWORD totalBufLen = *bufLen;
nsDependentCSubstring str;
DWORD tempBufLen, tempIdx;
bool success =
HQIADelegateResponseHandler::Unmarshal(aTuple, ret, str, tempBufLen, tempIdx);
if (!success) {
return false;
}
if (bufLen) {
*bufLen = tempBufLen;
}
if (idx) {
*idx = tempIdx;
}
if (buf && ret) {
// When HttpQueryInfo returns strings, the buffer length will not include
// the null terminator. Rather than (brittle-y) trying to determine if the
// return buffer is a string, we always tack on a null terminator if the
// buffer has room for it.
MOZ_ASSERT(str.Length() == *bufLen);
memcpy(buf, str.Data(), str.Length());
if (str.Length() < totalBufLen) {
char* cbuf = static_cast<char*>(buf);
cbuf[str.Length()] = '\0';
}
}
return true;
}
/* HttpSendRequestA */
typedef FunctionBroker<ID_HttpSendRequestA,
decltype(HttpSendRequestA)> HttpSendRequestAFB;
typedef HttpSendRequestAFB::Request HSRARequestHandler;
typedef RequestHandler<ID_HttpSendRequestA,
BOOL HOOK_CALL (HINTERNET, nsDependentCSubstring,
nsDependentCSubstring)> HSRADelegateRequestHandler;
template<>
void HSRARequestHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h,
const LPCSTR& head, const DWORD& headLen,
const LPVOID& opt, const DWORD& optLen)
{
nsDependentCSubstring headStr;
headStr.SetIsVoid(head == nullptr);
if (head) {
// HttpSendRequest allows headLen == -1L for length of a null terminated string.
DWORD ncHeadLen = headLen;
if (ncHeadLen == -1L) {
ncHeadLen = strlen(head);
}
headStr.Rebind(head, ncHeadLen);
}
nsDependentCSubstring optStr;
optStr.SetIsVoid(opt == nullptr);
if (opt) {
optStr.Rebind(static_cast<const char*>(opt), optLen);
}
HSRADelegateRequestHandler::Marshal(aTuple, h, headStr, optStr);
}
template<>
bool HSRARequestHandler::Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, HINTERNET& h,
LPCSTR& head, DWORD& headLen, LPVOID& opt,
DWORD& optLen)
{
nsDependentCSubstring headStr;
nsDependentCSubstring optStr;
bool success = HSRADelegateRequestHandler::Unmarshal(aScd, aTuple, h, headStr, optStr);
if (!success) {
return false;
}
if (headStr.IsVoid()) {
head = nullptr;
MOZ_ASSERT(headLen == 0);
} else {
aScd.AllocateString(headStr, head, false);
headLen = headStr.Length();
}
if (optStr.IsVoid()) {
opt = nullptr;
MOZ_ASSERT(optLen == 0);
} else {
aScd.AllocateString(optStr, opt, false);
optLen = optStr.Length();
}
return true;
}
template<>
bool HSRARequestHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h,
const LPCSTR& head, const DWORD& headLen,
const LPVOID& opt, const DWORD& optLen)
{
// If we are server side then we were already validated since we had to be
// looked up in the "uint64_t <-> HINTERNET" hashtable.
// In the client, we check that this is a dummy handle.
return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
}
/* HttpSendRequestExA */
typedef FunctionBroker<ID_HttpSendRequestExA,
decltype(HttpSendRequestExA)> HttpSendRequestExAFB;
typedef RequestInfo<ID_HttpSendRequestExA> HSRExAReqInfo;
template<> template<>
struct HSRExAReqInfo::FixedValue<2> { static const LPINTERNET_BUFFERSA value; };
const LPINTERNET_BUFFERSA HSRExAReqInfo::FixedValue<2>::value = nullptr;
// Docs for HttpSendRequestExA say this parameter 'must' be zero but Flash
// passes other values.
// template<> template<>
// struct HSRExAReqInfo::FixedValue<3> { static const DWORD value = 0; };
template<> template<>
struct HSRExAReqInfo::FixedValue<4> { static const DWORD_PTR value; };
const DWORD_PTR HSRExAReqInfo::FixedValue<4>::value = 0;
/* InternetQueryOptionA */
typedef FunctionBroker<ID_InternetQueryOptionA,
decltype(InternetQueryOptionA)> InternetQueryOptionAFB;
typedef InternetQueryOptionAFB::Request IQOARequestHandler;
typedef RequestHandler<ID_InternetQueryOptionA,
BOOL HOOK_CALL (HINTERNET, DWORD, DWORD)> IQOADelegateRequestHandler;
template<>
void IQOARequestHandler::Marshal(IpdlTuple& aTuple, const HINTERNET& h,
const DWORD& opt, const LPVOID& buf, const LPDWORD& bufLen)
{
MOZ_ASSERT(bufLen);
IQOADelegateRequestHandler::Marshal(aTuple, h, opt, buf ? *bufLen : 0);
}
template<>
bool IQOARequestHandler::Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, HINTERNET& h,
DWORD& opt, LPVOID& buf, LPDWORD& bufLen)
{
DWORD tempBufLen;
bool success =
IQOADelegateRequestHandler::Unmarshal(aScd, aTuple, h, opt, tempBufLen);
if (!success) {
return false;
}
aScd.AllocateMemory(tempBufLen, buf, bufLen);
return true;
}
template<>
bool IQOARequestHandler::ShouldBroker(Endpoint endpoint, const HINTERNET& h,
const DWORD& opt, const LPVOID& buf,
const LPDWORD& bufLen)
{
// If we are server side then we were already validated since we had to be
// looked up in the "uint64_t <-> HINTERNET" hashtable.
// In the client, we check that this is a dummy handle.
return (endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h));
}
// Marshal all of the output parameters that we sent to the response delegate.
template<> template<>
struct InternetQueryOptionAFB::Response::Info::ShouldMarshal<0> { static const bool value = true; };
template<> template<>
struct InternetQueryOptionAFB::Response::Info::ShouldMarshal<1> { static const bool value = true; };
typedef InternetQueryOptionAFB::Response IQOAResponseHandler;
typedef ResponseHandler<ID_InternetQueryOptionA,
BOOL HOOK_CALL (nsDependentCSubstring, DWORD)> IQOADelegateResponseHandler;
template<>
void IQOAResponseHandler::Marshal(IpdlTuple& aTuple, const BOOL& ret, const HINTERNET& h,
const DWORD& opt, const LPVOID& buf, const LPDWORD& bufLen)
{
nsDependentCSubstring str;
if (buf && ret) {
MOZ_ASSERT(*bufLen);
str.Assign(static_cast<const char*>(buf), *bufLen);
}
IQOADelegateResponseHandler::Marshal(aTuple, ret, str, *bufLen);
}
template<>
bool IQOAResponseHandler::Unmarshal(const IpdlTuple& aTuple, BOOL& ret, HINTERNET& h,
DWORD& opt, LPVOID& buf, LPDWORD& bufLen)
{
nsDependentCSubstring str;
bool success =
IQOADelegateResponseHandler::Unmarshal(aTuple, ret, str, *bufLen);
if (!success) {
return false;
}
if (buf && ret) {
MOZ_ASSERT(str.Length() == *bufLen);
memcpy(buf, str.Data(), str.Length());
}
return true;
}
/* InternetErrorDlg */
typedef FunctionBroker<ID_InternetErrorDlg,
decltype(InternetErrorDlg)> InternetErrorDlgFB;
typedef RequestInfo<ID_InternetErrorDlg> IEDReqInfo;
template<> template<>
struct IEDReqInfo::FixedValue<4> { static LPVOID* const value; };
LPVOID* const IEDReqInfo::FixedValue<4>::value = nullptr;
typedef InternetErrorDlgFB::Request IEDReqHandler;
template<>
bool IEDReqHandler::ShouldBroker(Endpoint endpoint, const HWND& hwnd,
const HINTERNET& h, const DWORD& err,
const DWORD& flags, LPVOID* const & data)
{
const DWORD SUPPORTED_FLAGS =
FLAGS_ERROR_UI_FILTER_FOR_ERRORS | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS |
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_FLAGS_NO_UI;
// We broker if (1) the handle h is brokered (odd in client),
// (2) we support the requested action flags and (3) there is no user
// data, which wouldn't make sense for our supported flags anyway.
return ((endpoint == SERVER) || IsOdd(reinterpret_cast<uint64_t>(h))) &&
(!(flags & ~SUPPORTED_FLAGS)) && (data == nullptr);
}
/* AcquireCredentialsHandleA */
typedef FunctionBroker<ID_AcquireCredentialsHandleA,
decltype(AcquireCredentialsHandleA)> AcquireCredentialsHandleAFB;
typedef RequestInfo<ID_AcquireCredentialsHandleA> ACHAReqInfo;
template<> template<>
struct ACHAReqInfo::FixedValue<0> { static const LPSTR value; };
const LPSTR ACHAReqInfo::FixedValue<0>::value = nullptr;
template<> template<>
struct ACHAReqInfo::FixedValue<1> { static const LPSTR value; };
const LPSTR ACHAReqInfo::FixedValue<1>::value = UNISP_NAME_A;
template<> template<>
struct ACHAReqInfo::FixedValue<2> { static const unsigned long value; };
const unsigned long ACHAReqInfo::FixedValue<2>::value = SECPKG_CRED_OUTBOUND;
template<> template<>
struct ACHAReqInfo::FixedValue<3> { static void* const value; };
void* const ACHAReqInfo::FixedValue<3>::value = nullptr;
template<> template<>
struct ACHAReqInfo::FixedValue<5> { static const SEC_GET_KEY_FN value; };
const SEC_GET_KEY_FN ACHAReqInfo::FixedValue<5>::value = nullptr;
template<> template<>
struct ACHAReqInfo::FixedValue<6> { static void* const value; };
void* const ACHAReqInfo::FixedValue<6>::value = nullptr;
typedef AcquireCredentialsHandleAFB::Request ACHARequestHandler;
typedef RequestHandler<ID_AcquireCredentialsHandleA,
SECURITY_STATUS HOOK_CALL (LPSTR, LPSTR, unsigned long,
void*, PSCHANNEL_CRED, SEC_GET_KEY_FN,
void*)> ACHADelegateRequestHandler;
template<>
void ACHARequestHandler::Marshal(IpdlTuple& aTuple, const LPSTR& principal,
const LPSTR& pkg, const unsigned long& credUse,
const PVOID& logonId, const PVOID& auth,
const SEC_GET_KEY_FN& getKeyFn,
const PVOID& getKeyArg, const PCredHandle& cred,
const PTimeStamp& expiry)
{
const PSCHANNEL_CRED& scCred = reinterpret_cast<const PSCHANNEL_CRED&>(auth);
ACHADelegateRequestHandler::Marshal(aTuple, principal, pkg, credUse, logonId,
scCred, getKeyFn, getKeyArg);
}
template<>
bool ACHARequestHandler::Unmarshal(ServerCallData& aScd, const IpdlTuple& aTuple, LPSTR& principal,
LPSTR& pkg, unsigned long& credUse,
PVOID& logonId, PVOID& auth, SEC_GET_KEY_FN& getKeyFn,
PVOID& getKeyArg, PCredHandle& cred, PTimeStamp& expiry)
{
PSCHANNEL_CRED& scCred = reinterpret_cast<PSCHANNEL_CRED&>(auth);
if (!ACHADelegateRequestHandler::Unmarshal(aScd, aTuple, principal, pkg, credUse,
logonId, scCred, getKeyFn, getKeyArg)) {
return false;
}
cred = aScd.Allocate<CredHandle>();
expiry = aScd.Allocate<::TimeStamp>();
return true;
}
typedef ResponseInfo<ID_AcquireCredentialsHandleA> ACHARspInfo;
// Response phase must send output parameters
template<> template<>
struct ACHARspInfo::ShouldMarshal<7> { static const bool value = true; };
template<> template<>
struct ACHARspInfo::ShouldMarshal<8> { static const bool value = true; };
/* QueryCredentialsAttributesA */
typedef FunctionBroker<ID_QueryCredentialsAttributesA,
decltype(QueryCredentialsAttributesA)> QueryCredentialsAttributesAFB;
/* FreeCredentialsHandle */
typedef FunctionBroker<ID_FreeCredentialsHandle,
decltype(FreeCredentialsHandle)> FreeCredentialsHandleFB;
typedef FreeCredentialsHandleFB::Request FCHReq;
template<>
bool FCHReq::ShouldBroker(Endpoint endpoint, const PCredHandle& h)
{
// If we are server side then we were already validated since we had to be
// looked up in the "uint64_t <-> CredHandle" hashtable.
// In the client, we check that this is a dummy handle.
return (endpoint == SERVER) ||
((h->dwLower == h->dwUpper) && IsOdd(static_cast<uint64_t>(h->dwLower)));
}
#endif // defined(XP_WIN)
/*****************************************************************************/
#define FUN_HOOK(x) static_cast<FunctionHook*>(x)
void
AddBrokeredFunctionHooks(FunctionHookArray& aHooks)
{
// We transfer ownership of the FunctionHook objects to the array.
#if defined(XP_WIN)
aHooks[ID_GetKeyState] =
FUN_HOOK(new GetKeyStateFB("user32.dll", "GetKeyState", &GetKeyState));
aHooks[ID_SetCursorPos] =
FUN_HOOK(new SetCursorPosFB("user32.dll", "SetCursorPos", &SetCursorPos));
aHooks[ID_GetSaveFileNameW] =
FUN_HOOK(new GetSaveFileNameWFB("comdlg32.dll", "GetSaveFileNameW",
&GetSaveFileNameW));
aHooks[ID_GetOpenFileNameW] =
FUN_HOOK(new GetOpenFileNameWFB("comdlg32.dll", "GetOpenFileNameW",
&GetOpenFileNameW));
aHooks[ID_InternetOpenA] =
FUN_HOOK(new InternetOpenAFB("wininet.dll", "InternetOpenA", &InternetOpenA));
aHooks[ID_InternetConnectA] =
FUN_HOOK(new InternetConnectAFB("wininet.dll", "InternetConnectA",
&InternetConnectA));
aHooks[ID_InternetCloseHandle] =
FUN_HOOK(new InternetCloseHandleFB("wininet.dll", "InternetCloseHandle",
&InternetCloseHandle));
aHooks[ID_InternetQueryDataAvailable] =
FUN_HOOK(new InternetQueryDataAvailableFB("wininet.dll",
"InternetQueryDataAvailable",
&InternetQueryDataAvailable));
aHooks[ID_InternetReadFile] =
FUN_HOOK(new InternetReadFileFB("wininet.dll", "InternetReadFile",
&InternetReadFile));
aHooks[ID_InternetWriteFile] =
FUN_HOOK(new InternetWriteFileFB("wininet.dll", "InternetWriteFile",
&InternetWriteFile));
aHooks[ID_InternetSetOptionA] =
FUN_HOOK(new InternetSetOptionAFB("wininet.dll", "InternetSetOptionA",
&InternetSetOptionA));
aHooks[ID_HttpAddRequestHeadersA] =
FUN_HOOK(new HttpAddRequestHeadersAFB("wininet.dll",
"HttpAddRequestHeadersA",
&HttpAddRequestHeadersA));
aHooks[ID_HttpOpenRequestA] =
FUN_HOOK(new HttpOpenRequestAFB("wininet.dll", "HttpOpenRequestA",
&HttpOpenRequestA));
aHooks[ID_HttpQueryInfoA] =
FUN_HOOK(new HttpQueryInfoAFB("wininet.dll", "HttpQueryInfoA",
&HttpQueryInfoA));
aHooks[ID_HttpSendRequestA] =
FUN_HOOK(new HttpSendRequestAFB("wininet.dll", "HttpSendRequestA",
&HttpSendRequestA));
aHooks[ID_HttpSendRequestExA] =
FUN_HOOK(new HttpSendRequestExAFB("wininet.dll", "HttpSendRequestExA",
&HttpSendRequestExA));
aHooks[ID_InternetQueryOptionA] =
FUN_HOOK(new InternetQueryOptionAFB("wininet.dll", "InternetQueryOptionA",
&InternetQueryOptionA));
aHooks[ID_InternetErrorDlg] =
FUN_HOOK(new InternetErrorDlgFB("wininet.dll", "InternetErrorDlg",
InternetErrorDlg));
aHooks[ID_AcquireCredentialsHandleA] =
FUN_HOOK(new AcquireCredentialsHandleAFB("sspicli.dll",
"AcquireCredentialsHandleA",
&AcquireCredentialsHandleA));
aHooks[ID_QueryCredentialsAttributesA] =
FUN_HOOK(new QueryCredentialsAttributesAFB("sspicli.dll",
"QueryCredentialsAttributesA",
&QueryCredentialsAttributesA));
aHooks[ID_FreeCredentialsHandle] =
FUN_HOOK(new FreeCredentialsHandleFB("sspicli.dll",
"FreeCredentialsHandle",
&FreeCredentialsHandle));
#endif // defined(XP_WIN)
}
#undef FUN_HOOK
} // namespace plugins
} // namespace mozilla

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,123 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=4 et :
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "FunctionBrokerChild.h"
#include "FunctionBrokerThread.h"
namespace mozilla {
namespace plugins {
FunctionBrokerChild* FunctionBrokerChild::sInstance = nullptr;
bool
FunctionBrokerChild::IsDispatchThread()
{
return mThread->IsOnThread();
}
void
FunctionBrokerChild::PostToDispatchThread(already_AddRefed<nsIRunnable>&& runnable)
{
mThread->Dispatch(Move(runnable));
}
/* static */ bool
FunctionBrokerChild::Initialize(Endpoint<PFunctionBrokerChild>&& aBrokerEndpoint)
{
MOZ_RELEASE_ASSERT(XRE_IsPluginProcess(),
"FunctionBrokerChild can only be used in plugin processes");
MOZ_ASSERT(!sInstance);
FunctionBrokerThread* thread = FunctionBrokerThread::Create();
if (!thread) {
return false;
}
sInstance = new FunctionBrokerChild(thread, Move(aBrokerEndpoint));
return true;
}
/* static */ FunctionBrokerChild*
FunctionBrokerChild::GetInstance()
{
MOZ_RELEASE_ASSERT(XRE_IsPluginProcess(),
"FunctionBrokerChild can only be used in plugin processes");
MOZ_ASSERT(sInstance, "Must initialize FunctionBrokerChild before using it");
return sInstance;
}
FunctionBrokerChild::FunctionBrokerChild(FunctionBrokerThread* aThread,
Endpoint<PFunctionBrokerChild>&& aEndpoint) :
mThread(aThread)
, mShutdownDone(false)
, mMonitor("FunctionBrokerChild Lock")
{
MOZ_ASSERT(aThread);
PostToDispatchThread(NewNonOwningRunnableMethod<Endpoint<PFunctionBrokerChild>&&>(
"FunctionBrokerChild::Bind", this, &FunctionBrokerChild::Bind,
Move(aEndpoint)));
}
void
FunctionBrokerChild::Bind(Endpoint<PFunctionBrokerChild>&& aEndpoint)
{
MOZ_RELEASE_ASSERT(mThread->IsOnThread());
DebugOnly<bool> ok = aEndpoint.Bind(this);
MOZ_ASSERT(ok);
}
void
FunctionBrokerChild::ShutdownOnDispatchThread()
{
MOZ_ASSERT(mThread->IsOnThread());
// Set mShutdownDone and notify waiting thread (if any) that we are done.
MonitorAutoLock lock(mMonitor);
mShutdownDone = true;
mMonitor.Notify();
}
void
FunctionBrokerChild::ActorDestroy(ActorDestroyReason aWhy)
{
MOZ_ASSERT(mThread->IsOnThread());
// Queue up a task on the PD thread. When that task is executed then
// we know that anything queued before ActorDestroy has completed.
// At that point, we can set mShutdownDone and alert any waiting
// threads that it is safe to destroy us.
sInstance->PostToDispatchThread(NewNonOwningRunnableMethod(
"FunctionBrokerChild::ShutdownOnDispatchThread", sInstance,
&FunctionBrokerChild::ShutdownOnDispatchThread));
}
void
FunctionBrokerChild::Destroy()
{
MOZ_ASSERT(NS_IsMainThread());
if (!sInstance) {
return;
}
// mShutdownDone will tell us when ActorDestroy has been run and any tasks
// on the FunctionBrokerThread have completed. At that point, we can
// safely delete the actor.
{
MonitorAutoLock lock(sInstance->mMonitor);
while (!sInstance->mShutdownDone) {
// Release lock and wait. Regain lock when we are notified that
// we have ShutdownOnDispatchThread.
sInstance->mMonitor.Wait();
}
}
delete sInstance;
sInstance = nullptr;
}
} // namespace plugins
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=4 et :
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_plugins_functionbrokerchild_h
#define mozilla_plugins_functionbrokerchild_h
#include "mozilla/plugins/PFunctionBrokerChild.h"
namespace mozilla {
namespace plugins {
class FunctionBrokerThread;
/**
* Dispatches brokered methods to the Parent process to allow functionality
* that is otherwise blocked by the sandbox.
*/
class FunctionBrokerChild : public PFunctionBrokerChild
{
public:
static bool Initialize(Endpoint<PFunctionBrokerChild>&& aBrokerEndpoint);
static FunctionBrokerChild* GetInstance();
static void Destroy();
bool IsDispatchThread();
void PostToDispatchThread(already_AddRefed<nsIRunnable>&& runnable);
void ActorDestroy(ActorDestroyReason aWhy) override;
private:
explicit FunctionBrokerChild(FunctionBrokerThread* aThread,
Endpoint<PFunctionBrokerChild>&& aEndpoint);
void ShutdownOnDispatchThread();
void Bind(Endpoint<PFunctionBrokerChild>&& aEndpoint);
nsAutoPtr<FunctionBrokerThread> mThread;
// True if tasks on the FunctionBrokerThread have completed
bool mShutdownDone;
// This monitor guards mShutdownDone.
Monitor mMonitor;
static FunctionBrokerChild* sInstance;
};
} // namespace plugins
} // namespace mozilla
#endif // mozilla_plugins_functionbrokerchild_h

Просмотреть файл

@ -0,0 +1,359 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8; -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "FunctionBrokerIPCUtils.h"
#if defined(XP_WIN)
#include <schannel.h>
/* these defines are missing from mingw headers */
#ifndef SP_PROT_TLS1_1_CLIENT
#define SP_PROT_TLS1_1_CLIENT 0x00000200
#endif
#ifndef SP_PROT_TLS1_2_CLIENT
#define SP_PROT_TLS1_2_CLIENT 0x00000800
#endif
namespace mozilla {
namespace plugins {
mozilla::LazyLogModule sPluginHooksLog("PluginHooks");
static const DWORD SCHANNEL_SUPPORTED_PROTOCOLS =
SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT;
static const DWORD SCHANNEL_SUPPORTED_FLAGS =
SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS |
SCH_CRED_REVOCATION_CHECK_END_CERT;
void
OpenFileNameIPC::CopyFromOfn(LPOPENFILENAMEW aLpofn)
{
mHwndOwner = nullptr;
// Filter is double-NULL terminated. mFilter should include the double-NULL.
mHasFilter = aLpofn->lpstrFilter != nullptr;
if (mHasFilter) {
uint32_t dNullIdx = 0;
while (aLpofn->lpstrFilter[dNullIdx] != L'\0' ||
aLpofn->lpstrFilter[dNullIdx+1] != L'\0') {
dNullIdx++;
}
mFilter.assign(aLpofn->lpstrFilter, dNullIdx+2);
}
mHasCustomFilter = aLpofn->lpstrCustomFilter != nullptr;
if (mHasCustomFilter) {
mCustomFilterIn = std::wstring(aLpofn->lpstrCustomFilter);
mNMaxCustFilterOut =
aLpofn->nMaxCustFilter - (wcslen(aLpofn->lpstrCustomFilter) + 1);
}
else {
mNMaxCustFilterOut = 0;
}
mFilterIndex = aLpofn->nFilterIndex;
mFile = std::wstring(aLpofn->lpstrFile);
mNMaxFile = aLpofn->nMaxFile;
mNMaxFileTitle =
aLpofn->lpstrFileTitle != nullptr ? aLpofn->nMaxFileTitle : 0;
mHasInitialDir = aLpofn->lpstrInitialDir != nullptr;
if (mHasInitialDir) {
mInitialDir = std::wstring(aLpofn->lpstrInitialDir);
}
mHasTitle = aLpofn->lpstrTitle != nullptr;
if (mHasTitle) {
mTitle = std::wstring(aLpofn->lpstrTitle);
}
mHasDefExt = aLpofn->lpstrDefExt != nullptr;
if (mHasDefExt) {
mDefExt = std::wstring(aLpofn->lpstrDefExt);
}
mFlags = aLpofn->Flags;
// If the user sets OFN_ALLOWMULTISELECT then we require OFN_EXPLORER
// as well. Without OFN_EXPLORER, the method has ancient legacy
// behavior that we don't support.
MOZ_ASSERT((mFlags & OFN_EXPLORER) || !(mFlags & OFN_ALLOWMULTISELECT));
// We ignore any visual customization and callbacks that the user set.
mFlags &= ~(OFN_ENABLEHOOK | OFN_ENABLETEMPLATEHANDLE | OFN_ENABLETEMPLATE);
mFlagsEx = aLpofn->FlagsEx;
}
void
OpenFileNameIPC::AddToOfn(LPOPENFILENAMEW aLpofn) const
{
aLpofn->lStructSize = sizeof(OPENFILENAMEW);
aLpofn->hwndOwner = mHwndOwner;
if (mHasFilter) {
memcpy(const_cast<LPWSTR>(aLpofn->lpstrFilter),
mFilter.data(), mFilter.size() * sizeof(wchar_t));
}
if (mHasCustomFilter) {
aLpofn->nMaxCustFilter = mCustomFilterIn.size() + 1 + mNMaxCustFilterOut;
wcscpy(aLpofn->lpstrCustomFilter, mCustomFilterIn.c_str());
memset(aLpofn->lpstrCustomFilter + mCustomFilterIn.size() + 1, 0,
mNMaxCustFilterOut * sizeof(wchar_t));
}
else {
aLpofn->nMaxCustFilter = 0;
}
aLpofn->nFilterIndex = mFilterIndex;
if (mNMaxFile > 0) {
wcsncpy(aLpofn->lpstrFile, mFile.c_str(),
std::min(static_cast<uint32_t>(mFile.size()+1), mNMaxFile));
aLpofn->lpstrFile[mNMaxFile - 1] = L'\0';
}
aLpofn->nMaxFile = mNMaxFile;
aLpofn->nMaxFileTitle = mNMaxFileTitle;
if (mHasInitialDir) {
wcscpy(const_cast<LPWSTR>(aLpofn->lpstrInitialDir), mInitialDir.c_str());
}
if (mHasTitle) {
wcscpy(const_cast<LPWSTR>(aLpofn->lpstrTitle), mTitle.c_str());
}
aLpofn->Flags = mFlags; /* TODO: Consider adding OFN_NOCHANGEDIR */
if (mHasDefExt) {
wcscpy(const_cast<LPWSTR>(aLpofn->lpstrDefExt), mDefExt.c_str());
}
aLpofn->FlagsEx = mFlagsEx;
}
void
OpenFileNameIPC::AllocateOfnStrings(LPOPENFILENAMEW aLpofn) const
{
if (mHasFilter) {
// mFilter is double-NULL terminated and it includes the double-NULL in its length.
aLpofn->lpstrFilter =
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mFilter.size())));
}
if (mHasCustomFilter) {
aLpofn->lpstrCustomFilter =
static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * (mCustomFilterIn.size() + 1 + mNMaxCustFilterOut)));
}
aLpofn->lpstrFile =
static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * mNMaxFile));
if (mNMaxFileTitle > 0) {
aLpofn->lpstrFileTitle =
static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * mNMaxFileTitle));
}
if (mHasInitialDir) {
aLpofn->lpstrInitialDir =
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mInitialDir.size() + 1)));
}
if (mHasTitle) {
aLpofn->lpstrTitle =
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mTitle.size() + 1)));
}
if (mHasDefExt) {
aLpofn->lpstrDefExt =
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mDefExt.size() + 1)));
}
}
// static
void
OpenFileNameIPC::FreeOfnStrings(LPOPENFILENAMEW aLpofn)
{
if (aLpofn->lpstrFilter) {
free(const_cast<LPWSTR>(aLpofn->lpstrFilter));
}
if (aLpofn->lpstrCustomFilter) {
free(aLpofn->lpstrCustomFilter);
}
if (aLpofn->lpstrFile) {
free(aLpofn->lpstrFile);
}
if (aLpofn->lpstrFileTitle) {
free(aLpofn->lpstrFileTitle);
}
if (aLpofn->lpstrInitialDir) {
free(const_cast<LPWSTR>(aLpofn->lpstrInitialDir));
}
if (aLpofn->lpstrTitle) {
free(const_cast<LPWSTR>(aLpofn->lpstrTitle));
}
if (aLpofn->lpstrDefExt) {
free(const_cast<LPWSTR>(aLpofn->lpstrDefExt));
}
}
void
OpenFileNameRetIPC::CopyFromOfn(LPOPENFILENAMEW aLpofn)
{
if (aLpofn->lpstrCustomFilter != nullptr) {
mCustomFilterOut =
std::wstring(aLpofn->lpstrCustomFilter + wcslen(aLpofn->lpstrCustomFilter) + 1);
}
mFile.assign(aLpofn->lpstrFile, aLpofn->nMaxFile);
if (aLpofn->lpstrFileTitle != nullptr) {
mFileTitle.assign(aLpofn->lpstrFileTitle, wcslen(aLpofn->lpstrFileTitle) + 1);
}
mFileOffset = aLpofn->nFileOffset;
mFileExtension = aLpofn->nFileExtension;
}
void
OpenFileNameRetIPC::AddToOfn(LPOPENFILENAMEW aLpofn) const
{
if (aLpofn->lpstrCustomFilter) {
LPWSTR secondString =
aLpofn->lpstrCustomFilter + wcslen(aLpofn->lpstrCustomFilter) + 1;
const wchar_t* customFilterOut = mCustomFilterOut.c_str();
MOZ_ASSERT(wcslen(aLpofn->lpstrCustomFilter) + 1 +
wcslen(customFilterOut) + 1 + 1 <= aLpofn->nMaxCustFilter);
wcscpy(secondString, customFilterOut);
secondString[wcslen(customFilterOut) + 1] = L'\0'; // terminated with two NULLs
}
MOZ_ASSERT(mFile.size() <= aLpofn->nMaxFile);
memcpy(aLpofn->lpstrFile,
mFile.data(), mFile.size() * sizeof(wchar_t));
if (aLpofn->lpstrFileTitle != nullptr) {
MOZ_ASSERT(mFileTitle.size() + 1 < aLpofn->nMaxFileTitle);
wcscpy(aLpofn->lpstrFileTitle, mFileTitle.c_str());
}
aLpofn->nFileOffset = mFileOffset;
aLpofn->nFileExtension = mFileExtension;
}
void
IPCSchannelCred::CopyFrom(const PSCHANNEL_CRED& aSCred)
{
// We assert that the aSCred fields take supported values.
// If they do not then we ignore the values we were given.
MOZ_ASSERT(aSCred->dwVersion == SCHANNEL_CRED_VERSION);
MOZ_ASSERT(aSCred->cCreds == 0);
MOZ_ASSERT(aSCred->paCred == nullptr);
MOZ_ASSERT(aSCred->hRootStore == nullptr);
MOZ_ASSERT(aSCred->cMappers == 0);
MOZ_ASSERT(aSCred->aphMappers == nullptr);
MOZ_ASSERT(aSCred->cSupportedAlgs == 0);
MOZ_ASSERT(aSCred->palgSupportedAlgs == nullptr);
MOZ_ASSERT((aSCred->grbitEnabledProtocols & SCHANNEL_SUPPORTED_PROTOCOLS) ==
aSCred->grbitEnabledProtocols);
mEnabledProtocols =
aSCred->grbitEnabledProtocols & SCHANNEL_SUPPORTED_PROTOCOLS;
mMinStrength = aSCred->dwMinimumCipherStrength;
mMaxStrength = aSCred->dwMaximumCipherStrength;
MOZ_ASSERT(aSCred->dwSessionLifespan == 0);
MOZ_ASSERT((aSCred->dwFlags & SCHANNEL_SUPPORTED_FLAGS) == aSCred->dwFlags);
mFlags = aSCred->dwFlags & SCHANNEL_SUPPORTED_FLAGS;
MOZ_ASSERT(aSCred->dwCredFormat == 0);
}
void
IPCSchannelCred::CopyTo(PSCHANNEL_CRED& aSCred) const
{
// Validate values as they come from an untrusted process.
memset(aSCred, 0, sizeof(SCHANNEL_CRED));
aSCred->dwVersion = SCHANNEL_CRED_VERSION;
aSCred->grbitEnabledProtocols =
mEnabledProtocols & SCHANNEL_SUPPORTED_PROTOCOLS;
aSCred->dwMinimumCipherStrength = mMinStrength;
aSCred->dwMaximumCipherStrength = mMaxStrength;
aSCred->dwFlags = mFlags & SCHANNEL_SUPPORTED_FLAGS;
}
void
IPCInternetBuffers::CopyFrom(const LPINTERNET_BUFFERSA& aBufs)
{
mBuffers.Clear();
LPINTERNET_BUFFERSA inetBuf = aBufs;
while (inetBuf) {
MOZ_ASSERT(inetBuf->dwStructSize == sizeof(INTERNET_BUFFERSA));
Buffer* ipcBuf = mBuffers.AppendElement();
ipcBuf->mHeader.SetIsVoid(inetBuf->lpcszHeader == nullptr);
if (inetBuf->lpcszHeader) {
ipcBuf->mHeader.Assign(inetBuf->lpcszHeader, inetBuf->dwHeadersLength);
}
ipcBuf->mHeaderTotal = inetBuf->dwHeadersTotal;
ipcBuf->mBuffer.SetIsVoid(inetBuf->lpvBuffer == nullptr);
if (inetBuf->lpvBuffer) {
ipcBuf->mBuffer.Assign(static_cast<char*>(inetBuf->lpvBuffer),
inetBuf->dwBufferLength);
}
ipcBuf->mBufferTotal = inetBuf->dwBufferTotal;
inetBuf = inetBuf->Next;
}
}
void
IPCInternetBuffers::CopyTo(LPINTERNET_BUFFERSA& aBufs) const
{
MOZ_ASSERT(!aBufs);
LPINTERNET_BUFFERSA lastBuf = nullptr;
for (size_t idx = 0; idx < mBuffers.Length(); ++idx) {
const Buffer& ipcBuf = mBuffers[idx];
LPINTERNET_BUFFERSA newBuf =
static_cast<LPINTERNET_BUFFERSA>(moz_xcalloc(1, sizeof(INTERNET_BUFFERSA)));
if (idx == 0) {
aBufs = newBuf;
} else {
MOZ_ASSERT(lastBuf);
lastBuf->Next = newBuf;
lastBuf = newBuf;
}
newBuf->dwStructSize = sizeof(INTERNET_BUFFERSA);
newBuf->dwHeadersTotal = ipcBuf.mHeaderTotal;
if (!ipcBuf.mHeader.IsVoid()) {
newBuf->lpcszHeader =
static_cast<LPCSTR>(moz_xmalloc(ipcBuf.mHeader.Length()));
memcpy(const_cast<char*>(newBuf->lpcszHeader), ipcBuf.mHeader.Data(),
ipcBuf.mHeader.Length());
newBuf->dwHeadersLength = ipcBuf.mHeader.Length();
}
newBuf->dwBufferTotal = ipcBuf.mBufferTotal;
if (!ipcBuf.mBuffer.IsVoid()) {
newBuf->lpvBuffer = moz_xmalloc(ipcBuf.mBuffer.Length());
memcpy(newBuf->lpvBuffer, ipcBuf.mBuffer.Data(),
ipcBuf.mBuffer.Length());
newBuf->dwBufferLength = ipcBuf.mBuffer.Length();
}
}
}
/* static */ void
IPCInternetBuffers::FreeBuffers(LPINTERNET_BUFFERSA& aBufs)
{
if (!aBufs) {
return;
}
while (aBufs) {
LPINTERNET_BUFFERSA temp = aBufs->Next;
free(const_cast<char*>(aBufs->lpcszHeader));
free(aBufs->lpvBuffer);
free(aBufs);
aBufs = temp;
}
}
void
IPCPrintDlg::CopyFrom(const LPPRINTDLGW& aDlg)
{
// DLP: Trouble -- my prior impl "worked" but didn't return anything
// AFAIR. So... ??? But it printed a page!!! How?!
MOZ_ASSERT_UNREACHABLE("TODO: DLP:");
}
void
IPCPrintDlg::CopyTo(LPPRINTDLGW& aDlg) const
{
MOZ_ASSERT_UNREACHABLE("TODO: DLP:");
}
} // namespace plugins
} // namespace mozilla
#endif // defined(XP_WIN)

Просмотреть файл

@ -0,0 +1,459 @@
#ifndef dom_plugins_ipc_functionbrokeripcutils_h
#define dom_plugins_ipc_functionbrokeripcutils_h 1
#include "PluginMessageUtils.h"
#if defined(XP_WIN)
#define SECURITY_WIN32
#include <security.h>
#include <wininet.h>
#include <schannel.h>
#include <commdlg.h>
#endif // defined(XP_WIN)
namespace mozilla {
namespace plugins {
/**
* This enum represents all of the methods hooked by the main facility in BrokerClient.
* It is used to allow quick lookup in the sFunctionsToHook structure.
*/
enum FunctionHookId
{
#if defined(XP_WIN)
ID_GetWindowInfo = 0
, ID_GetKeyState
, ID_SetCursorPos
, ID_GetSaveFileNameW
, ID_GetOpenFileNameW
, ID_InternetOpenA
, ID_InternetConnectA
, ID_InternetCloseHandle
, ID_InternetQueryDataAvailable
, ID_InternetReadFile
, ID_InternetWriteFile
, ID_InternetSetOptionA
, ID_HttpAddRequestHeadersA
, ID_HttpOpenRequestA
, ID_HttpQueryInfoA
, ID_HttpSendRequestA
, ID_HttpSendRequestExA
, ID_InternetQueryOptionA
, ID_InternetErrorDlg
, ID_AcquireCredentialsHandleA
, ID_QueryCredentialsAttributesA
, ID_FreeCredentialsHandle
, ID_PrintDlgW
, ID_FunctionHookCount
#else // defined(XP_WIN)
ID_FunctionHookCount
#endif // defined(XP_WIN)
};
// Max number of bytes to show when logging a blob of raw memory
static const uint32_t MAX_BLOB_CHARS_TO_LOG = 12;
// Format strings for safe logging despite the fact that they are sometimes
// used as raw binary blobs.
inline nsCString FormatBlob(const nsACString& aParam)
{
if (aParam.IsVoid() || aParam.IsEmpty()) {
return nsCString(aParam.IsVoid() ? "<void>" : "<empty>");
}
nsCString str;
uint32_t totalLen = std::min(MAX_BLOB_CHARS_TO_LOG, aParam.Length());
// If we are printing only a portion of the string then follow it with ellipsis
const char* maybeEllipsis = (MAX_BLOB_CHARS_TO_LOG < aParam.Length()) ? "..." : "";
for (uint32_t idx = 0; idx < totalLen; ++idx) {
// Should be %02x but I've run into a AppendPrintf bug...
str.AppendPrintf("0x%2x ", aParam.Data()[idx] & 0xff);
}
str.AppendPrintf("%s | '", maybeEllipsis);
for (uint32_t idx = 0; idx < totalLen; ++idx) {
str.AppendPrintf("%c", (aParam.Data()[idx] > 0) ? aParam.Data()[idx] : '.');
}
str.AppendPrintf("'%s", maybeEllipsis);
return str;
}
#if defined(XP_WIN)
// Values indicate GetOpenFileNameW and GetSaveFileNameW.
enum GetFileNameFunc { OPEN_FUNC, SAVE_FUNC };
typedef nsTArray<nsCString> StringArray;
// IPC-capable version of the Windows OPENFILENAMEW struct.
typedef struct _OpenFileNameIPC
{
// Allocates memory for the strings in this object. This should usually
// be used with a zeroed out OPENFILENAMEW structure.
void AllocateOfnStrings(LPOPENFILENAMEW aLpofn) const;
static void FreeOfnStrings(LPOPENFILENAMEW aLpofn);
void AddToOfn(LPOPENFILENAMEW aLpofn) const;
void CopyFromOfn(LPOPENFILENAMEW aLpofn);
bool operator==(const _OpenFileNameIPC& o) const
{
return (o.mHwndOwner == mHwndOwner) &&
(o.mFilter == mFilter) &&
(o.mHasFilter == mHasFilter) &&
(o.mCustomFilterIn == mCustomFilterIn) &&
(o.mHasCustomFilter == mHasCustomFilter) &&
(o.mNMaxCustFilterOut == mNMaxCustFilterOut) &&
(o.mFilterIndex == mFilterIndex) &&
(o.mFile == mFile) &&
(o.mNMaxFile == mNMaxFile) &&
(o.mNMaxFileTitle == mNMaxFileTitle) &&
(o.mInitialDir == mInitialDir) &&
(o.mHasInitialDir == mHasInitialDir) &&
(o.mTitle == mTitle) &&
(o.mHasTitle == mHasTitle) &&
(o.mFlags == mFlags) &&
(o.mDefExt == mDefExt) &&
(o.mHasDefExt == mHasDefExt) &&
(o.mFlagsEx == mFlagsEx);
}
NativeWindowHandle mHwndOwner;
std::wstring mFilter; // Double-NULL terminated (i.e. L"\0\0") if mHasFilter is true
bool mHasFilter;
std::wstring mCustomFilterIn;
bool mHasCustomFilter;
uint32_t mNMaxCustFilterOut;
uint32_t mFilterIndex;
std::wstring mFile;
uint32_t mNMaxFile;
uint32_t mNMaxFileTitle;
std::wstring mInitialDir;
bool mHasInitialDir;
std::wstring mTitle;
bool mHasTitle;
uint32_t mFlags;
std::wstring mDefExt;
bool mHasDefExt;
uint32_t mFlagsEx;
} OpenFileNameIPC;
// GetOpenFileNameW and GetSaveFileNameW overwrite fields of their OPENFILENAMEW
// parameter. This represents those values so that they can be returned via IPC.
typedef struct _OpenFileNameRetIPC
{
void CopyFromOfn(LPOPENFILENAMEW aLpofn);
void AddToOfn(LPOPENFILENAMEW aLpofn) const;
bool operator==(const _OpenFileNameRetIPC& o) const
{
return (o.mCustomFilterOut == mCustomFilterOut) &&
(o.mFile == mFile) &&
(o.mFileTitle == mFileTitle) &&
(o.mFileOffset == mFileOffset) &&
(o.mFileExtension == mFileExtension);
}
std::wstring mCustomFilterOut;
std::wstring mFile; // Double-NULL terminated (i.e. L"\0\0")
std::wstring mFileTitle;
uint16_t mFileOffset;
uint16_t mFileExtension;
} OpenFileNameRetIPC;
typedef struct _IPCSchannelCred
{
void CopyFrom(const PSCHANNEL_CRED& aSCred);
void CopyTo(PSCHANNEL_CRED& aSCred) const;
bool operator==(const _IPCSchannelCred& o) const
{
return (o.mEnabledProtocols == mEnabledProtocols) &&
(o.mMinStrength == mMinStrength) &&
(o.mMaxStrength == mMaxStrength) &&
(o.mFlags == mFlags);
}
DWORD mEnabledProtocols;
DWORD mMinStrength;
DWORD mMaxStrength;
DWORD mFlags;
} IPCSchannelCred;
typedef struct _IPCInternetBuffers
{
void CopyFrom(const LPINTERNET_BUFFERSA& aBufs);
void CopyTo(LPINTERNET_BUFFERSA& aBufs) const;
bool operator==(const _IPCInternetBuffers& o) const
{
return o.mBuffers == mBuffers;
}
static void FreeBuffers(LPINTERNET_BUFFERSA& aBufs);
struct Buffer
{
nsCString mHeader;
uint32_t mHeaderTotal;
nsCString mBuffer;
uint32_t mBufferTotal;
bool operator==(const Buffer& o) const
{
return (o.mHeader == mHeader) && (o.mHeaderTotal == mHeaderTotal) &&
(o.mBuffer == mBuffer) && (o.mBufferTotal == mBufferTotal);
}
};
nsTArray<Buffer> mBuffers;
} IPCInternetBuffers;
typedef struct _IPCPrintDlg
{
void CopyFrom(const LPPRINTDLGW& aDlg);
void CopyTo(LPPRINTDLGW& aDlg) const;
bool operator==(const _IPCPrintDlg& o) const
{
MOZ_ASSERT_UNREACHABLE("DLP: TODO:"); return false;
}
} IPCPrintDlg;
#endif // defined(XP_WIN)
} // namespace plugins
} // namespace mozilla
namespace IPC {
using mozilla::plugins::FunctionHookId;
#if defined(XP_WIN)
using mozilla::plugins::OpenFileNameIPC;
using mozilla::plugins::OpenFileNameRetIPC;
using mozilla::plugins::IPCSchannelCred;
using mozilla::plugins::IPCInternetBuffers;
using mozilla::plugins::IPCPrintDlg;
using mozilla::plugins::NativeWindowHandle;
using mozilla::plugins::StringArray;
template <>
struct ParamTraits<OpenFileNameIPC>
{
typedef OpenFileNameIPC paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mHwndOwner);
WriteParam(aMsg, aParam.mFilter);
WriteParam(aMsg, aParam.mHasFilter);
WriteParam(aMsg, aParam.mCustomFilterIn);
WriteParam(aMsg, aParam.mHasCustomFilter);
WriteParam(aMsg, aParam.mNMaxCustFilterOut);
WriteParam(aMsg, aParam.mFilterIndex);
WriteParam(aMsg, aParam.mFile);
WriteParam(aMsg, aParam.mNMaxFile);
WriteParam(aMsg, aParam.mNMaxFileTitle);
WriteParam(aMsg, aParam.mInitialDir);
WriteParam(aMsg, aParam.mHasInitialDir);
WriteParam(aMsg, aParam.mTitle);
WriteParam(aMsg, aParam.mHasTitle);
WriteParam(aMsg, aParam.mFlags);
WriteParam(aMsg, aParam.mDefExt);
WriteParam(aMsg, aParam.mHasDefExt);
WriteParam(aMsg, aParam.mFlagsEx);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
if (ReadParam(aMsg, aIter, &aResult->mHwndOwner) &&
ReadParam(aMsg, aIter, &aResult->mFilter) &&
ReadParam(aMsg, aIter, &aResult->mHasFilter) &&
ReadParam(aMsg, aIter, &aResult->mCustomFilterIn) &&
ReadParam(aMsg, aIter, &aResult->mHasCustomFilter) &&
ReadParam(aMsg, aIter, &aResult->mNMaxCustFilterOut) &&
ReadParam(aMsg, aIter, &aResult->mFilterIndex) &&
ReadParam(aMsg, aIter, &aResult->mFile) &&
ReadParam(aMsg, aIter, &aResult->mNMaxFile) &&
ReadParam(aMsg, aIter, &aResult->mNMaxFileTitle) &&
ReadParam(aMsg, aIter, &aResult->mInitialDir) &&
ReadParam(aMsg, aIter, &aResult->mHasInitialDir) &&
ReadParam(aMsg, aIter, &aResult->mTitle) &&
ReadParam(aMsg, aIter, &aResult->mHasTitle) &&
ReadParam(aMsg, aIter, &aResult->mFlags) &&
ReadParam(aMsg, aIter, &aResult->mDefExt) &&
ReadParam(aMsg, aIter, &aResult->mHasDefExt) &&
ReadParam(aMsg, aIter, &aResult->mFlagsEx)) {
return true;
}
return false;
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
aLog->append(StringPrintf(L"[%S, %S, %S, %S]", aParam.mFilter.c_str(),
aParam.mCustomFilterIn.c_str(), aParam.mFile.c_str(),
aParam.mTitle.c_str()));
}
};
template <>
struct ParamTraits<OpenFileNameRetIPC>
{
typedef OpenFileNameRetIPC paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mCustomFilterOut);
WriteParam(aMsg, aParam.mFile);
WriteParam(aMsg, aParam.mFileTitle);
WriteParam(aMsg, aParam.mFileOffset);
WriteParam(aMsg, aParam.mFileExtension);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
if (ReadParam(aMsg, aIter, &aResult->mCustomFilterOut) &&
ReadParam(aMsg, aIter, &aResult->mFile) &&
ReadParam(aMsg, aIter, &aResult->mFileTitle) &&
ReadParam(aMsg, aIter, &aResult->mFileOffset) &&
ReadParam(aMsg, aIter, &aResult->mFileExtension)) {
return true;
}
return false;
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
aLog->append(StringPrintf(L"[%S, %S, %S, %d, %d]", aParam.mCustomFilterOut.c_str(),
aParam.mFile.c_str(), aParam.mFileTitle.c_str(),
aParam.mFileOffset, aParam.mFileExtension));
}
};
template <>
struct ParamTraits<mozilla::plugins::GetFileNameFunc> :
public ContiguousEnumSerializerInclusive<mozilla::plugins::GetFileNameFunc,
mozilla::plugins::OPEN_FUNC,
mozilla::plugins::SAVE_FUNC>
{};
template <>
struct ParamTraits<IPCSchannelCred>
{
typedef mozilla::plugins::IPCSchannelCred paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, static_cast<uint32_t>(aParam.mEnabledProtocols));
WriteParam(aMsg, static_cast<uint32_t>(aParam.mMinStrength));
WriteParam(aMsg, static_cast<uint32_t>(aParam.mMaxStrength));
WriteParam(aMsg, static_cast<uint32_t>(aParam.mFlags));
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
uint32_t proto, minStr, maxStr, flags;
if (!ReadParam(aMsg, aIter, &proto) ||
!ReadParam(aMsg, aIter, &minStr) ||
!ReadParam(aMsg, aIter, &maxStr) ||
!ReadParam(aMsg, aIter, &flags)) {
return false;
}
aResult->mEnabledProtocols = proto;
aResult->mMinStrength = minStr;
aResult->mMaxStrength = maxStr;
aResult->mFlags = flags;
return true;
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
aLog->append(StringPrintf(L"[%d,%d,%d,%d]",
aParam.mEnabledProtocols, aParam.mMinStrength,
aParam.mMaxStrength, aParam.mFlags));
}
};
template <>
struct ParamTraits<IPCInternetBuffers::Buffer>
{
typedef mozilla::plugins::IPCInternetBuffers::Buffer paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mHeader);
WriteParam(aMsg, aParam.mHeaderTotal);
WriteParam(aMsg, aParam.mBuffer);
WriteParam(aMsg, aParam.mBufferTotal);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
return ReadParam(aMsg, aIter, &aResult->mHeader) &&
ReadParam(aMsg, aIter, &aResult->mHeaderTotal) &&
ReadParam(aMsg, aIter, &aResult->mBuffer) &&
ReadParam(aMsg, aIter, &aResult->mBufferTotal);
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
nsCString head = mozilla::plugins::FormatBlob(aParam.mHeader);
nsCString buffer = mozilla::plugins::FormatBlob(aParam.mBuffer);
std::string msg = StringPrintf("[%s, %d, %s, %d]",
head.Data(), aParam.mHeaderTotal,
buffer.Data(), aParam.mBufferTotal);
aLog->append(msg.begin(), msg.end());
}
};
template <>
struct ParamTraits<IPCInternetBuffers>
{
typedef mozilla::plugins::IPCInternetBuffers paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mBuffers);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
return ReadParam(aMsg, aIter, &aResult->mBuffers);
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
ParamTraits<nsTArray<IPCInternetBuffers::Buffer>>::Log(aParam.mBuffers, aLog);
}
};
template <>
struct ParamTraits<IPCPrintDlg>
{
typedef mozilla::plugins::IPCPrintDlg paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
MOZ_ASSERT_UNREACHABLE("TODO: DLP:");
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
MOZ_ASSERT_UNREACHABLE("TODO: DLP:");
return true;
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
MOZ_ASSERT_UNREACHABLE("TODO: DLP:");
}
};
#endif // defined(XP_WIN)
template <>
struct ParamTraits<FunctionHookId> :
public ContiguousEnumSerializer<FunctionHookId,
static_cast<FunctionHookId>(0),
FunctionHookId::ID_FunctionHookCount>
{};
} // namespace IPC
#endif /* dom_plugins_ipc_functionbrokeripcutils_h */

Просмотреть файл

@ -0,0 +1,152 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=4 et :
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "FunctionBrokerParent.h"
#include "FunctionBroker.h"
#include "FunctionBrokerThread.h"
namespace mozilla {
namespace plugins {
#if defined(XP_WIN)
UlongPairToIdMap sPairToIdMap;
IdToUlongPairMap sIdToPairMap;
PtrToIdMap sPtrToIdMap;
IdToPtrMap sIdToPtrMap;
#endif // defined(XP_WIN)
/* static */ FunctionBrokerParent*
FunctionBrokerParent::Create(Endpoint<PFunctionBrokerParent>&& aParentEnd)
{
FunctionBrokerThread* thread = FunctionBrokerThread::Create();
if (!thread) {
return nullptr;
}
// We get the FunctionHooks so that they are created here, not on the
// message thread.
FunctionHook::GetHooks();
return new FunctionBrokerParent(thread, Move(aParentEnd));
}
FunctionBrokerParent::FunctionBrokerParent(FunctionBrokerThread* aThread,
Endpoint<PFunctionBrokerParent>&& aParentEnd) :
mThread(aThread)
, mMonitor("FunctionBrokerParent Lock")
, mShutdownDone(false)
{
MOZ_ASSERT(mThread);
mThread->Dispatch(NewNonOwningRunnableMethod<Endpoint<PFunctionBrokerParent>&&>(
"FunctionBrokerParent::Bind", this, &FunctionBrokerParent::Bind, Move(aParentEnd)));
}
FunctionBrokerParent::~FunctionBrokerParent()
{
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
// Clean up any file permissions that we granted to the child process.
MOZ_RELEASE_ASSERT(NS_IsMainThread());
RemovePermissionsForProcess(OtherPid());
#endif
}
void
FunctionBrokerParent::Bind(Endpoint<PFunctionBrokerParent>&& aEnd)
{
MOZ_RELEASE_ASSERT(mThread->IsOnThread());
DebugOnly<bool> ok = aEnd.Bind(this);
MOZ_ASSERT(ok);
}
void
FunctionBrokerParent::ShutdownOnBrokerThread()
{
MOZ_ASSERT(mThread->IsOnThread());
Close();
// Notify waiting thread that we are done.
MonitorAutoLock lock(mMonitor);
mShutdownDone = true;
mMonitor.Notify();
}
void
FunctionBrokerParent::Destroy(FunctionBrokerParent* aInst)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aInst);
{
// Hold the lock while we destroy the actor on the broker thread.
MonitorAutoLock lock(aInst->mMonitor);
aInst->mThread->Dispatch(NewNonOwningRunnableMethod(
"FunctionBrokerParent::ShutdownOnBrokerThread", aInst,
&FunctionBrokerParent::ShutdownOnBrokerThread));
// Wait for broker thread to complete destruction.
while (!aInst->mShutdownDone) {
aInst->mMonitor.Wait();
}
}
delete aInst;
}
void
FunctionBrokerParent::ActorDestroy(ActorDestroyReason aWhy)
{
MOZ_RELEASE_ASSERT(mThread->IsOnThread());
}
mozilla::ipc::IPCResult
FunctionBrokerParent::RecvBrokerFunction(const FunctionHookId &aFunctionId,
const IpdlTuple &aInTuple,
IpdlTuple *aOutTuple)
{
#if defined(XP_WIN)
MOZ_ASSERT(mThread->IsOnThread());
if (RunBrokeredFunction(OtherPid(), aFunctionId, aInTuple, aOutTuple)) {
return IPC_OK();
}
return IPC_FAIL_NO_REASON(this);
#else
MOZ_ASSERT_UNREACHABLE("BrokerFunction is currently only implemented on Windows.");
return IPC_FAIL_NO_REASON(this);
#endif
}
// static
bool
FunctionBrokerParent::RunBrokeredFunction(base::ProcessId aClientId,
const FunctionHookId &aFunctionId,
const IPC::IpdlTuple &aInTuple,
IPC::IpdlTuple *aOutTuple)
{
if ((size_t)aFunctionId >= FunctionHook::GetHooks()->Length()) {
MOZ_ASSERT_UNREACHABLE("Invalid function ID");
return false;
}
FunctionHook* hook = FunctionHook::GetHooks()->ElementAt(aFunctionId);
MOZ_ASSERT(hook->FunctionId() == aFunctionId);
return hook->RunOriginalFunction(aClientId, aInTuple, aOutTuple);
}
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
mozilla::SandboxPermissions FunctionBrokerParent::sSandboxPermissions;
// static
void
FunctionBrokerParent::RemovePermissionsForProcess(base::ProcessId aClientId)
{
sSandboxPermissions.RemovePermissionsForProcess(aClientId);
}
#endif // defined(XP_WIN) && defined(MOZ_SANDBOX)
} // namespace plugins
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=4 et :
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_plugins_functionbrokerparent_h
#define mozilla_plugins_functionbrokerparent_h
#include "mozilla/plugins/PFunctionBrokerParent.h"
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
#include "sandboxPermissions.h"
#endif
namespace mozilla {
namespace plugins {
class FunctionBrokerThread;
/**
* Top-level actor run on the process to which we broker calls from sandboxed
* plugin processes.
*/
class FunctionBrokerParent : public PFunctionBrokerParent
{
public:
static FunctionBrokerParent* Create(Endpoint<PFunctionBrokerParent>&& aParentEnd);
static void Destroy(FunctionBrokerParent* aInst);
void ActorDestroy(ActorDestroyReason aWhy) override;
mozilla::ipc::IPCResult
RecvBrokerFunction(const FunctionHookId &aFunctionId, const IpdlTuple &aInTuple,
IpdlTuple *aOutTuple) override;
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
static mozilla::SandboxPermissions*
GetSandboxPermissions() { return &sSandboxPermissions; }
#endif // defined(XP_WIN) && defined(MOZ_SANDBOX)
private:
explicit FunctionBrokerParent(FunctionBrokerThread* aThread,
Endpoint<PFunctionBrokerParent>&& aParentEnd);
~FunctionBrokerParent();
void ShutdownOnBrokerThread();
void Bind(Endpoint<PFunctionBrokerParent>&& aEnd);
static bool RunBrokeredFunction(base::ProcessId aClientId,
const FunctionHookId &aFunctionId,
const IPC::IpdlTuple &aInTuple,
IPC::IpdlTuple *aOutTuple);
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
static void RemovePermissionsForProcess(base::ProcessId aClientId);
static mozilla::SandboxPermissions sSandboxPermissions;
#endif // defined(XP_WIN) && defined(MOZ_SANDBOX)
nsAutoPtr<FunctionBrokerThread> mThread;
Monitor mMonitor;
bool mShutdownDone;
};
} // namespace plugins
} // namespace mozilla
#endif // mozilla_plugins_functionbrokerparent_hk

Просмотреть файл

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=4 et :
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_plugins_functionbrokerthread_h
#define mozilla_plugins_functionbrokerthread_h
#include "nsThreadManager.h"
namespace mozilla {
namespace plugins {
class FunctionBrokerThread
{
public:
void Dispatch(already_AddRefed<nsIRunnable>&& aRunnable)
{
mThread->Dispatch(Move(aRunnable), nsIEventTarget::NS_DISPATCH_NORMAL);
}
bool IsOnThread()
{
bool on;
return NS_SUCCEEDED(mThread->IsOnCurrentThread(&on)) && on;
}
static FunctionBrokerThread* Create()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIThread> thread;
if (NS_FAILED(NS_NewNamedThread("Function Broker", getter_AddRefs(thread)))) {
return nullptr;
}
return new FunctionBrokerThread(thread);
}
~FunctionBrokerThread()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
mThread->Shutdown();
}
private:
explicit FunctionBrokerThread(nsIThread* aThread) : mThread(aThread)
{
MOZ_ASSERT(mThread);
}
nsCOMPtr<nsIThread> mThread;
};
} // namespace plugins
} // namespace mozilla
#endif // mozilla_plugins_functionbrokerthread_h

Просмотреть файл

@ -0,0 +1,332 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "FunctionHook.h"
#include "FunctionBroker.h"
#include "nsClassHashtable.h"
#include "mozilla/ClearOnShutdown.h"
#if defined(XP_WIN)
#include <shlobj.h>
#endif
namespace mozilla {
namespace plugins {
StaticAutoPtr<FunctionHookArray> FunctionHook::sFunctionHooks;
bool AlwaysHook(int) { return true; }
FunctionHookArray*
FunctionHook::GetHooks()
{
if (sFunctionHooks) {
return sFunctionHooks;
}
// sFunctionHooks is the StaticAutoPtr to the singleton array of FunctionHook
// objects. We free it by clearing the StaticAutoPtr on shutdown.
sFunctionHooks = new FunctionHookArray();
ClearOnShutdown(&sFunctionHooks);
sFunctionHooks->SetLength(ID_FunctionHookCount);
AddFunctionHooks(*sFunctionHooks);
AddBrokeredFunctionHooks(*sFunctionHooks);
return sFunctionHooks;
}
void
FunctionHook::HookFunctions(int aQuirks)
{
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Plugin);
FunctionHookArray* hooks = FunctionHook::GetHooks();
MOZ_ASSERT(hooks);
for(size_t i=0; i < hooks->Length(); ++i) {
FunctionHook* mhb = hooks->ElementAt(i);
// Check that the FunctionHook array is in the same order as the
// FunctionHookId enum.
MOZ_ASSERT((size_t)mhb->FunctionId() == i);
mhb->Register(aQuirks);
}
}
#if defined(XP_WIN)
// This cache is created when a DLL is registered with a FunctionHook.
// It is cleared on a call to ClearDllInterceptorCache(). It
// must be freed before exit to avoid leaks.
typedef nsClassHashtable<nsCStringHashKey, WindowsDllInterceptor> DllInterceptors;
DllInterceptors* sDllInterceptorCache = nullptr;
WindowsDllInterceptor*
FunctionHook::GetDllInterceptorFor(const char* aModuleName)
{
if (!sDllInterceptorCache) {
sDllInterceptorCache = new DllInterceptors();
}
WindowsDllInterceptor* ret =
sDllInterceptorCache->LookupOrAdd(nsCString(aModuleName), aModuleName);
MOZ_ASSERT(ret);
return ret;
}
void
FunctionHook::ClearDllInterceptorCache()
{
delete sDllInterceptorCache;
sDllInterceptorCache = nullptr;
}
/* GetWindowInfo */
typedef BasicFunctionHook<ID_GetWindowInfo, decltype(GetWindowInfo)> GetWindowInfoFH;
template<>
ShouldHookFunc* const
GetWindowInfoFH::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_GETWINDOWINFO>;
static const wchar_t * kMozillaWindowClass = L"MozillaWindowClass";
static HWND sBrowserHwnd = nullptr;
BOOL WINAPI
GetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi)
{
if (!pwi) {
return FALSE;
}
MOZ_ASSERT(ID_GetWindowInfo < FunctionHook::GetHooks()->Length());
GetWindowInfoFH* functionHook =
static_cast<GetWindowInfoFH*>(FunctionHook::GetHooks()->ElementAt(ID_GetWindowInfo));
if (!functionHook->OriginalFunction()) {
NS_ASSERTION(FALSE, "Something is horribly wrong in PHGetWindowInfoHook!");
return FALSE;
}
if (!sBrowserHwnd) {
wchar_t szClass[20];
// GetClassNameW returns the length it copied w/o null terminator.
// Therefore, if the name and null-terminator fit then it returns a
// value less than the buffer's length.
int nameLen = GetClassNameW(hWnd, szClass, ArrayLength(szClass));
if ((nameLen < (int)ArrayLength(szClass)) &&
!wcscmp(szClass, kMozillaWindowClass)) {
sBrowserHwnd = hWnd;
}
}
// Oddity: flash does strange rect comparisons for mouse input destined for
// it's internal settings window. Post removing sub widgets for tabs, touch
// this up so they get the rect they expect.
// XXX potentially tie this to a specific major version?
typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi);
GetWindowInfoPtr gwiFunc =
static_cast<GetWindowInfoPtr>(functionHook->OriginalFunction());
BOOL result = gwiFunc(hWnd, pwi);
if (sBrowserHwnd && sBrowserHwnd == hWnd) {
pwi->rcWindow = pwi->rcClient;
}
return result;
}
/* PrintDlgW */
typedef BasicFunctionHook<ID_PrintDlgW, decltype(PrintDlgW)> PrintDlgWFH;
template<>
ShouldHookFunc* const
PrintDlgWFH::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_PRINTDLGW>;
BOOL WINAPI PrintDlgWHook(LPPRINTDLGW aDlg)
{
// Zero out the HWND supplied by the plugin. We are sacrificing window
// parentage for the ability to run in the NPAPI sandbox.
HWND hwnd = aDlg->hwndOwner;
aDlg->hwndOwner = 0;
MOZ_ASSERT(ID_PrintDlgW < FunctionHook::GetHooks()->Length());
PrintDlgWFH* functionHook =
static_cast<PrintDlgWFH*>(FunctionHook::GetHooks()->ElementAt(ID_PrintDlgW));
MOZ_ASSERT(functionHook);
BOOL ret = functionHook->OriginalFunction()(aDlg);
aDlg->hwndOwner = hwnd;
return ret;
}
// Hooking CreateFileW for protected-mode magic
static WindowsDllInterceptor sKernel32Intercept;
typedef HANDLE (WINAPI *CreateFileWPtr)(LPCWSTR aFname, DWORD aAccess,
DWORD aShare,
LPSECURITY_ATTRIBUTES aSecurity,
DWORD aCreation, DWORD aFlags,
HANDLE aFTemplate);
static CreateFileWPtr sCreateFileWStub = nullptr;
typedef HANDLE (WINAPI *CreateFileAPtr)(LPCSTR aFname, DWORD aAccess,
DWORD aShare,
LPSECURITY_ATTRIBUTES aSecurity,
DWORD aCreation, DWORD aFlags,
HANDLE aFTemplate);
static CreateFileAPtr sCreateFileAStub = nullptr;
// Windows 8 RTM (kernelbase's version is 6.2.9200.16384) doesn't call
// CreateFileW from CreateFileA.
// So we hook CreateFileA too to use CreateFileW hook.
static HANDLE WINAPI
CreateFileAHookFn(LPCSTR aFname, DWORD aAccess, DWORD aShare,
LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags,
HANDLE aFTemplate)
{
while (true) { // goto out
// Our hook is for mms.cfg into \Windows\System32\Macromed\Flash
// We don't require supporting too long path.
WCHAR unicodeName[MAX_PATH];
size_t len = strlen(aFname);
if (len >= MAX_PATH) {
break;
}
// We call to CreateFileW for workaround of Windows 8 RTM
int newLen = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, aFname,
len, unicodeName, MAX_PATH);
if (newLen == 0 || newLen >= MAX_PATH) {
break;
}
unicodeName[newLen] = '\0';
return CreateFileW(unicodeName, aAccess, aShare, aSecurity, aCreation, aFlags, aFTemplate);
}
return sCreateFileAStub(aFname, aAccess, aShare, aSecurity, aCreation, aFlags,
aFTemplate);
}
static bool
GetLocalLowTempPath(size_t aLen, LPWSTR aPath)
{
NS_NAMED_LITERAL_STRING(tempname, "\\Temp");
LPWSTR path;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0,
nullptr, &path))) {
if (wcslen(path) + tempname.Length() < aLen) {
wcscpy(aPath, path);
wcscat(aPath, tempname.get());
CoTaskMemFree(path);
return true;
}
CoTaskMemFree(path);
}
// XP doesn't support SHGetKnownFolderPath and LocalLow
if (!GetTempPathW(aLen, aPath)) {
return false;
}
return true;
}
HANDLE WINAPI
CreateFileWHookFn(LPCWSTR aFname, DWORD aAccess, DWORD aShare,
LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags,
HANDLE aFTemplate)
{
static const WCHAR kConfigFile[] = L"mms.cfg";
static const size_t kConfigLength = ArrayLength(kConfigFile) - 1;
while (true) { // goto out, in sheep's clothing
size_t len = wcslen(aFname);
if (len < kConfigLength) {
break;
}
if (wcscmp(aFname + len - kConfigLength, kConfigFile) != 0) {
break;
}
// This is the config file we want to rewrite
WCHAR tempPath[MAX_PATH+1];
if (GetLocalLowTempPath(MAX_PATH, tempPath) == 0) {
break;
}
WCHAR tempFile[MAX_PATH+1];
if (GetTempFileNameW(tempPath, L"fx", 0, tempFile) == 0) {
break;
}
HANDLE replacement =
sCreateFileWStub(tempFile, GENERIC_READ | GENERIC_WRITE, aShare,
aSecurity, TRUNCATE_EXISTING,
FILE_ATTRIBUTE_TEMPORARY |
FILE_FLAG_DELETE_ON_CLOSE,
NULL);
if (replacement == INVALID_HANDLE_VALUE) {
break;
}
HANDLE original = sCreateFileWStub(aFname, aAccess, aShare, aSecurity,
aCreation, aFlags, aFTemplate);
if (original != INVALID_HANDLE_VALUE) {
// copy original to replacement
static const size_t kBufferSize = 1024;
char buffer[kBufferSize];
DWORD bytes;
while (ReadFile(original, buffer, kBufferSize, &bytes, NULL)) {
if (bytes == 0) {
break;
}
DWORD wbytes;
WriteFile(replacement, buffer, bytes, &wbytes, NULL);
if (bytes < kBufferSize) {
break;
}
}
CloseHandle(original);
}
static const char kSettingString[] = "\nProtectedMode=0\n";
DWORD wbytes;
WriteFile(replacement, static_cast<const void*>(kSettingString),
sizeof(kSettingString) - 1, &wbytes, NULL);
SetFilePointer(replacement, 0, NULL, FILE_BEGIN);
return replacement;
}
return sCreateFileWStub(aFname, aAccess, aShare, aSecurity, aCreation, aFlags,
aFTemplate);
}
void FunctionHook::HookProtectedMode()
{
// Legacy code. Uses the nsWindowsDLLInterceptor directly instead of
// using the FunctionHook
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Plugin);
WindowsDllInterceptor k32Intercept("kernel32.dll");
k32Intercept.AddHook("CreateFileW",
reinterpret_cast<intptr_t>(CreateFileWHookFn),
(void**) &sCreateFileWStub);
k32Intercept.AddHook("CreateFileA",
reinterpret_cast<intptr_t>(CreateFileAHookFn),
(void**) &sCreateFileAStub);
}
#endif // defined(XP_WIN)
#define FUN_HOOK(x) static_cast<FunctionHook*>(x)
void
FunctionHook::AddFunctionHooks(FunctionHookArray& aHooks)
{
// We transfer ownership of the FunctionHook objects to the array.
#if defined(XP_WIN)
aHooks[ID_GetWindowInfo] =
FUN_HOOK(new GetWindowInfoFH("user32.dll", "GetWindowInfo",
&GetWindowInfo, &GetWindowInfoHook));
aHooks[ID_PrintDlgW] =
FUN_HOOK(new PrintDlgWFH("comdlg32.dll", "PrintDlgW", &PrintDlgW,
PrintDlgWHook));
#endif // defined(XP_WIN)
}
#undef FUN_HOOK
} // namespace plugins
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,183 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef dom_plugins_ipc_functionhook_h
#define dom_plugins_ipc_functionhook_h 1
#include "IpdlTuple.h"
#include "base/process.h"
#if defined(XP_WIN)
#include "nsWindowsDllInterceptor.h"
#endif
namespace mozilla {
namespace plugins {
// "PluginHooks" logging helpers
extern mozilla::LazyLogModule sPluginHooksLog;
#define HOOK_LOG(lvl, msg) MOZ_LOG(mozilla::plugins::sPluginHooksLog, lvl, msg);
inline const char *SuccessMsg(bool aVal) { return aVal ? "succeeded" : "failed"; }
class FunctionHook;
class FunctionHookArray;
class FunctionHook
{
public:
virtual ~FunctionHook() {}
virtual FunctionHookId FunctionId() const = 0;
/**
* Register to hook the function represented by this class.
* Returns false if we should have hooked but didn't.
*/
virtual bool Register(int aQuirks) = 0;
/**
* Run the original function with parameters stored in a tuple.
* This is only supported on server-side and for auto-brokered methods.
*/
virtual bool RunOriginalFunction(base::ProcessId aClientId,
const IPC::IpdlTuple &aInTuple,
IPC::IpdlTuple *aOutTuple) const = 0;
/**
* Hook the Win32 methods needed by the plugin process.
*/
static void HookFunctions(int aQuirks);
static FunctionHookArray* GetHooks();
#if defined(XP_WIN)
/**
* Special handler for hooking some kernel32.dll methods that we use to
* disable Flash protected mode.
*/
static void HookProtectedMode();
/**
* Get the WindowsDllInterceptor for the given module. Creates a cache of
* WindowsDllInterceptors by name.
*/
static WindowsDllInterceptor* GetDllInterceptorFor(const char* aModuleName);
/**
* Must be called to clear the cache created by calls to GetDllInterceptorFor.
*/
static void ClearDllInterceptorCache();
#endif // defined(XP_WIN)
private:
static StaticAutoPtr<FunctionHookArray> sFunctionHooks;
static void AddFunctionHooks(FunctionHookArray& aHooks);
};
// The FunctionHookArray deletes its FunctionHook objects when freed.
class FunctionHookArray : public nsTArray<FunctionHook*> {
public:
~FunctionHookArray()
{
for (uint32_t idx = 0; idx < Length(); ++idx) {
FunctionHook* elt = ElementAt(idx);
MOZ_ASSERT(elt);
delete elt;
}
}
};
// Type of function that returns true if a function should be hooked according to quirks.
typedef bool(ShouldHookFunc)(int aQuirks);
template<FunctionHookId functionId, typename FunctionType>
class BasicFunctionHook : public FunctionHook
{
public:
BasicFunctionHook(const char* aModuleName,
const char* aFunctionName, FunctionType* aOldFunction,
FunctionType* aNewFunction) :
mOldFunction(aOldFunction), mIsHooked(false), mModuleName(aModuleName),
mFunctionName(aFunctionName), mNewFunction(aNewFunction)
{
MOZ_ASSERT(mOldFunction);
MOZ_ASSERT(mNewFunction);
}
/**
* Hooks the function if we haven't already and if ShouldHook() says to.
*/
bool Register(int aQuirks) override;
/**
* Can be specialized to perform "extra" operations when running the
* function on the server side.
*/
bool RunOriginalFunction(base::ProcessId aClientId,
const IPC::IpdlTuple &aInTuple,
IPC::IpdlTuple *aOutTuple) const override { return false; }
FunctionHookId FunctionId() const override { return functionId; }
FunctionType* OriginalFunction() const { return mOldFunction; }
protected:
// Once the function is hooked, this field will take the value of a pointer to
// a function that performs the old behavior. Before that, it is a pointer to
// the original function.
FunctionType* mOldFunction;
// True if we have already hooked the function.
bool mIsHooked;
// The name of the module containing the function to hook. E.g. "user32.dll".
const nsCString mModuleName;
// The name of the function in the module.
const nsCString mFunctionName;
// The function that we should replace functionName with. The signature of
// newFunction must match that of functionName.
FunctionType* const mNewFunction;
static ShouldHookFunc* const mShouldHook;
};
// Default behavior is to hook every registered function.
extern bool AlwaysHook(int);
template<FunctionHookId functionId, typename FunctionType>
ShouldHookFunc* const BasicFunctionHook<functionId, FunctionType>::mShouldHook = AlwaysHook;
template <FunctionHookId functionId, typename FunctionType>
bool
BasicFunctionHook<functionId, FunctionType>::Register(int aQuirks)
{
MOZ_RELEASE_ASSERT(XRE_IsPluginProcess());
// If we have already hooked or if quirks tell us not to then don't hook.
if (mIsHooked || !mShouldHook(aQuirks)) {
return true;
}
#if defined(XP_WIN)
WindowsDllInterceptor* dllInterceptor =
FunctionHook::GetDllInterceptorFor(mModuleName.Data());
if (!dllInterceptor) {
return false;
}
mIsHooked =
dllInterceptor->AddHook(mFunctionName.Data(), reinterpret_cast<intptr_t>(mNewFunction),
reinterpret_cast<void**>(&mOldFunction));
#endif
HOOK_LOG(LogLevel::Debug,
("Registering to intercept function '%s' : '%s'", mFunctionName.Data(),
SuccessMsg(mIsHooked)));
return mIsHooked;
}
}
}
#endif // dom_plugins_ipc_functionhook_h

184
dom/plugins/ipc/IpdlTuple.h Normal file
Просмотреть файл

@ -0,0 +1,184 @@
#ifndef dom_plugins_ipc_ipdltuple_h
#define dom_plugins_ipc_ipdltuple_h
#include "mozilla/plugins/FunctionBrokerIPCUtils.h"
#include "mozilla/Variant.h"
namespace mozilla {
namespace plugins {
/**
* IpdlTuple is used by automatic function brokering to pass parameter
* lists for brokered functions. It supports a limited set of types
* (see IpdlTuple::IpdlTupleElement).
*/
class IpdlTuple
{
public:
uint32_t NumElements() const { return mTupleElements.Length(); }
template<typename EltType>
EltType* Element(uint32_t index)
{
if ((index >= mTupleElements.Length()) ||
!mTupleElements[index].GetVariant().is<EltType>()) {
return nullptr;
}
return &mTupleElements[index].GetVariant().as<EltType>();
}
template<typename EltType>
const EltType* Element(uint32_t index) const
{
return const_cast<IpdlTuple*>(this)->Element<EltType>(index);
}
template <typename EltType>
void AddElement(const EltType& aElt)
{
IpdlTupleElement* newEntry = mTupleElements.AppendElement();
newEntry->Set(aElt);
}
private:
struct InvalidType {};
// Like Variant but with a default constructor.
template <typename ... Types>
struct MaybeVariant
{
public:
MaybeVariant() : mValue(InvalidType()) {}
MaybeVariant(MaybeVariant&& o) : mValue(Move(o.mValue)) {}
template <typename Param> void Set(const Param& aParam)
{
mValue = mozilla::AsVariant(aParam);
}
typedef mozilla::Variant<InvalidType, Types...> MaybeVariantType;
MaybeVariantType& GetVariant() { return mValue; }
const MaybeVariantType& GetVariant() const { return mValue; }
private:
MaybeVariantType mValue;
};
#if defined(XP_WIN)
typedef MaybeVariant<int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,
int64_t,uint64_t,nsCString,bool,OpenFileNameIPC,
OpenFileNameRetIPC,NativeWindowHandle,
IPCSchannelCred,IPCInternetBuffers,StringArray,
IPCPrintDlg> IpdlTupleElement;
#else
typedef MaybeVariant<int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,
int64_t,uint64_t,nsCString,bool> IpdlTupleElement;
#endif // defined(XP_WIN)
friend struct IPC::ParamTraits<IpdlTuple>;
friend struct IPC::ParamTraits<IpdlTuple::IpdlTupleElement>;
friend struct IPC::ParamTraits<IpdlTuple::InvalidType>;
nsTArray<IpdlTupleElement> mTupleElements;
};
template <> template<>
inline void IpdlTuple::IpdlTupleElement::Set<nsDependentCSubstring>(const nsDependentCSubstring& aParam)
{
mValue = MaybeVariantType(mozilla::VariantType<nsCString>(), aParam);
}
} // namespace plugins
} // namespace mozilla
namespace IPC {
using namespace mozilla::plugins;
template <>
struct ParamTraits<IpdlTuple>
{
typedef IpdlTuple paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mTupleElements);
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
paramType* aParam)
{
return ReadParam(aMsg, aIter, &aParam->mTupleElements);
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
LogParam(aParam.mTupleElements, aLog);
}
};
template<>
struct ParamTraits<IpdlTuple::IpdlTupleElement>
{
typedef IpdlTuple::IpdlTupleElement paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
MOZ_RELEASE_ASSERT(!aParam.GetVariant().is<IpdlTuple::InvalidType>());
WriteParam(aMsg, aParam.GetVariant());
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
paramType* aParam)
{
bool ret = ReadParam(aMsg, aIter, &aParam->GetVariant());
MOZ_RELEASE_ASSERT(!aParam->GetVariant().is<IpdlTuple::InvalidType>());
return ret;
}
struct LogMatcher
{
explicit LogMatcher(std::wstring* aLog) : mLog(aLog) {}
template <typename EntryType>
void match(const EntryType& aParam)
{
LogParam(aParam, mLog);
}
private:
std::wstring* mLog;
};
static void Log(const paramType& aParam, std::wstring* aLog)
{
aParam.GetVariant().match(LogMatcher(aLog));
}
};
template<>
struct ParamTraits<IpdlTuple::InvalidType>
{
typedef IpdlTuple::InvalidType paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
MOZ_ASSERT_UNREACHABLE("Attempt to serialize an invalid tuple element");
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
paramType* aParam)
{
MOZ_ASSERT_UNREACHABLE("Attempt to deserialize an invalid tuple element");
return false;
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
aLog->append(L"<Invalid Tuple Entry>");
}
};
} // namespace IPC
#endif /* dom_plugins_ipc_ipdltuple_h */

Просмотреть файл

@ -0,0 +1,23 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
using mozilla::plugins::FunctionHookId from "mozilla/plugins/FunctionBrokerIPCUtils.h";
using IPC::IpdlTuple from "mozilla/plugins/IpdlTuple.h";
namespace mozilla {
namespace plugins {
/**
* Top-level actor that brokers functions for the client process.
*/
sync protocol PFunctionBroker
{
parent:
sync BrokerFunction(FunctionHookId aFunctionId, IpdlTuple aFunctionParams)
returns (IpdlTuple aFunctionRet);
};
} // namespace plugins
} // namespace mozilla

Просмотреть файл

@ -7,6 +7,7 @@ include protocol PPluginInstance;
include protocol PPluginScriptableObject;
include protocol PContent;
include protocol PProfiler;
include protocol PFunctionBroker;
using NPError from "npapi.h";
using NPNVariable from "npapi.h";
@ -14,9 +15,6 @@ using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
using class mac_plugin_interposing::NSCursorInfo from "mozilla/plugins/PluginMessageUtils.h";
using struct nsID from "nsID.h";
using struct mozilla::plugins::NPAudioDeviceChangeDetailsIPC from "mozilla/plugins/PluginMessageUtils.h";
using mozilla::plugins::GetFileNameFunc from "mozilla/plugins/PluginMessageUtils.h";
using mozilla::plugins::OpenFileNameIPC from "mozilla/plugins/PluginMessageUtils.h";
using mozilla::plugins::OpenFileNameRetIPC from "mozilla/plugins/PluginMessageUtils.h";
namespace mozilla {
namespace plugins {
@ -98,6 +96,8 @@ child:
async InitPluginModuleChild(Endpoint<PPluginModuleChild> endpoint);
async InitPluginFunctionBroker(Endpoint<PFunctionBrokerChild> endpoint);
parent:
/**
* This message is only used on X11 platforms.
@ -145,17 +145,8 @@ parent:
async ReturnSitesWithData(nsCString[] aSites, uint64_t aCallbackId);
intr GetKeyState(int32_t aVirtKey)
returns (int16_t aState);
intr NPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(bool shouldRegister)
returns (NPError result);
// Used to broker the GetOpenFileName/GetSaveFileName file pickers on Windows.
intr GetFileName(GetFileNameFunc aFunc, OpenFileNameIPC aOfnIn)
returns (OpenFileNameRetIPC aOfnOut, bool aResult);
intr SetCursorPos(int x, int y) returns (bool aResult);
};
} // namespace plugins

Просмотреть файл

@ -152,196 +152,5 @@ void DeferNPVariantLastRelease(const NPNetscapeFuncs* f, NPVariant* v)
VOID_TO_NPVARIANT(*v);
}
#ifdef XP_WIN
void
OpenFileNameIPC::CopyFromOfn(LPOPENFILENAMEW aLpofn)
{
mHwndOwner = nullptr;
// Filter is double-NULL terminated. mFilter should include the double-NULL.
mHasFilter = aLpofn->lpstrFilter != nullptr;
if (mHasFilter) {
uint32_t dNullIdx = 0;
while (aLpofn->lpstrFilter[dNullIdx] != L'\0' ||
aLpofn->lpstrFilter[dNullIdx+1] != L'\0') {
dNullIdx++;
}
mFilter.assign(aLpofn->lpstrFilter, dNullIdx+2);
}
mHasCustomFilter = aLpofn->lpstrCustomFilter != nullptr;
if (mHasCustomFilter) {
mCustomFilterIn = std::wstring(aLpofn->lpstrCustomFilter);
mNMaxCustFilterOut =
aLpofn->nMaxCustFilter - (wcslen(aLpofn->lpstrCustomFilter) + 1);
}
else {
mNMaxCustFilterOut = 0;
}
mFilterIndex = aLpofn->nFilterIndex;
mFile = std::wstring(aLpofn->lpstrFile);
mNMaxFile = aLpofn->nMaxFile;
mNMaxFileTitle =
aLpofn->lpstrFileTitle != nullptr ? aLpofn->nMaxFileTitle : 0;
mHasInitialDir = aLpofn->lpstrInitialDir != nullptr;
if (mHasInitialDir) {
mInitialDir = std::wstring(aLpofn->lpstrInitialDir);
}
mHasTitle = aLpofn->lpstrTitle != nullptr;
if (mHasTitle) {
mTitle = std::wstring(aLpofn->lpstrTitle);
}
mHasDefExt = aLpofn->lpstrDefExt != nullptr;
if (mHasDefExt) {
mDefExt = std::wstring(aLpofn->lpstrDefExt);
}
mFlags = aLpofn->Flags;
// If the user sets OFN_ALLOWMULTISELECT then we require OFN_EXPLORER
// as well. Without OFN_EXPLORER, the method has ancient legacy
// behavior that we don't support.
MOZ_ASSERT((mFlags & OFN_EXPLORER) || !(mFlags & OFN_ALLOWMULTISELECT));
// We ignore any visual customization and callbacks that the user set.
mFlags &= ~(OFN_ENABLEHOOK | OFN_ENABLETEMPLATEHANDLE | OFN_ENABLETEMPLATE);
mFlagsEx = aLpofn->FlagsEx;
}
void
OpenFileNameIPC::AddToOfn(LPOPENFILENAMEW aLpofn) const
{
aLpofn->lStructSize = sizeof(OPENFILENAMEW);
aLpofn->hwndOwner = mHwndOwner;
if (mHasFilter) {
memcpy(const_cast<LPWSTR>(aLpofn->lpstrFilter),
mFilter.data(), mFilter.size() * sizeof(wchar_t));
}
if (mHasCustomFilter) {
aLpofn->nMaxCustFilter = mCustomFilterIn.size() + 1 + mNMaxCustFilterOut;
wcscpy(aLpofn->lpstrCustomFilter, mCustomFilterIn.c_str());
memset(aLpofn->lpstrCustomFilter + mCustomFilterIn.size() + 1, 0,
mNMaxCustFilterOut * sizeof(wchar_t));
}
else {
aLpofn->nMaxCustFilter = 0;
}
aLpofn->nFilterIndex = mFilterIndex;
if (mNMaxFile > 0) {
wcsncpy(aLpofn->lpstrFile, mFile.c_str(),
std::min(static_cast<uint32_t>(mFile.size()+1), mNMaxFile));
aLpofn->lpstrFile[mNMaxFile - 1] = L'\0';
}
aLpofn->nMaxFile = mNMaxFile;
aLpofn->nMaxFileTitle = mNMaxFileTitle;
if (mHasInitialDir) {
wcscpy(const_cast<LPWSTR>(aLpofn->lpstrInitialDir), mInitialDir.c_str());
}
if (mHasTitle) {
wcscpy(const_cast<LPWSTR>(aLpofn->lpstrTitle), mTitle.c_str());
}
aLpofn->Flags = mFlags; /* TODO: Consider adding OFN_NOCHANGEDIR */
if (mHasDefExt) {
wcscpy(const_cast<LPWSTR>(aLpofn->lpstrDefExt), mDefExt.c_str());
}
aLpofn->FlagsEx = mFlagsEx;
}
void
OpenFileNameIPC::AllocateOfnStrings(LPOPENFILENAMEW aLpofn) const
{
if (mHasFilter) {
// mFilter is double-NULL terminated and it includes the double-NULL in its length.
aLpofn->lpstrFilter =
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mFilter.size())));
}
if (mHasCustomFilter) {
aLpofn->lpstrCustomFilter =
static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * (mCustomFilterIn.size() + 1 + mNMaxCustFilterOut)));
}
aLpofn->lpstrFile =
static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * mNMaxFile));
if (mNMaxFileTitle > 0) {
aLpofn->lpstrFileTitle =
static_cast<LPTSTR>(moz_xmalloc(sizeof(wchar_t) * mNMaxFileTitle));
}
if (mHasInitialDir) {
aLpofn->lpstrInitialDir =
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mInitialDir.size() + 1)));
}
if (mHasTitle) {
aLpofn->lpstrTitle =
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mTitle.size() + 1)));
}
if (mHasDefExt) {
aLpofn->lpstrDefExt =
static_cast<LPCTSTR>(moz_xmalloc(sizeof(wchar_t) * (mDefExt.size() + 1)));
}
}
void
OpenFileNameIPC::FreeOfnStrings(LPOPENFILENAMEW aLpofn) const
{
if (aLpofn->lpstrFilter) {
free(const_cast<LPWSTR>(aLpofn->lpstrFilter));
}
if (aLpofn->lpstrCustomFilter) {
free(aLpofn->lpstrCustomFilter);
}
if (aLpofn->lpstrFile) {
free(aLpofn->lpstrFile);
}
if (aLpofn->lpstrFileTitle) {
free(aLpofn->lpstrFileTitle);
}
if (aLpofn->lpstrInitialDir) {
free(const_cast<LPWSTR>(aLpofn->lpstrInitialDir));
}
if (aLpofn->lpstrTitle) {
free(const_cast<LPWSTR>(aLpofn->lpstrTitle));
}
if (aLpofn->lpstrDefExt) {
free(const_cast<LPWSTR>(aLpofn->lpstrDefExt));
}
}
void
OpenFileNameRetIPC::CopyFromOfn(LPOPENFILENAMEW aLpofn)
{
if (aLpofn->lpstrCustomFilter != nullptr) {
mCustomFilterOut =
std::wstring(aLpofn->lpstrCustomFilter + wcslen(aLpofn->lpstrCustomFilter) + 1);
}
mFile.assign(aLpofn->lpstrFile, aLpofn->nMaxFile);
if (aLpofn->lpstrFileTitle != nullptr) {
mFileTitle.assign(aLpofn->lpstrFileTitle, wcslen(aLpofn->lpstrFileTitle) + 1);
}
mFileOffset = aLpofn->nFileOffset;
mFileExtension = aLpofn->nFileExtension;
}
void
OpenFileNameRetIPC::AddToOfn(LPOPENFILENAMEW aLpofn) const
{
if (aLpofn->lpstrCustomFilter) {
LPWSTR secondString =
aLpofn->lpstrCustomFilter + wcslen(aLpofn->lpstrCustomFilter) + 1;
const wchar_t* customFilterOut = mCustomFilterOut.c_str();
MOZ_ASSERT(wcslen(aLpofn->lpstrCustomFilter) + 1 +
wcslen(customFilterOut) + 1 + 1 <= aLpofn->nMaxCustFilter);
wcscpy(secondString, customFilterOut);
secondString[wcslen(customFilterOut) + 1] = L'\0'; // terminated with two NULLs
}
MOZ_ASSERT(mFile.size() <= aLpofn->nMaxFile);
memcpy(aLpofn->lpstrFile,
mFile.data(), mFile.size() * sizeof(wchar_t));
if (aLpofn->lpstrFileTitle != nullptr) {
MOZ_ASSERT(mFileTitle.size() + 1 < aLpofn->nMaxFileTitle);
wcscpy(aLpofn->lpstrFileTitle, mFileTitle.c_str());
}
aLpofn->nFileOffset = mFileOffset;
aLpofn->nFileExtension = mFileExtension;
}
#endif // XP_WIN
} // namespace plugins
} // namespace mozilla

Просмотреть файл

@ -32,9 +32,6 @@
namespace mac_plugin_interposing { class NSCursorInfo { }; }
#endif
using mac_plugin_interposing::NSCursorInfo;
#ifdef XP_WIN
#include "commdlg.h"
#endif
namespace mozilla {
namespace plugins {
@ -126,59 +123,9 @@ typedef intptr_t NativeWindowHandle; // never actually used, will always be 0
#ifdef XP_WIN
typedef base::SharedMemoryHandle WindowsSharedMemoryHandle;
typedef HANDLE DXGISharedSurfaceHandle;
// Values indicate GetOpenFileNameW and GetSaveFileNameW.
enum GetFileNameFunc { OPEN_FUNC, SAVE_FUNC };
// IPC-capable version of the Windows OPENFILENAMEW struct.
typedef struct _OpenFileNameIPC
{
// Allocates memory for the strings in this object. This should usually
// be used with a zeroed out OPENFILENAMEW structure.
void AllocateOfnStrings(LPOPENFILENAMEW aLpofn) const;
void FreeOfnStrings(LPOPENFILENAMEW aLpofn) const;
void AddToOfn(LPOPENFILENAMEW aLpofn) const;
void CopyFromOfn(LPOPENFILENAMEW aLpofn);
NativeWindowHandle mHwndOwner;
std::wstring mFilter; // Double-NULL terminated (i.e. L"\0\0") if mHasFilter is true
bool mHasFilter;
std::wstring mCustomFilterIn;
bool mHasCustomFilter;
uint32_t mNMaxCustFilterOut;
uint32_t mFilterIndex;
std::wstring mFile;
uint32_t mNMaxFile;
uint32_t mNMaxFileTitle;
std::wstring mInitialDir;
bool mHasInitialDir;
std::wstring mTitle;
bool mHasTitle;
uint32_t mFlags;
std::wstring mDefExt;
bool mHasDefExt;
uint32_t mFlagsEx;
} OpenFileNameIPC;
// GetOpenFileNameW and GetSaveFileNameW overwrite fields of their OPENFILENAMEW
// parameter. This represents those values so that they can be returned via IPC.
typedef struct _OpenFileNameRetIPC
{
void CopyFromOfn(LPOPENFILENAMEW aLpofn);
void AddToOfn(LPOPENFILENAMEW aLpofn) const;
std::wstring mCustomFilterOut;
std::wstring mFile; // Double-NULL terminated (i.e. L"\0\0")
std::wstring mFileTitle;
uint16_t mFileOffset;
uint16_t mFileExtension;
} OpenFileNameRetIPC;
#else // XP_WIN
typedef mozilla::null_t WindowsSharedMemoryHandle;
typedef mozilla::null_t DXGISharedSurfaceHandle;
typedef mozilla::null_t GetFileNameFunc;
typedef mozilla::null_t OpenFileNameIPC;
typedef mozilla::null_t OpenFileNameRetIPC;
#endif
// XXX maybe not the best place for these. better one?
@ -707,109 +654,6 @@ struct ParamTraits<mozilla::plugins::NPAudioDeviceChangeDetailsIPC>
}
};
#ifdef XP_WIN
template <>
struct ParamTraits<mozilla::plugins::_OpenFileNameIPC>
{
typedef mozilla::plugins::_OpenFileNameIPC paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mHwndOwner);
WriteParam(aMsg, aParam.mFilter);
WriteParam(aMsg, aParam.mHasFilter);
WriteParam(aMsg, aParam.mCustomFilterIn);
WriteParam(aMsg, aParam.mHasCustomFilter);
WriteParam(aMsg, aParam.mNMaxCustFilterOut);
WriteParam(aMsg, aParam.mFilterIndex);
WriteParam(aMsg, aParam.mFile);
WriteParam(aMsg, aParam.mNMaxFile);
WriteParam(aMsg, aParam.mNMaxFileTitle);
WriteParam(aMsg, aParam.mInitialDir);
WriteParam(aMsg, aParam.mHasInitialDir);
WriteParam(aMsg, aParam.mTitle);
WriteParam(aMsg, aParam.mHasTitle);
WriteParam(aMsg, aParam.mFlags);
WriteParam(aMsg, aParam.mDefExt);
WriteParam(aMsg, aParam.mHasDefExt);
WriteParam(aMsg, aParam.mFlagsEx);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
if (ReadParam(aMsg, aIter, &aResult->mHwndOwner) &&
ReadParam(aMsg, aIter, &aResult->mFilter) &&
ReadParam(aMsg, aIter, &aResult->mHasFilter) &&
ReadParam(aMsg, aIter, &aResult->mCustomFilterIn) &&
ReadParam(aMsg, aIter, &aResult->mHasCustomFilter) &&
ReadParam(aMsg, aIter, &aResult->mNMaxCustFilterOut) &&
ReadParam(aMsg, aIter, &aResult->mFilterIndex) &&
ReadParam(aMsg, aIter, &aResult->mFile) &&
ReadParam(aMsg, aIter, &aResult->mNMaxFile) &&
ReadParam(aMsg, aIter, &aResult->mNMaxFileTitle) &&
ReadParam(aMsg, aIter, &aResult->mInitialDir) &&
ReadParam(aMsg, aIter, &aResult->mHasInitialDir) &&
ReadParam(aMsg, aIter, &aResult->mTitle) &&
ReadParam(aMsg, aIter, &aResult->mHasTitle) &&
ReadParam(aMsg, aIter, &aResult->mFlags) &&
ReadParam(aMsg, aIter, &aResult->mDefExt) &&
ReadParam(aMsg, aIter, &aResult->mHasDefExt) &&
ReadParam(aMsg, aIter, &aResult->mFlagsEx)) {
return true;
}
return false;
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
aLog->append(StringPrintf(L"[%S, %S, %S, %S]", aParam.mFilter.c_str(),
aParam.mCustomFilterIn.c_str(), aParam.mFile.c_str(),
aParam.mTitle.c_str()));
}
};
template <>
struct ParamTraits<mozilla::plugins::_OpenFileNameRetIPC>
{
typedef mozilla::plugins::_OpenFileNameRetIPC paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mCustomFilterOut);
WriteParam(aMsg, aParam.mFile);
WriteParam(aMsg, aParam.mFileTitle);
WriteParam(aMsg, aParam.mFileOffset);
WriteParam(aMsg, aParam.mFileExtension);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
if (ReadParam(aMsg, aIter, &aResult->mCustomFilterOut) &&
ReadParam(aMsg, aIter, &aResult->mFile) &&
ReadParam(aMsg, aIter, &aResult->mFileTitle) &&
ReadParam(aMsg, aIter, &aResult->mFileOffset) &&
ReadParam(aMsg, aIter, &aResult->mFileExtension)) {
return true;
}
return false;
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
aLog->append(StringPrintf(L"[%S, %S, %S, %d, %d]", aParam.mCustomFilterOut.c_str(),
aParam.mFile.c_str(), aParam.mFileTitle.c_str(),
aParam.mFileOffset, aParam.mFileExtension));
}
};
template <>
struct ParamTraits<mozilla::plugins::GetFileNameFunc> :
public ContiguousEnumSerializerInclusive<mozilla::plugins::GetFileNameFunc,
mozilla::plugins::OPEN_FUNC,
mozilla::plugins::SAVE_FUNC>
{};
#endif // XP_WIN
} /* namespace IPC */

Просмотреть файл

@ -37,12 +37,12 @@
#include "mozilla/Unused.h"
#include "nsNPAPIPlugin.h"
#include "FunctionHook.h"
#include "FunctionBrokerChild.h"
#ifdef XP_WIN
#include "nsWindowsDllInterceptor.h"
#include "mozilla/widget/AudioSession.h"
#include <knownfolders.h>
#include <shlobj.h>
#endif
#ifdef MOZ_WIDGET_COCOA
@ -61,7 +61,6 @@ using namespace mozilla::widget;
#if defined(XP_WIN)
const wchar_t * kFlashFullscreenClass = L"ShockwaveFlashFullScreen";
const wchar_t * kMozillaWindowClass = L"MozillaWindowClass";
#endif
namespace {
@ -70,49 +69,8 @@ PluginModuleChild* gChromeInstance = nullptr;
} // namespace
#ifdef XP_WIN
// Hooking CreateFileW for protected-mode magic
static WindowsDllInterceptor sKernel32Intercept;
typedef HANDLE (WINAPI *CreateFileWPtr)(LPCWSTR fname, DWORD access,
DWORD share,
LPSECURITY_ATTRIBUTES security,
DWORD creation, DWORD flags,
HANDLE ftemplate);
static CreateFileWPtr sCreateFileWStub = nullptr;
typedef HANDLE (WINAPI *CreateFileAPtr)(LPCSTR fname, DWORD access,
DWORD share,
LPSECURITY_ATTRIBUTES security,
DWORD creation, DWORD flags,
HANDLE ftemplate);
static CreateFileAPtr sCreateFileAStub = nullptr;
// Used with fix for flash fullscreen window loosing focus.
static bool gDelayFlashFocusReplyUntilEval = false;
// Used to fix GetWindowInfo problems with internal flash settings dialogs
static WindowsDllInterceptor sUser32Intercept;
typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi);
static GetWindowInfoPtr sGetWindowInfoPtrStub = nullptr;
static HWND sBrowserHwnd = nullptr;
// sandbox process doesn't get current key states. So we need get it on chrome.
typedef SHORT (WINAPI *GetKeyStatePtr)(int);
static GetKeyStatePtr sGetKeyStatePtrStub = nullptr;
static WindowsDllInterceptor sComDlg32Intercept;
// proxy GetSaveFileName/GetOpenFileName on chrome so that we can know which
// files the user has given permission to access
// We count on GetOpenFileNameA/GetSaveFileNameA calling
// GetOpenFileNameW/GetSaveFileNameW so we don't proxy them explicitly.
typedef BOOL (WINAPI *GetOpenFileNameWPtr)(LPOPENFILENAMEW lpofn);
static GetOpenFileNameWPtr sGetOpenFileNameWPtrStub = nullptr;
typedef BOOL (WINAPI *GetSaveFileNameWPtr)(LPOPENFILENAMEW lpofn);
static GetSaveFileNameWPtr sGetSaveFileNameWPtrStub = nullptr;
typedef BOOL (WINAPI *SetCursorPosPtr)(int x, int y);
static SetCursorPosPtr sSetCursorPosPtrStub = nullptr;
typedef BOOL (WINAPI *PrintDlgWPtr)(LPPRINTDLGW aDlg);
static PrintDlgWPtr sPrintDlgWPtrStub = nullptr;
#endif
/* static */
@ -226,7 +184,7 @@ PluginModuleChild::RecvDisableFlashProtectedMode()
{
MOZ_ASSERT(mIsChrome);
#ifdef XP_WIN
HookProtectedMode();
FunctionHook::HookProtectedMode();
#else
MOZ_ASSERT(false, "Should not be called");
#endif
@ -744,6 +702,21 @@ PluginModuleChild::RecvInitPluginModuleChild(Endpoint<PPluginModuleChild>&& aEnd
return IPC_OK();
}
mozilla::ipc::IPCResult
PluginModuleChild::RecvInitPluginFunctionBroker(Endpoint<PFunctionBrokerChild>&& aEndpoint)
{
#if defined(XP_WIN)
MOZ_ASSERT(mIsChrome);
if (!FunctionBrokerChild::Initialize(Move(aEndpoint))) {
return IPC_FAIL(this,
"InitPluginFunctionBroker failed to initialize broker child.");
}
return IPC_OK();
#else
return IPC_FAIL(this, "InitPluginFunctionBroker not supported on this platform.");
#endif
}
mozilla::ipc::IPCResult
PluginModuleChild::AnswerInitCrashReporter(Shmem&& aShmem, mozilla::dom::NativeThreadId* aOutId)
@ -787,6 +760,11 @@ PluginModuleChild::ActorDestroy(ActorDestroyReason why)
NP_Shutdown();
}
#if defined(XP_WIN)
FunctionBrokerChild::Destroy();
FunctionHook::ClearDllInterceptorCache();
#endif
// doesn't matter why we're being destroyed; it's up to us to
// initiate (clean) shutdown
CrashReporterClient::DestroySingleton();
@ -1789,426 +1767,6 @@ PluginModuleChild::DoNP_Initialize(const PluginSettings& aSettings)
return result;
}
#if defined(XP_WIN)
// Windows 8 RTM (kernelbase's version is 6.2.9200.16384) doesn't call
// CreateFileW from CreateFileA.
// So we hook CreateFileA too to use CreateFileW hook.
static HANDLE WINAPI
CreateFileAHookFn(LPCSTR fname, DWORD access, DWORD share,
LPSECURITY_ATTRIBUTES security, DWORD creation, DWORD flags,
HANDLE ftemplate)
{
while (true) { // goto out
// Our hook is for mms.cfg into \Windows\System32\Macromed\Flash
// We don't requrie supporting too long path.
WCHAR unicodeName[MAX_PATH];
size_t len = strlen(fname);
if (len >= MAX_PATH) {
break;
}
// We call to CreateFileW for workaround of Windows 8 RTM
int newLen = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, fname,
len, unicodeName, MAX_PATH);
if (newLen == 0 || newLen >= MAX_PATH) {
break;
}
unicodeName[newLen] = '\0';
return CreateFileW(unicodeName, access, share, security, creation, flags, ftemplate);
}
return sCreateFileAStub(fname, access, share, security, creation, flags,
ftemplate);
}
static bool
GetLocalLowTempPath(size_t aLen, LPWSTR aPath)
{
NS_NAMED_LITERAL_STRING(tempname, "\\Temp");
LPWSTR path;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0,
nullptr, &path))) {
if (wcslen(path) + tempname.Length() < aLen) {
wcscpy(aPath, path);
wcscat(aPath, tempname.get());
::CoTaskMemFree(path);
return true;
}
::CoTaskMemFree(path);
}
// XP doesn't support SHGetKnownFolderPath and LocalLow
if (!GetTempPathW(aLen, aPath)) {
return false;
}
return true;
}
HANDLE WINAPI
CreateFileWHookFn(LPCWSTR fname, DWORD access, DWORD share,
LPSECURITY_ATTRIBUTES security, DWORD creation, DWORD flags,
HANDLE ftemplate)
{
static const WCHAR kConfigFile[] = L"mms.cfg";
static const size_t kConfigLength = ArrayLength(kConfigFile) - 1;
while (true) { // goto out, in sheep's clothing
size_t len = wcslen(fname);
if (len < kConfigLength) {
break;
}
if (wcscmp(fname + len - kConfigLength, kConfigFile) != 0) {
break;
}
// This is the config file we want to rewrite
WCHAR tempPath[MAX_PATH+1];
if (GetLocalLowTempPath(MAX_PATH, tempPath) == 0) {
break;
}
WCHAR tempFile[MAX_PATH+1];
if (GetTempFileNameW(tempPath, L"fx", 0, tempFile) == 0) {
break;
}
HANDLE replacement =
sCreateFileWStub(tempFile, GENERIC_READ | GENERIC_WRITE, share,
security, TRUNCATE_EXISTING,
FILE_ATTRIBUTE_TEMPORARY |
FILE_FLAG_DELETE_ON_CLOSE,
NULL);
if (replacement == INVALID_HANDLE_VALUE) {
break;
}
HANDLE original = sCreateFileWStub(fname, access, share, security,
creation, flags, ftemplate);
if (original != INVALID_HANDLE_VALUE) {
// copy original to replacement
static const size_t kBufferSize = 1024;
char buffer[kBufferSize];
DWORD bytes;
while (ReadFile(original, buffer, kBufferSize, &bytes, NULL)) {
if (bytes == 0) {
break;
}
DWORD wbytes;
WriteFile(replacement, buffer, bytes, &wbytes, NULL);
if (bytes < kBufferSize) {
break;
}
}
CloseHandle(original);
}
static const char kSettingString[] = "\nProtectedMode=0\n";
DWORD wbytes;
WriteFile(replacement, static_cast<const void*>(kSettingString),
sizeof(kSettingString) - 1, &wbytes, NULL);
SetFilePointer(replacement, 0, NULL, FILE_BEGIN);
return replacement;
}
return sCreateFileWStub(fname, access, share, security, creation, flags,
ftemplate);
}
void
PluginModuleChild::HookProtectedMode()
{
sKernel32Intercept.Init("kernel32.dll");
sKernel32Intercept.AddHook("CreateFileW",
reinterpret_cast<intptr_t>(CreateFileWHookFn),
(void**) &sCreateFileWStub);
sKernel32Intercept.AddHook("CreateFileA",
reinterpret_cast<intptr_t>(CreateFileAHookFn),
(void**) &sCreateFileAStub);
}
BOOL WINAPI
PMCGetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi)
{
if (!pwi)
return FALSE;
if (!sGetWindowInfoPtrStub) {
NS_ASSERTION(FALSE, "Something is horribly wrong in PMCGetWindowInfoHook!");
return FALSE;
}
if (!sBrowserHwnd) {
wchar_t szClass[20];
if (GetClassNameW(hWnd, szClass, ArrayLength(szClass)) &&
!wcscmp(szClass, kMozillaWindowClass)) {
sBrowserHwnd = hWnd;
}
}
// Oddity: flash does strange rect comparisons for mouse input destined for
// it's internal settings window. Post removing sub widgets for tabs, touch
// this up so they get the rect they expect.
// XXX potentially tie this to a specific major version?
BOOL result = sGetWindowInfoPtrStub(hWnd, pwi);
if (sBrowserHwnd && sBrowserHwnd == hWnd)
pwi->rcWindow = pwi->rcClient;
return result;
}
SHORT WINAPI PMCGetKeyState(int aVirtKey);
// Runnable that performs GetKeyState on the main thread so that it can be
// synchronously run on the PluginModuleParent via IPC.
// The task alerts the given semaphore when it is finished.
class GetKeyStateTask : public Runnable
{
SHORT* mKeyState;
int mVirtKey;
HANDLE mSemaphore;
public:
explicit GetKeyStateTask(int aVirtKey, HANDLE aSemaphore, SHORT* aKeyState) :
Runnable("GetKeyStateTask"),
mKeyState(aKeyState),
mVirtKey(aVirtKey),
mSemaphore(aSemaphore)
{}
NS_IMETHOD Run() override
{
PLUGIN_LOG_DEBUG_METHOD;
AssertPluginThread();
*mKeyState = PMCGetKeyState(mVirtKey);
if (!ReleaseSemaphore(mSemaphore, 1, nullptr)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
};
// static
SHORT WINAPI
PMCGetKeyState(int aVirtKey)
{
if (!IsPluginThread()) {
// synchronously request the key state from the main thread
// Start a semaphore at 0. We Release the semaphore (bringing its count to 1)
// when the synchronous call is done.
HANDLE semaphore = CreateSemaphore(NULL, 0, 1, NULL);
if (semaphore == nullptr) {
MOZ_ASSERT(semaphore != nullptr);
return 0;
}
SHORT keyState;
RefPtr<GetKeyStateTask> task = new GetKeyStateTask(aVirtKey, semaphore, &keyState);
ProcessChild::message_loop()->PostTask(task.forget());
DWORD err = WaitForSingleObject(semaphore, INFINITE);
if (err != WAIT_FAILED) {
CloseHandle(semaphore);
return keyState;
}
PLUGIN_LOG_DEBUG(("Error while waiting for GetKeyState semaphore: %d",
GetLastError()));
MOZ_ASSERT(err != WAIT_FAILED);
CloseHandle(semaphore);
return 0;
}
PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
if (chromeInstance) {
int16_t ret = 0;
if (chromeInstance->CallGetKeyState(aVirtKey, &ret)) {
return ret;
}
}
return sGetKeyStatePtrStub(aVirtKey);
}
class PluginThreadTaskData
{
public:
virtual bool RunTask() = 0;
};
// Runnable that performs a task on the main thread so that the call can be
// synchronously run on the PluginModuleParent via IPC.
// The task alerts the given semaphore when it is finished.
class PluginThreadTask : public Runnable
{
bool mSuccess;
PluginThreadTaskData* mTaskData;
HANDLE mSemaphore;
public:
explicit PluginThreadTask(PluginThreadTaskData* aTaskData,
HANDLE aSemaphore) :
Runnable("PluginThreadTask"),
mSuccess(false),
mTaskData(aTaskData),
mSemaphore(aSemaphore)
{}
NS_IMETHOD Run() override
{
PLUGIN_LOG_DEBUG_METHOD;
AssertPluginThread();
mSuccess = mTaskData->RunTask();
if (!ReleaseSemaphore(mSemaphore, 1, nullptr)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
bool Success() { return mSuccess; }
};
// static
BOOL
PostToPluginThread(PluginThreadTaskData* aTaskData)
{
MOZ_ASSERT(!IsPluginThread());
// Synchronously run GetFileNameTask from the main thread.
// Start a semaphore at 0. We release the semaphore (bringing its
// count to 1) when the synchronous call is done.
nsAutoHandle semaphore(CreateSemaphore(NULL, 0, 1, NULL));
if (semaphore == nullptr) {
MOZ_ASSERT(semaphore != nullptr);
return FALSE;
}
RefPtr<PluginThreadTask> task = new PluginThreadTask(aTaskData, semaphore);
ProcessChild::message_loop()->PostTask(do_AddRef(task));
DWORD err = WaitForSingleObject(semaphore, INFINITE);
if (err != WAIT_FAILED) {
return task->Success();
}
PLUGIN_LOG_DEBUG(("Error while waiting for semaphore: %d",
GetLastError()));
MOZ_ASSERT(err != WAIT_FAILED);
return FALSE;
}
BOOL WINAPI PMCGetSaveFileNameW(LPOPENFILENAMEW lpofn);
BOOL WINAPI PMCGetOpenFileNameW(LPOPENFILENAMEW lpofn);
class GetFileNameTaskData : public PluginThreadTaskData
{
public:
GetFileNameTaskData(GetFileNameFunc aFunc, void* aLpOpenFileName) :
mFunc(aFunc), mLpOpenFileName(aLpOpenFileName)
{}
bool RunTask()
{
switch (mFunc) {
case OPEN_FUNC:
return PMCGetOpenFileNameW(static_cast<LPOPENFILENAMEW>(mLpOpenFileName));
case SAVE_FUNC:
return PMCGetSaveFileNameW(static_cast<LPOPENFILENAMEW>(mLpOpenFileName));
}
return false;
}
private:
GetFileNameFunc mFunc;
void* mLpOpenFileName;
};
// static
BOOL WINAPI
PMCGetFileNameW(GetFileNameFunc aFunc, LPOPENFILENAMEW aLpofn)
{
if (!IsPluginThread()) {
GetFileNameTaskData gfnData(aFunc, aLpofn);
return PostToPluginThread(&gfnData);
}
PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
if (chromeInstance) {
bool ret = FALSE;
OpenFileNameIPC inputOfn;
inputOfn.CopyFromOfn(aLpofn);
OpenFileNameRetIPC outputOfn;
if (chromeInstance->CallGetFileName(aFunc, inputOfn,
&outputOfn, &ret)) {
if (ret) {
outputOfn.AddToOfn(aLpofn);
}
}
return ret;
}
switch (aFunc) {
case OPEN_FUNC:
return sGetOpenFileNameWPtrStub(aLpofn);
case SAVE_FUNC:
return sGetSaveFileNameWPtrStub(aLpofn);
}
MOZ_ASSERT_UNREACHABLE("Illegal GetFileNameFunc value");
return FALSE;
}
// static
BOOL WINAPI
PMCGetSaveFileNameW(LPOPENFILENAMEW aLpofn)
{
return PMCGetFileNameW(SAVE_FUNC, aLpofn);
}
// static
BOOL WINAPI
PMCGetOpenFileNameW(LPOPENFILENAMEW aLpofn)
{
return PMCGetFileNameW(OPEN_FUNC, aLpofn);
}
//static
BOOL WINAPI
PMCPrintDlgW(LPPRINTDLGW aDlg)
{
// Zero out the HWND supplied by the plugin. We are sacrificing window
// parentage for the ability to run in the NPAPI sandbox.
HWND hwnd = aDlg->hwndOwner;
aDlg->hwndOwner = 0;
BOOL ret = sPrintDlgWPtrStub(aDlg);
aDlg->hwndOwner = hwnd;
return ret;
}
BOOL WINAPI PMCSetCursorPos(int x, int y);
class SetCursorPosTaskData : public PluginThreadTaskData
{
public:
SetCursorPosTaskData(int x, int y) : mX(x), mY(y) {}
bool RunTask() { return PMCSetCursorPos(mX, mY); }
private:
int mX, mY;
};
// static
BOOL WINAPI
PMCSetCursorPos(int x, int y)
{
if (!IsPluginThread()) {
SetCursorPosTaskData scpData(x, y);
return PostToPluginThread(&scpData);
}
PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
if (chromeInstance) {
bool ret = FALSE;
chromeInstance->CallSetCursorPos(x, y, &ret);
return ret;
}
return sSetCursorPosPtrStub(x, y);
}
#endif
PPluginInstanceChild*
PluginModuleChild::AllocPPluginInstanceChild(const nsCString& aMimeType,
const InfallibleTArray<nsCString>& aNames,
@ -2226,40 +1784,7 @@ PluginModuleChild::AllocPPluginInstanceChild(const nsCString& aMimeType,
mQuirks = GetChrome()->mQuirks;
#ifdef XP_WIN
sUser32Intercept.Init("user32.dll");
if ((mQuirks & QUIRK_FLASH_HOOK_GETWINDOWINFO) &&
!sGetWindowInfoPtrStub) {
sUser32Intercept.AddHook("GetWindowInfo", reinterpret_cast<intptr_t>(PMCGetWindowInfoHook),
(void**) &sGetWindowInfoPtrStub);
}
if ((mQuirks & QUIRK_FLASH_HOOK_GETKEYSTATE) &&
!sGetKeyStatePtrStub) {
sUser32Intercept.AddHook("GetKeyState", reinterpret_cast<intptr_t>(PMCGetKeyState),
(void**) &sGetKeyStatePtrStub);
}
if (!sSetCursorPosPtrStub) {
sUser32Intercept.AddHook("SetCursorPos", reinterpret_cast<intptr_t>(PMCSetCursorPos),
(void**) &sSetCursorPosPtrStub);
}
sComDlg32Intercept.Init("comdlg32.dll");
if (!sGetSaveFileNameWPtrStub) {
sComDlg32Intercept.AddHook("GetSaveFileNameW", reinterpret_cast<intptr_t>(PMCGetSaveFileNameW),
(void**) &sGetSaveFileNameWPtrStub);
}
if (!sGetOpenFileNameWPtrStub) {
sComDlg32Intercept.AddHook("GetOpenFileNameW", reinterpret_cast<intptr_t>(PMCGetOpenFileNameW),
(void**) &sGetOpenFileNameWPtrStub);
}
if ((mQuirks & QUIRK_FLASH_HOOK_PRINTDLGW) &&
!sPrintDlgWPtrStub) {
sComDlg32Intercept.AddHook("PrintDlgW", reinterpret_cast<intptr_t>(PMCPrintDlgW),
(void**) &sPrintDlgWPtrStub);
}
FunctionHook::HookFunctions(mQuirks);
#endif
return new PluginInstanceChild(&mFunctions, aMimeType, aNames,

Просмотреть файл

@ -65,6 +65,9 @@ protected:
virtual mozilla::ipc::IPCResult
RecvInitPluginModuleChild(Endpoint<PPluginModuleChild>&& endpoint) override;
virtual mozilla::ipc::IPCResult
RecvInitPluginFunctionBroker(Endpoint<PFunctionBrokerChild>&& endpoint) override;
virtual PPluginInstanceChild*
AllocPPluginInstanceChild(const nsCString& aMimeType,
const InfallibleTArray<nsCString>& aNames,
@ -220,10 +223,6 @@ private:
bool InitGraphics();
void DeinitGraphics();
#if defined(OS_WIN)
void HookProtectedMode();
#endif
#if defined(MOZ_WIDGET_GTK)
static gboolean DetectNestedEventLoop(gpointer data);
static gboolean ProcessBrowserEvents(gpointer data);

Просмотреть файл

@ -43,6 +43,7 @@
#include "mozilla/plugins/PluginSurfaceParent.h"
#include "mozilla/widget/AudioSession.h"
#include "PluginHangUIParent.h"
#include "FunctionBrokerParent.h"
#include "PluginUtilsWin.h"
#endif
@ -486,6 +487,23 @@ PluginModuleChromeParent::LoadModule(const char* aFilePath, uint32_t aPluginId,
parent->mShutdown = true;
return nullptr;
}
#if defined(XP_WIN)
Endpoint<PFunctionBrokerParent> brokerParentEnd;
Endpoint<PFunctionBrokerChild> brokerChildEnd;
rv = PFunctionBroker::CreateEndpoints(base::GetCurrentProcId(), parent->OtherPid(),
&brokerParentEnd, &brokerChildEnd);
if (NS_FAILED(rv)) {
parent->mShutdown = true;
return nullptr;
}
parent->mBrokerParent =
FunctionBrokerParent::Create(Move(brokerParentEnd));
if (parent->mBrokerParent) {
parent->SendInitPluginFunctionBroker(Move(brokerChildEnd));
}
#endif
return parent.forget();
}
@ -622,6 +640,7 @@ PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath,
, mHangUIParent(nullptr)
, mHangUIEnabled(true)
, mIsTimerReset(true)
, mBrokerParent(nullptr)
#endif
#ifdef MOZ_CRASHREPORTER_INJECTOR
, mFlashProcess1(0)
@ -648,10 +667,6 @@ PluginModuleChromeParent::~PluginModuleChromeParent()
false);
#endif
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
mSandboxPermissions.RemovePermissionsForProcess(OtherPid());
#endif
if (!mShutdown) {
NS_WARNING("Plugin host deleted the module without shutting down.");
NPError err;
@ -1596,6 +1611,13 @@ PluginModuleChromeParent::ActorDestroy(ActorDestroyReason why)
// We can't broadcast settings changes anymore.
UnregisterSettingsCallbacks();
#if defined(XP_WIN)
if (mBrokerParent) {
FunctionBrokerParent::Destroy(mBrokerParent);
mBrokerParent = nullptr;
}
#endif
PluginModuleParent::ActorDestroy(why);
}
@ -2879,102 +2901,3 @@ PluginModuleChromeParent::OnCrash(DWORD processID)
}
#endif // MOZ_CRASHREPORTER_INJECTOR
mozilla::ipc::IPCResult
PluginModuleParent::AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet)
{
return IPC_FAIL_NO_REASON(this);
}
mozilla::ipc::IPCResult
PluginModuleChromeParent::AnswerGetKeyState(const int32_t& aVirtKey,
int16_t* aRet)
{
#if defined(XP_WIN)
*aRet = ::GetKeyState(aVirtKey);
return IPC_OK();
#else
return PluginModuleParent::AnswerGetKeyState(aVirtKey, aRet);
#endif
}
mozilla::ipc::IPCResult
PluginModuleChromeParent::AnswerGetFileName(const GetFileNameFunc& aFunc,
const OpenFileNameIPC& aOfnIn,
OpenFileNameRetIPC* aOfnOut,
bool* aResult)
{
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
OPENFILENAMEW ofn;
memset(&ofn, 0, sizeof(ofn));
aOfnIn.AllocateOfnStrings(&ofn);
aOfnIn.AddToOfn(&ofn);
switch (aFunc) {
case OPEN_FUNC:
*aResult = GetOpenFileName(&ofn);
break;
case SAVE_FUNC:
*aResult = GetSaveFileName(&ofn);
break;
default:
*aResult = false;
break;
}
if (*aResult) {
if (ofn.Flags & OFN_ALLOWMULTISELECT) {
// We only support multiselect with the OFN_EXPLORER flag.
// This guarantees that ofn.lpstrFile follows the pattern below.
MOZ_ASSERT(ofn.Flags & OFN_EXPLORER);
// lpstrFile is one of two things:
// 1. A null terminated full path to a file, or
// 2. A path to a folder, followed by a NULL, followed by a
// list of file names, each NULL terminated, followed by an
// additional NULL (so it is also double-NULL terminated).
std::wstring path = std::wstring(ofn.lpstrFile);
MOZ_ASSERT(ofn.nFileOffset > 0);
// For condition #1, nFileOffset points to the file name in the path.
// It will be preceeded by a non-NULL character from the path.
if (ofn.lpstrFile[ofn.nFileOffset-1] != L'\0') {
mSandboxPermissions.GrantFileAccess(OtherPid(), path.c_str(),
aFunc == SAVE_FUNC);
}
else {
// This is condition #2
wchar_t* nextFile = ofn.lpstrFile + path.size() + 1;
while (*nextFile != L'\0') {
std::wstring nextFileStr(nextFile);
std::wstring fullPath =
path + std::wstring(L"\\") + nextFileStr;
mSandboxPermissions.GrantFileAccess(OtherPid(), fullPath.c_str(),
aFunc == SAVE_FUNC);
nextFile += nextFileStr.size() + 1;
}
}
}
else {
mSandboxPermissions.GrantFileAccess(OtherPid(), ofn.lpstrFile,
aFunc == SAVE_FUNC);
}
aOfnOut->CopyFromOfn(&ofn);
}
aOfnIn.FreeOfnStrings(&ofn);
return IPC_OK();
#else
MOZ_ASSERT_UNREACHABLE("GetFileName IPC message is only available on "
"Windows builds with sandbox.");
return IPC_FAIL_NO_REASON(this);
#endif
}
mozilla::ipc::IPCResult
PluginModuleChromeParent::AnswerSetCursorPos(const int &x, const int &y,
bool* aResult)
{
#if defined(XP_WIN)
*aResult = ::SetCursorPos(x, y);
return IPC_OK();
#else
return PluginModuleParent::AnswerSetCursorPos(x, y, aResult);
#endif
}

Просмотреть файл

@ -27,9 +27,6 @@
#include "nsIObserver.h"
#ifdef XP_WIN
#include "nsWindowsHelpers.h"
#if defined(MOZ_SANDBOX)
#include "sandboxPermissions.h"
#endif
#endif
class nsPluginTag;
@ -48,6 +45,7 @@ class PluginInstanceParent;
#ifdef XP_WIN
class PluginHangUIParent;
class FunctionBrokerParent;
#endif
#ifdef MOZ_CRASHREPORTER_INJECTOR
class FinishInjectorInitTask;
@ -168,20 +166,6 @@ protected:
const bool& shouldRegister,
NPError* result) override;
virtual mozilla::ipc::IPCResult
AnswerGetFileName(const GetFileNameFunc& aFunc,
const OpenFileNameIPC& aOfnIn,
OpenFileNameRetIPC* aOfnOut, bool* aResult) override
{
return IPC_FAIL_NO_REASON(this);
}
virtual mozilla::ipc::IPCResult
AnswerSetCursorPos(const int &x, const int &y, bool* aResult) override
{
return IPC_FAIL_NO_REASON(this);
}
protected:
void SetChildTimeout(const int32_t aChildTimeout);
static void TimeoutChanged(const char* aPref, void* aModule);
@ -190,8 +174,6 @@ protected:
virtual mozilla::ipc::IPCResult RecvNotifyContentModuleDestroyed() override { return IPC_OK(); }
virtual mozilla::ipc::IPCResult AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet) override;
virtual mozilla::ipc::IPCResult RecvReturnClearSiteData(const NPError& aRv,
const uint64_t& aCallbackId) override;
@ -484,19 +466,6 @@ class PluginModuleChromeParent
void CachedSettingChanged();
virtual mozilla::ipc::IPCResult
AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet) override;
// Proxy GetOpenFileName/GetSaveFileName on Windows.
virtual mozilla::ipc::IPCResult
AnswerGetFileName(const GetFileNameFunc& aFunc,
const OpenFileNameIPC& aOfnIn,
OpenFileNameRetIPC* aOfnOut, bool* aResult) override;
// Proxy SetCursorPos on Windows.
virtual mozilla::ipc::IPCResult
AnswerSetCursorPos(const int &x, const int &y, bool* aResult) override;
private:
virtual void
EnteredCxxStack() override;
@ -588,6 +557,8 @@ private:
*/
void
FinishHangUI();
FunctionBrokerParent* mBrokerParent;
#endif
#ifdef MOZ_CRASHREPORTER_INJECTOR
@ -629,9 +600,6 @@ private:
nsCOMPtr<nsIObserver> mPluginOfflineObserver;
bool mIsBlocklisted;
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
mozilla::SandboxPermissions mSandboxPermissions;
#endif
nsCOMPtr<nsIFile> mBrowserDumpFile;
TakeFullMinidumpCallback mTakeFullMinidumpCallback;

Просмотреть файл

@ -12,6 +12,8 @@
#include "base/command_line.h"
#include "base/string_util.h"
#include "nsDebugImpl.h"
#include "nsThreadManager.h"
#include "ClearOnShutdown.h"
#if defined(XP_MACOSX)
#include "nsCocoaFeatures.h"
@ -106,6 +108,14 @@ PluginProcessChild::Init(int aArgc, char* aArgv[])
pluginFilename = WideToUTF8(values[0]);
// We don't initialize XPCOM but we need the thread manager and the
// logging framework for the FunctionBroker.
NS_SetMainThread();
mozilla::TimeStamp::Startup();
NS_LogInit();
mozilla::LogModule::Init();
nsThreadManager::get().Init();
#if defined(MOZ_SANDBOX)
// This is probably the earliest we would want to start the sandbox.
// As we attempt to tighten the sandbox, we may need to consider moving this
@ -141,6 +151,18 @@ PluginProcessChild::Init(int aArgc, char* aArgv[])
void
PluginProcessChild::CleanUp()
{
#if defined(OS_WIN)
MOZ_ASSERT(NS_IsMainThread());
// Shutdown components we started in Init. Note that KillClearOnShutdown
// is an event that is regularly part of XPCOM shutdown. We do not
// call XPCOM's shutdown but we need this event to be sent to avoid
// leaking objects labeled as ClearOnShutdown.
nsThreadManager::get().Shutdown();
mozilla::KillClearOnShutdown(ShutdownPhase::ShutdownFinal);
NS_LogTerm();
#endif
nsRegion::ShutdownStatic();
}

Просмотреть файл

@ -20,6 +20,8 @@
#include "mozilla/UniquePtr.h"
#include "nsCOMPtr.h"
#include "nsIRunnable.h"
#include "nsTHashtable.h"
#include "nsHashKeys.h"
namespace mozilla {
namespace plugins {

Просмотреть файл

@ -7,6 +7,8 @@
#ifndef dom_plugins_PluginQuirks_h
#define dom_plugins_PluginQuirks_h
#include "nsString.h"
namespace mozilla {
namespace plugins {

Просмотреть файл

@ -16,6 +16,8 @@ EXPORTS.mozilla.plugins += [
'BrowserStreamChild.h',
'BrowserStreamParent.h',
'ChildTimer.h',
'FunctionBrokerIPCUtils.h',
'IpdlTuple.h',
'NPEventAndroid.h',
'NPEventOSX.h',
'NPEventUnix.h',
@ -64,9 +66,15 @@ UNIFIED_SOURCES += [
'BrowserStreamChild.cpp',
'BrowserStreamParent.cpp',
'ChildTimer.cpp',
'FunctionBroker.cpp',
'FunctionBrokerChild.cpp',
'FunctionBrokerIPCUtils.cpp',
'FunctionBrokerParent.cpp',
'FunctionHook.cpp',
'PluginBackgroundDestroyer.cpp',
'PluginInstanceParent.cpp',
'PluginMessageUtils.cpp',
'PluginModuleChild.cpp',
'PluginModuleParent.cpp',
'PluginProcessChild.cpp',
'PluginProcessParent.cpp',
@ -77,7 +85,6 @@ UNIFIED_SOURCES += [
SOURCES += [
'PluginInstanceChild.cpp', # 'PluginThreadCallback' : ambiguous symbol
'PluginModuleChild.cpp', # Redefinition of mozilla::WindowsDllInterceptor sUser32Intercept
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
@ -102,6 +109,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
IPDL_SOURCES += [
'PBrowserStream.ipdl',
'PFunctionBroker.ipdl',
'PluginTypes.ipdlh',
'PPluginBackgroundDestroyer.ipdl',
'PPluginInstance.ipdl',
@ -117,6 +125,7 @@ FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'../base',
'/xpcom/base/',
'/xpcom/threads/',
]
if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':

Просмотреть файл

@ -72,9 +72,11 @@ SVGTransformableElement::GetAttributeChangeHint(const nsAtom* aAttribute,
MOZ_ASSERT(aModType == nsIDOMMutationEvent::MODIFICATION,
"Unknown modification type.");
if (!mTransforms ||
!mTransforms->HasTransform() ||
!mTransforms->HadTransformBeforeLastBaseValChange()) {
// New or old value is empty; this is effectively addition or removal.
!mTransforms->HasTransform()) {
// New value is empty, treat as removal.
isAdditionOrRemoval = true;
} else if (mTransforms->RequiresFrameReconstruction()) {
// Old value was empty, treat as addition.
isAdditionOrRemoval = true;
}
}

Просмотреть файл

@ -62,12 +62,10 @@ nsSVGAnimatedTransformList::SetBaseValue(const SVGTransformList& aValue,
domWrapper->InternalBaseValListWillChangeLengthTo(mBaseVal.Length());
} else {
mIsAttrSet = true;
// If we set this flag to false, we're indicating that aSVGElement's frames
// will need reconstructing to account for stacking context changes.
// If aSVGElement doesn't have any frames, then that's clearly unnecessary,
// so in that case we set the flag to true.
mHadTransformBeforeLastBaseValChange =
!aSVGElement->GetPrimaryFrame() || hadTransform;
// We only need to reconstruct the frame for aSVGElement if it already
// exists and the stacking context changes because a transform is created.
mRequiresFrameReconstruction =
aSVGElement->GetPrimaryFrame() && !hadTransform;
}
return rv;
}
@ -75,7 +73,7 @@ nsSVGAnimatedTransformList::SetBaseValue(const SVGTransformList& aValue,
void
nsSVGAnimatedTransformList::ClearBaseValue()
{
mHadTransformBeforeLastBaseValChange = HasTransform();
mRequiresFrameReconstruction = !HasTransform();
SVGAnimatedTransformList *domWrapper =
SVGAnimatedTransformList::GetDOMWrapperIfExists(this);

Просмотреть файл

@ -47,7 +47,7 @@ class nsSVGAnimatedTransformList
public:
nsSVGAnimatedTransformList()
: mIsAttrSet(false),
mHadTransformBeforeLastBaseValChange(false) { }
mRequiresFrameReconstruction(true) { }
/**
* Because it's so important that mBaseVal and its DOMSVGTransformList wrapper
@ -98,8 +98,8 @@ public:
}
/**
* Returns true iff "HasTransform" returned true just before our most recent
* SetBaseValue/SetBaseValueString/ClearBaseValue change.
* Returns true if we need to reconstruct the frame of the element associated
* with this transform list because the stacking context has changed.
*
* (This is used as part of an optimization in
* SVGTransformableElement::GetAttributeChangeHint. That function reports an
@ -108,8 +108,8 @@ public:
* a transform where we previously had none. These cases require a more
* thorough nsChangeHint.)
*/
bool HadTransformBeforeLastBaseValChange() const {
return mHadTransformBeforeLastBaseValChange;
bool RequiresFrameReconstruction() const {
return mRequiresFrameReconstruction;
}
mozilla::UniquePtr<nsISMILAttr> ToSMILAttr(nsSVGElement* aSVGElement);
@ -124,8 +124,8 @@ private:
SVGTransformList mBaseVal;
nsAutoPtr<SVGTransformList> mAnimVal;
bool mIsAttrSet;
// (See documentation for accessor, HadTransformBeforeLastBaseValChange.)
bool mHadTransformBeforeLastBaseValChange;
// (See documentation for accessor, RequiresFrameReconstruction.)
bool mRequiresFrameReconstruction;
struct SMILAnimatedTransformList : public nsISMILAttr
{

Просмотреть файл

@ -507,7 +507,7 @@ nsXULPrototypeCache::BeginCaching(nsIURI* aURI)
if (NS_FAILED(rv))
return rv;
nsAutoCString chromePath;
rv = chromeDir->GetNativePath(chromePath);
rv = chromeDir->GetPersistentDescriptor(chromePath);
if (NS_FAILED(rv))
return rv;

Просмотреть файл

@ -6,6 +6,7 @@
#include "PrintTargetEMF.h"
#include "nsAnonymousTemporaryFile.h"
#include "nsIFile.h"
#include "nsNativeCharsetUtils.h"
#include "mozilla/widget/PDFiumProcessParent.h"
#include "mozilla/widget/PDFiumParent.h"
#include "mozilla/widget/WindowsEMF.h"
@ -101,7 +102,15 @@ PrintTargetEMF::BeginPage()
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsAutoCString filePath;
#ifdef XP_WIN
// Unfortunately, SkFILEWStream does not support wide char paths yet.
// We have to use the native charset even though it is lossy :(
nsAutoString filePathU;
mPDFFileForOnePage->GetPath(filePathU);
NS_CopyUnicodeToNative(filePathU, filePath);
#else
mPDFFileForOnePage->GetNativePath(filePath);
#endif
auto stream = MakeUnique<SkFILEWStream>(filePath.get());
// Creating a new PrintTargetSkPDF for each page so that we can convert each

Просмотреть файл

@ -0,0 +1,30 @@
Bug 1422415 - NumberFormat returns NaN if RegionalPrefsLocales is fa-IR and value has decimals
https://ssl.icu-project.org/trac/ticket/13497
diff --git a/intl/icu/source/i18n/digitlst.cpp b/intl/icu/source/i18n/digitlst.cpp
--- a/intl/icu/source/i18n/digitlst.cpp
+++ b/intl/icu/source/i18n/digitlst.cpp
@@ -846,17 +846,22 @@ DigitList::set(double source)
// That is why infinity is special cased here.
if (uprv_isInfinite(source)) {
if (uprv_isNegativeInfinity(source)) {
uprv_strcpy(rep,"-inf"); // Handle negative infinity
} else {
uprv_strcpy(rep,"inf");
}
} else {
+#if U_USE_STRTOD_L && U_PLATFORM_USES_ONLY_WIN32_API
+ umtx_initOnce(gCLocaleInitOnce, &initCLocale);
+ _sprintf_l(rep, "%+1.*e", gCLocale, MAX_DBL_DIGITS - 1, source);
+#else
sprintf(rep, "%+1.*e", MAX_DBL_DIGITS - 1, source);
+#endif
}
U_ASSERT(uprv_strlen(rep) < sizeof(rep));
// uprv_decNumberFromString() will parse the string expecting '.' as a
// decimal separator, however sprintf() can use ',' in certain locales.
// Overwrite a ',' with '.' here before proceeding.
char *decimalSeparator = strchr(rep, ',');
if (decimalSeparator != NULL) {

Просмотреть файл

@ -851,7 +851,12 @@ DigitList::set(double source)
uprv_strcpy(rep,"inf");
}
} else {
#if U_USE_STRTOD_L && U_PLATFORM_USES_ONLY_WIN32_API
umtx_initOnce(gCLocaleInitOnce, &initCLocale);
_sprintf_l(rep, "%+1.*e", gCLocale, MAX_DBL_DIGITS - 1, source);
#else
sprintf(rep, "%+1.*e", MAX_DBL_DIGITS - 1, source);
#endif
}
U_ASSERT(uprv_strlen(rep) < sizeof(rep));

Просмотреть файл

@ -70,6 +70,7 @@ for patch in \
suppress-warnings.diff \
bug-1172609-timezone-recreateDefault.diff \
bug-1198952-workaround-make-3.82-bug.diff \
bug-1422415-numberformat-sprintfl-windows.diff \
; do
echo "Applying local patch $patch"
patch -d ${icu_dir}/../../ -p1 --no-backup-if-mismatch < ${icu_dir}/../icu-patches/$patch

Просмотреть файл

@ -310,6 +310,12 @@ struct ParamTraits<int8_t>
{
return aMsg->ReadBytesInto(aIter, aResult, sizeof(*aResult));
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
// Use 0xff to avoid sign extension.
aLog->append(StringPrintf(L"0x%02x", aParam & 0xff));
}
};
template<>
@ -326,6 +332,11 @@ struct ParamTraits<uint8_t>
{
return aMsg->ReadBytesInto(aIter, aResult, sizeof(*aResult));
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
aLog->append(StringPrintf(L"0x%02x", aParam));
}
};
#if !defined(OS_POSIX)

Просмотреть файл

@ -659,6 +659,8 @@ description =
description =
[PPluginWidget::SetNativeChildWindow]
description =
[PFunctionBroker::BrokerFunction]
description =
[PPluginInstance::__delete__]
description =
[PPluginInstance::CreateChildPluginWindow]
@ -771,16 +773,10 @@ description =
description =
[PPluginModule::NPN_SetException]
description =
[PPluginModule::GetKeyState]
description =
[PPluginModule::NPN_SetValue_NPPVpluginRequiresAudioDeviceChanges]
description =
[PPluginModule::InitCrashReporter]
description =
[PPluginModule::GetFileName]
description =
[PPluginModule::SetCursorPos]
description =
[PPluginScriptableObject::NPN_Evaluate]
description =
[PPluginScriptableObject::Invalidate]

Просмотреть файл

@ -688,57 +688,53 @@ function String_toLocaleUpperCase() {
return intl_toLocaleUpperCase(string, requestedLocale);
}
/* ES6 Draft May 22, 2014 21.1.2.4 */
function String_static_raw(callSite, ...substitutions) {
// Step 1 (implicit).
// Step 2.
var numberOfSubstitutions = substitutions.length;
// ES2018 draft rev 8fadde42cf6a9879b4ab0cb6142b31c4ee501667
// 21.1.2.4 String.raw ( template, ...substitutions )
function String_static_raw(callSite/*, ...substitutions*/) {
// Steps 1-2 (not applicable).
// Steps 3-4.
// Step 3.
var cooked = ToObject(callSite);
// Steps 5-7.
// Step 4.
var raw = ToObject(cooked.raw);
// Steps 8-10.
// Step 5.
var literalSegments = ToLength(raw.length);
// Step 11.
if (literalSegments <= 0)
// Step 6.
if (literalSegments === 0)
return "";
// Step 12.
var resultString = "";
// Special case for |String.raw `<literal>`| callers to avoid falling into
// the loop code below.
if (literalSegments === 1)
return ToString(raw[0]);
// Step 13.
var nextIndex = 0;
// Steps 7-9 were reordered to use the arguments object instead of a rest
// parameter, because the former is currently more optimized.
//
// String.raw intersperses the substitution elements between the literal
// segments, i.e. a substitution is added iff there are still pending
// literal segments. Furthermore by moving the access to |raw[0]| outside
// of the loop, we can use |nextIndex| to index into both, the |raw| array
// and the arguments object.
// Step 14.
while (true) {
// Steps a-d.
var nextSeg = ToString(raw[nextIndex]);
// Steps 7 (implicit) and 9.a-c.
var resultString = ToString(raw[0]);
// Step e.
resultString = resultString + nextSeg;
// Steps 8-9, 9.d, and 9.i.
for (var nextIndex = 1; nextIndex < literalSegments; nextIndex++) {
// Steps 9.e-h.
if (nextIndex < arguments.length)
resultString += ToString(arguments[nextIndex]);
// Step f.
if (nextIndex + 1 === literalSegments)
// Step f.i.
return resultString;
// Steps g-j.
var nextSub;
if (nextIndex < numberOfSubstitutions)
nextSub = ToString(substitutions[nextIndex]);
else
nextSub = "";
// Step k.
resultString = resultString + nextSub;
// Step l.
nextIndex++;
// Steps 9.a-c.
resultString += ToString(raw[nextIndex]);
}
// Step 9.d.i.
return resultString;
}
/**

Просмотреть файл

@ -3610,7 +3610,7 @@ static const JSFunctionSpec string_static_methods[] = {
JS_INLINABLE_FN("fromCharCode", js::str_fromCharCode, 1, 0, StringFromCharCode),
JS_INLINABLE_FN("fromCodePoint", js::str_fromCodePoint, 1, 0, StringFromCodePoint),
JS_SELF_HOSTED_FN("raw", "String_static_raw", 2,0),
JS_SELF_HOSTED_FN("raw", "String_static_raw", 1,0),
JS_SELF_HOSTED_FN("substring", "String_static_substring", 3,0),
JS_SELF_HOSTED_FN("substr", "String_static_substr", 3,0),
JS_SELF_HOSTED_FN("slice", "String_static_slice", 3,0),

Просмотреть файл

@ -1875,7 +1875,7 @@ dnl ========================================================
MOZ_CHECK_ALLOCATOR
AC_CHECK_FUNCS(setlocale localeconv)
AC_CHECK_FUNCS(localeconv)
AC_SUBST(ac_configure_args)

Просмотреть файл

@ -8961,9 +8961,7 @@ main(int argc, char** argv, char** envp)
int result;
#ifdef HAVE_SETLOCALE
setlocale(LC_ALL, "");
#endif
// Special-case stdout and stderr. We bump their refcounts to prevent them
// from getting closed and then having some printf fail somewhere.

Просмотреть файл

@ -639,12 +639,8 @@ JSRuntime::getDefaultLocale()
if (defaultLocale)
return defaultLocale;
const char* locale;
#ifdef HAVE_SETLOCALE
locale = setlocale(LC_ALL, nullptr);
#else
locale = getenv("LANG");
#endif
const char* locale = setlocale(LC_ALL, nullptr);
// convert to a well-formed BCP 47 language tag
if (!locale || !strcmp(locale, "C"))
locale = "und";

Просмотреть файл

@ -1206,16 +1206,10 @@ TypedArrayObjectTemplate<T>::fromTypedArray(JSContext* cx, HandleObject other, b
// Steps 8, 18-19.
Rooted<ArrayBufferObject*> buffer(cx);
if (ArrayTypeID() == srcType) {
// Step 18.a.
if (srcArray->hasDetachedBuffer()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
return nullptr;
}
// Step 15.
uint32_t byteLength = srcArray->byteLength();
// Step 18.b.
// Step 18.a.
// 24.1.1.4 CloneArrayBuffer(...), steps 1-3.
if (!AllocateArrayBuffer(cx, bufferCtor, byteLength, 1, &buffer))
return nullptr;

Просмотреть файл

@ -19,6 +19,7 @@
#include "nsIFile.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsNativeCharsetUtils.h"
using mozilla::LogLevel;
@ -188,7 +189,14 @@ void ConfigWebRtcLog(mozilla::LogLevel level, uint32_t trace_mask,
nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tempDir));
if (NS_SUCCEEDED(rv)) {
tempDir->AppendNative(default_log_name);
#ifdef XP_WIN
// WebRTC wants a path encoded in the native charset, not UTF-8.
nsAutoString logFile;
tempDir->GetPath(logFile);
NS_CopyUnicodeToNative(logFile, aLogFile);
#else
tempDir->GetNativePath(aLogFile);
#endif
}
}
#endif
@ -268,7 +276,14 @@ nsCString ConfigAecLog() {
nsCOMPtr<nsIFile> tempDir;
nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tempDir));
if (NS_SUCCEEDED(rv)) {
#ifdef XP_WIN
// WebRTC wants a path encoded in the native charset, not UTF-8.
nsAutoString temp;
tempDir->GetPath(temp);
NS_CopyUnicodeToNative(temp, aecLogDir);
#else
tempDir->GetNativePath(aecLogDir);
#endif
}
#endif
webrtc::Trace::set_aec_debug_filename(aecLogDir.get());

Просмотреть файл

@ -89,11 +89,9 @@ nsDirectoryIndexStream::Init(nsIFile* aDir)
return NS_ERROR_ILLEGAL_VALUE;
if (MOZ_LOG_TEST(gLog, LogLevel::Debug)) {
nsAutoCString path;
aDir->GetNativePath(path);
MOZ_LOG(gLog, LogLevel::Debug,
("nsDirectoryIndexStream[%p]: initialized on %s",
this, path.get()));
this, aDir->HumanReadablePath().get()));
}
// Sigh. We have to allocate on the heap because there are no
@ -228,11 +226,9 @@ nsDirectoryIndexStream::Read(char* aBuf, uint32_t aCount, uint32_t* aReadCount)
++mPos;
if (MOZ_LOG_TEST(gLog, LogLevel::Debug)) {
nsAutoCString path;
current->GetNativePath(path);
MOZ_LOG(gLog, LogLevel::Debug,
("nsDirectoryIndexStream[%p]: iterated %s",
this, path.get()));
this, current->HumanReadablePath().get()));
}
// rjc: don't return hidden files/directories!

Просмотреть файл

@ -929,10 +929,10 @@ nsSocketTransport::Init(const char **types, uint32_t typeCount,
return NS_OK;
}
#if defined(XP_UNIX)
nsresult
nsSocketTransport::InitWithFilename(const char *filename)
{
#if defined(XP_UNIX)
size_t filenameLength = strlen(filename);
if (filenameLength > sizeof(mNetAddr.local.path) - 1)
@ -948,10 +948,8 @@ nsSocketTransport::InitWithFilename(const char *filename)
mNetAddrIsSet = true;
return NS_OK;
#else
return NS_ERROR_SOCKET_ADDRESS_NOT_SUPPORTED;
#endif
}
#endif
nsresult
nsSocketTransport::InitWithConnectedSocket(PRFileDesc *fd, const NetAddr *addr)

Просмотреть файл

@ -145,10 +145,12 @@ public:
const NetAddr* aAddr,
nsISupports* aSecInfo);
#ifdef XP_UNIX
// This method instructs the socket transport to open a socket
// connected to the given Unix domain address. We can only create
// unlayered, simple, stream sockets.
nsresult InitWithFilename(const char *filename);
#endif
// nsASocketHandler methods:
void OnSocketReady(PRFileDesc *, int16_t outFlags) override;

Просмотреть файл

@ -755,6 +755,7 @@ NS_IMETHODIMP
nsSocketTransportService::CreateUnixDomainTransport(nsIFile *aPath,
nsISocketTransport **result)
{
#ifdef XP_UNIX
nsresult rv;
NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
@ -772,6 +773,9 @@ nsSocketTransportService::CreateUnixDomainTransport(nsIFile *aPath,
trans.forget(result);
return NS_OK;
#else
return NS_ERROR_SOCKET_ADDRESS_NOT_SUPPORTED;
#endif
}
NS_IMETHODIMP

Просмотреть файл

@ -3240,10 +3240,8 @@ nsStandardURL::GetFile(nsIFile **result)
return rv;
if (LOG_ENABLED()) {
nsAutoCString path;
mFile->GetNativePath(path);
LOG(("nsStandardURL::GetFile [this=%p spec=%s resulting_path=%s]\n",
this, mSpec.get(), path.get()));
this, mSpec.get(), mFile->HumanReadablePath().get()));
}
// clone the file, so the caller can modify it.

9
netwerk/cache/nsCache.cpp поставляемый
Просмотреть файл

@ -20,14 +20,7 @@ mozilla::LazyLogModule gCacheLog("cache");
void
CacheLogPrintPath(mozilla::LogLevel level, const char * format, nsIFile * item)
{
nsAutoCString path;
nsresult rv = item->GetNativePath(path);
if (NS_SUCCEEDED(rv)) {
MOZ_LOG(gCacheLog, level, (format, path.get()));
} else {
MOZ_LOG(gCacheLog, level, ("GetNativePath failed: %" PRIx32,
static_cast<uint32_t>(rv)));
}
MOZ_LOG(gCacheLog, level, (format, item->HumanReadablePath().get()));
}

24
netwerk/cache/nsCacheService.cpp поставляемый
Просмотреть файл

@ -4,15 +4,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsCacheService.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/Assertions.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/FileUtils.h"
#include "necko-config.h"
#include "nsCache.h"
#include "nsCacheService.h"
#include "nsCacheRequest.h"
#include "nsCacheEntry.h"
#include "nsCacheEntryDescriptor.h"
@ -1764,10 +1766,8 @@ nsCacheService::CreateCustomOfflineDevice(nsIFile *aProfileDir,
NS_ENSURE_ARG(aProfileDir);
if (MOZ_LOG_TEST(gCacheLog, LogLevel::Info)) {
nsAutoCString profilePath;
aProfileDir->GetNativePath(profilePath);
CACHE_LOG_INFO(("Creating custom offline device, %s, %d",
profilePath.BeginReading(), aQuota));
aProfileDir->HumanReadablePath().get(), aQuota));
}
if (!mInitialized) return NS_ERROR_NOT_AVAILABLE;
@ -3128,10 +3128,7 @@ nsCacheService::MoveOrRemoveDiskCache(nsIFile *aOldCacheDir,
if (NS_FAILED(rv))
return;
nsAutoCString newPath;
rv = aNewCacheSubdir->GetNativePath(newPath);
if (NS_FAILED(rv))
return;
PathString newPath = aNewCacheSubdir->NativePath();
if (NS_SUCCEEDED(aNewCacheSubdir->Exists(&exists)) && !exists) {
// New cache directory does not exist, try to move the old one here
@ -3140,12 +3137,15 @@ nsCacheService::MoveOrRemoveDiskCache(nsIFile *aOldCacheDir,
// Make sure the parent of the target sub-dir exists
rv = aNewCacheDir->Create(nsIFile::DIRECTORY_TYPE, 0777);
if (NS_SUCCEEDED(rv) || NS_ERROR_FILE_ALREADY_EXISTS == rv) {
nsAutoCString oldPath;
rv = aOldCacheSubdir->GetNativePath(oldPath);
if (NS_FAILED(rv))
return;
PathString oldPath = aOldCacheSubdir->NativePath();
#ifdef XP_WIN
if (MoveFileW(oldPath.get(), newPath.get()))
#else
if (rename(oldPath.get(), newPath.get()) == 0)
#endif
{
return;
}
}
}

4
netwerk/cache/nsDiskCacheDeviceSQL.cpp поставляемый
Просмотреть файл

@ -288,9 +288,7 @@ nsOfflineCacheEvictionFunction::Apply()
for (int32_t i = 0; i < items.Count(); i++) {
if (MOZ_LOG_TEST(gCacheLog, LogLevel::Debug)) {
nsAutoCString path;
items[i]->GetNativePath(path);
LOG((" removing %s\n", path.get()));
LOG((" removing %s\n", items[i]->HumanReadablePath().get()));
}
items[i]->Remove(false);

Просмотреть файл

@ -278,8 +278,7 @@ CacheFileContextEvictor::PersistEvictionInfoToDisk(
return rv;
}
nsAutoCString path;
file->GetNativePath(path);
nsCString path = file->HumanReadablePath();
PRFileDesc *fd;
rv = file->OpenNSPRFileDesc(PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 0600,
@ -315,8 +314,7 @@ CacheFileContextEvictor::RemoveEvictInfoFromDisk(
return rv;
}
nsAutoCString path;
file->GetNativePath(path);
nsCString path = file->HumanReadablePath();
rv = file->Remove(false);
if (NS_WARN_IF(NS_FAILED(rv))) {

Просмотреть файл

@ -3319,9 +3319,8 @@ CacheFileIOManager::CacheIndexStateChangedInternal()
nsresult
CacheFileIOManager::TrashDirectory(nsIFile *aFile)
{
nsAutoCString path;
aFile->GetNativePath(path);
LOG(("CacheFileIOManager::TrashDirectory() [file=%s]", path.get()));
LOG(("CacheFileIOManager::TrashDirectory() [file=%s]",
aFile->HumanReadablePath().get()));
nsresult rv;
@ -3559,11 +3558,9 @@ CacheFileIOManager::RemoveTrashInternal()
NS_WARNING("Found a directory in a trash directory! It will be removed "
"recursively, but this can block IO thread for a while!");
if (LOG_ENABLED()) {
nsAutoCString path;
file->GetNativePath(path);
LOG(("CacheFileIOManager::RemoveTrashInternal() - Found a directory in a trash "
"directory! It will be removed recursively, but this can block IO "
"thread for a while! [file=%s]", path.get()));
"thread for a while! [file=%s]", file->HumanReadablePath().get()));
}
}
file->Remove(isDir);
@ -4152,10 +4149,8 @@ CacheFileIOManager::SyncRemoveDir(nsIFile *aFile, const char *aDir)
}
if (LOG_ENABLED()) {
nsAutoCString path;
file->GetNativePath(path);
LOG(("CacheFileIOManager::SyncRemoveDir() - Removing directory %s",
path.get()));
file->HumanReadablePath().get()));
}
rv = file->Remove(true);

Просмотреть файл

@ -609,13 +609,9 @@ LogExternalResourceError(nsIFile* aExtensionDir, nsIFile* aRequestedFile)
MOZ_ASSERT(aExtensionDir);
MOZ_ASSERT(aRequestedFile);
nsAutoCString extensionDirPath, requestedFilePath;
Unused << aExtensionDir->GetNativePath(extensionDirPath);
Unused << aRequestedFile->GetNativePath(requestedFilePath);
LOG("Rejecting external unpacked extension resource [%s] from "
"extension directory [%s]", requestedFilePath.get(),
extensionDirPath.get());
"extension directory [%s]", aRequestedFile->HumanReadablePath().get(),
aExtensionDir->HumanReadablePath().get());
}
Result<nsCOMPtr<nsIInputStream>, nsresult>

Просмотреть файл

@ -187,7 +187,7 @@ CertBlocklist::Init()
return rv;
}
nsAutoCString path;
rv = mBackingFile->GetNativePath(path);
rv = mBackingFile->GetPersistentDescriptor(path);
if (NS_FAILED(rv)) {
return rv;
}

Просмотреть файл

@ -33,6 +33,7 @@
#include "nsDirectoryServiceDefs.h"
#include "nsICertOverrideService.h"
#include "nsIFile.h"
#include "nsILocalFileWin.h"
#include "nsIObserverService.h"
#include "nsIPrompt.h"
#include "nsIProperties.h"
@ -1210,7 +1211,18 @@ GetNSS3Directory(nsCString& result)
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get parent directory?"));
return rv;
}
#ifdef XP_WIN
// Native path will drop Unicode characters that cannot be mapped to system's
// codepage, using short (canonical) path as workaround.
nsCOMPtr<nsILocalFileWin> nss3DirectoryWin = do_QueryInterface(nss3Directory);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get nsILocalFileWin"));
return rv;
}
return nss3DirectoryWin->GetNativeCanonicalPath(result);
#else
return nss3Directory->GetNativePath(result);
#endif
}
// Returns by reference the path to the desired directory, based on the current
@ -1232,7 +1244,18 @@ GetDirectoryPath(const char* directoryKey, nsCString& result)
("could not get '%s' from directory service", directoryKey));
return rv;
}
#ifdef XP_WIN
// Native path will drop Unicode characters that cannot be mapped to system's
// codepage, using short (canonical) path as workaround.
nsCOMPtr<nsILocalFileWin> directoryWin = do_QueryInterface(directory);
if (NS_FAILED(rv)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get nsILocalFileWin"));
return rv;
}
return directoryWin->GetNativeCanonicalPath(result);
#else
return directory->GetNativePath(result);
#endif
}

Просмотреть файл

@ -7,8 +7,10 @@ SOURCES += [
]
# Don't let LTO reorder StaticXULComponentsStart.o.
if '-flto' in CONFIG['OS_CXXFLAGS']:
SOURCES['StaticXULComponentsEnd.cpp'].flags += ['-fno-lto']
for f in CONFIG['OS_CXXFLAGS']:
if f.startswith('-flto'):
SOURCES['StaticXULComponentsEnd.cpp'].flags += ['-fno-lto']
break
Library('StaticXULComponentsEnd')

Просмотреть файл

@ -92,8 +92,10 @@ SOURCES += [
SOURCES['StaticXULComponentsStart.cpp'].no_pgo = True
# Don't let LTO reorder StaticXULComponentsStart.o.
if '-flto' in CONFIG['OS_CXXFLAGS']:
SOURCES['StaticXULComponentsStart.cpp'].flags += ['-fno-lto']
for f in CONFIG['OS_CXXFLAGS']:
if f.startswith('-flto'):
SOURCES['StaticXULComponentsStart.cpp'].flags += ['-fno-lto']
break
if CONFIG['OS_ARCH'] == 'WINNT':
SOURCES += [

Просмотреть файл

@ -5055,6 +5055,12 @@ XRE_IsContentProcess()
return XRE_GetProcessType() == GeckoProcessType_Content;
}
bool
XRE_IsPluginProcess()
{
return XRE_GetProcessType() == GeckoProcessType_Plugin;
}
bool
XRE_UseNativeEventProcessing()
{

Просмотреть файл

@ -5,6 +5,10 @@
#include <shlobj.h>
#include <stdio.h>
#include <commdlg.h>
#define SECURITY_WIN32
#include <security.h>
#include <wininet.h>
#include <schnlsp.h>
#include "mozilla/WindowsVersion.h"
#include "nsWindowsDllInterceptor.h"
@ -440,6 +444,141 @@ bool TestPrintDlgW(void* aFunc)
return true;
}
bool TestInternetConnectA(void* aFunc)
{
auto patchedInternetConnectA =
reinterpret_cast<decltype(&InternetConnectA)>(aFunc);
return patchedInternetConnectA(0, 0, 0, 0, 0, 0, 0, 0) == 0;
}
HINTERNET sInternet = 0;
bool TestInternetOpenA(void* aFunc)
{
auto patchedInternetOpenA =
reinterpret_cast<decltype(&InternetOpenA)>(aFunc);
sInternet = patchedInternetOpenA(0, 0, 0, 0, 0);
return sInternet != 0;
}
bool TestInternetCloseHandle(void* aFunc)
{
auto patchedInternetCloseHandle =
reinterpret_cast<decltype(&InternetCloseHandle)>(aFunc);
return patchedInternetCloseHandle(sInternet);
}
bool TestInternetQueryDataAvailable(void* aFunc)
{
auto patchedInternetQueryDataAvailable =
reinterpret_cast<decltype(&InternetQueryDataAvailable)>(aFunc);
return patchedInternetQueryDataAvailable(0, 0, 0, 0) == FALSE;
}
bool TestInternetReadFile(void* aFunc)
{
auto patchedInternetReadFile =
reinterpret_cast<decltype(&InternetReadFile)>(aFunc);
return patchedInternetReadFile(0, 0, 0, 0) == FALSE;
}
bool TestInternetWriteFile(void* aFunc)
{
auto patchedInternetWriteFile =
reinterpret_cast<decltype(&InternetWriteFile)>(aFunc);
return patchedInternetWriteFile(0, 0, 0, 0) == FALSE;
}
bool TestInternetSetOptionA(void* aFunc)
{
auto patchedInternetSetOptionA =
reinterpret_cast<decltype(&InternetSetOptionA)>(aFunc);
return patchedInternetSetOptionA(0, 0, 0, 0) == FALSE;
}
bool TestHttpAddRequestHeadersA(void* aFunc)
{
auto patchedHttpAddRequestHeadersA =
reinterpret_cast<decltype(&HttpAddRequestHeadersA)>(aFunc);
return patchedHttpAddRequestHeadersA(0, 0, 0, 0) == FALSE;
}
bool TestHttpOpenRequestA(void* aFunc)
{
auto patchedHttpOpenRequestA =
reinterpret_cast<decltype(&HttpOpenRequestA)>(aFunc);
return patchedHttpOpenRequestA(0, 0, 0, 0, 0, 0, 0, 0) == 0;
}
bool TestHttpQueryInfoA(void* aFunc)
{
auto patchedHttpQueryInfoA =
reinterpret_cast<decltype(&HttpQueryInfoA)>(aFunc);
return patchedHttpQueryInfoA(0, 0, 0, 0, 0) == FALSE;
}
bool TestHttpSendRequestA(void* aFunc)
{
auto patchedHttpSendRequestA =
reinterpret_cast<decltype(&HttpSendRequestA)>(aFunc);
return patchedHttpSendRequestA(0, 0, 0, 0, 0) == FALSE;
}
bool TestHttpSendRequestExA(void* aFunc)
{
auto patchedHttpSendRequestExA =
reinterpret_cast<decltype(&HttpSendRequestExA)>(aFunc);
return patchedHttpSendRequestExA(0, 0, 0, 0, 0) == FALSE;
}
bool TestHttpEndRequestA(void* aFunc)
{
auto patchedHttpEndRequestA =
reinterpret_cast<decltype(&HttpEndRequestA)>(aFunc);
return patchedHttpEndRequestA(0, 0, 0, 0) == FALSE;
}
bool TestInternetQueryOptionA(void* aFunc)
{
auto patchedInternetQueryOptionA =
reinterpret_cast<decltype(&InternetQueryOptionA)>(aFunc);
return patchedInternetQueryOptionA(0, 0, 0, 0) == FALSE;
}
bool TestInternetErrorDlg(void* aFunc)
{
auto patchedInternetErrorDlg =
reinterpret_cast<decltype(&InternetErrorDlg)>(aFunc);
return patchedInternetErrorDlg(0, 0, 0, 0, 0) == ERROR_INVALID_HANDLE;
}
CredHandle sCredHandle;
bool TestAcquireCredentialsHandleA(void* aFunc)
{
auto patchedAcquireCredentialsHandleA =
reinterpret_cast<decltype(&AcquireCredentialsHandleA)>(aFunc);
SCHANNEL_CRED cred;
memset(&cred, 0, sizeof(cred));
cred.dwVersion = SCHANNEL_CRED_VERSION;
return patchedAcquireCredentialsHandleA(0, UNISP_NAME, SECPKG_CRED_OUTBOUND,
0, &cred, 0, 0, &sCredHandle, 0) == S_OK;
}
bool TestQueryCredentialsAttributesA(void* aFunc)
{
auto patchedQueryCredentialsAttributesA =
reinterpret_cast<decltype(&QueryCredentialsAttributesA)>(aFunc);
return patchedQueryCredentialsAttributesA(&sCredHandle, 0, 0) == SEC_E_UNSUPPORTED_FUNCTION;
}
bool TestFreeCredentialsHandle(void* aFunc)
{
auto patchedFreeCredentialsHandle =
reinterpret_cast<decltype(&FreeCredentialsHandle)>(aFunc);
return patchedFreeCredentialsHandle(&sCredHandle) == S_OK;
}
int main()
{
// We disable this part of the test because the code coverage instrumentation
@ -556,6 +695,26 @@ int main()
TestHook(TestSetCursorPos, "user32.dll", "SetCursorPos") &&
TestHook(TestTlsAlloc, "kernel32.dll", "TlsAlloc") &&
TestHook(TestTlsFree, "kernel32.dll", "TlsFree") &&
TestHook(TestInternetOpenA, "wininet.dll", "InternetOpenA") &&
TestHook(TestInternetCloseHandle, "wininet.dll", "InternetCloseHandle") &&
TestHook(TestInternetConnectA, "wininet.dll", "InternetConnectA") &&
TestHook(TestInternetQueryDataAvailable, "wininet.dll", "InternetQueryDataAvailable") &&
TestHook(TestInternetReadFile, "wininet.dll", "InternetReadFile") &&
TestHook(TestInternetWriteFile, "wininet.dll", "InternetWriteFile") &&
TestHook(TestInternetSetOptionA, "wininet.dll", "InternetSetOptionA") &&
TestHook(TestHttpAddRequestHeadersA, "wininet.dll", "HttpAddRequestHeadersA") &&
TestHook(TestHttpOpenRequestA, "wininet.dll", "HttpOpenRequestA") &&
TestHook(TestHttpQueryInfoA, "wininet.dll", "HttpQueryInfoA") &&
TestHook(TestHttpSendRequestA, "wininet.dll", "HttpSendRequestA") &&
TestHook(TestHttpSendRequestExA, "wininet.dll", "HttpSendRequestExA") &&
TestHook(TestHttpEndRequestA, "wininet.dll", "HttpEndRequestA") &&
TestHook(TestInternetQueryOptionA, "wininet.dll", "InternetQueryOptionA") &&
TestHook(TestAcquireCredentialsHandleA, "sspicli.dll", "AcquireCredentialsHandleA") &&
TestHook(TestQueryCredentialsAttributesA, "sspicli.dll", "QueryCredentialsAttributesA") &&
TestHook(TestFreeCredentialsHandle, "sspicli.dll", "FreeCredentialsHandle") &&
TestDetour("kernel32.dll", "BaseThreadInitThunk") &&
TestDetour("ntdll.dll", "LdrLoadDll")) {
printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n");

Просмотреть файл

@ -304,9 +304,7 @@ nsMIMEInfoBase::LaunchWithFile(nsIFile* aFile)
rv = localHandler->GetExecutable(getter_AddRefs(executable));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString path;
aFile->GetNativePath(path);
return LaunchWithIProcess(executable, path);
return LaunchWithIProcess(executable, aFile->NativePath());
}
return NS_ERROR_INVALID_ARG;
@ -422,10 +420,7 @@ nsMIMEInfoImpl::LaunchDefaultWithFile(nsIFile* aFile)
if (!mDefaultApplication)
return NS_ERROR_FILE_NOT_FOUND;
nsAutoCString nativePath;
aFile->GetNativePath(nativePath);
return LaunchWithIProcess(mDefaultApplication, nativePath);
return LaunchWithIProcess(mDefaultApplication, aFile->NativePath());
}
NS_IMETHODIMP

Просмотреть файл

@ -11,6 +11,7 @@
#include "mozilla/dom/File.h"
#include "mozilla/Unused.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/FileUtils.h"
/* Scale DC by keeping aspect ratio */
static
@ -47,34 +48,14 @@ PDFViaEMFPrintHelper::OpenDocument(nsIFile* aFile)
return NS_ERROR_FAILURE;
}
nsAutoCString nativePath;
nsresult rv = aFile->GetNativePath(nativePath);
AutoFDClose prFileDesc;
nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &prFileDesc.rwget());
if (NS_FAILED(rv)) {
return rv;
}
return OpenDocument(nativePath.get());
}
nsresult
PDFViaEMFPrintHelper::OpenDocument(const char* aFileName)
{
MOZ_ASSERT(aFileName);
if (mPDFDoc) {
MOZ_ASSERT_UNREACHABLE("We can only open one PDF at a time,"
"Use CloseDocument() to close the opened file"
"before calling OpenDocument()");
return NS_ERROR_FAILURE;
}
NS_ENSURE_TRUE(CreatePDFiumEngineIfNeed(), NS_ERROR_FAILURE);
mPDFDoc = mPDFiumEngine->LoadDocument(aFileName, nullptr);
NS_ENSURE_TRUE(mPDFDoc, NS_ERROR_FAILURE);
return NS_OK;
return OpenDocument(FileDescriptor(FileDescriptor::PlatformHandleType(
PR_FileDesc2NativeHandle(prFileDesc))));
}
nsresult

Просмотреть файл

@ -42,7 +42,6 @@ public:
/** Loads the specified PDF file. */
NS_IMETHOD OpenDocument(nsIFile* aFile);
NS_IMETHOD OpenDocument(const char* aFileName);
NS_IMETHOD OpenDocument(const FileDescriptor& aFD);
/** Releases document buffer. */

Просмотреть файл

@ -231,7 +231,7 @@ WinTaskbar::GetAppUserModelID(nsAString & aDefaultGroupId) {
bool exists = false;
if (profileDir && NS_SUCCEEDED(profileDir->Exists(&exists)) && exists) {
nsAutoCString path;
if (NS_SUCCEEDED(profileDir->GetNativePath(path))) {
if (NS_SUCCEEDED(profileDir->GetPersistentDescriptor(path))) {
nsAutoString id;
id.AppendInt(HashString(path));
if (!id.IsEmpty()) {

Просмотреть файл

@ -41,10 +41,10 @@ GetFilePathViaSpecialDirectory(const char* aSpecialDirName,
aFileName);
NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
nsAutoCString path;
nsresult rv = file->GetNativePath(path);
nsAutoString path;
nsresult rv = file->GetPath(path);
if (NS_SUCCEEDED(rv)) {
aPath = NS_ConvertUTF8toUTF16(path);
aPath = path;
}
return rv;
}

Просмотреть файл

@ -1215,7 +1215,7 @@ nsDataObj :: GetFileContentsInternetShortcut ( FORMATETC& aFE, STGMEDIUM& aSTG )
const char *shortcutFormatStr;
int totalLen;
nsCString path;
nsCString asciiPath;
if (!Preferences::GetBool(kShellIconPref, true)) {
shortcutFormatStr = "[InternetShortcut]\r\nURL=%s\r\n";
const int formatLen = strlen(shortcutFormatStr) - 2; // don't include %s
@ -1229,15 +1229,29 @@ nsDataObj :: GetFileContentsInternetShortcut ( FORMATETC& aFE, STGMEDIUM& aSTG )
rv = mozilla::widget::FaviconHelper::GetOutputIconPath(aUri, icoFile, true);
NS_ENSURE_SUCCESS(rv, E_FAIL);
rv = icoFile->GetNativePath(path);
nsString path;
rv = icoFile->GetPath(path);
NS_ENSURE_SUCCESS(rv, E_FAIL);
shortcutFormatStr = "[InternetShortcut]\r\nURL=%s\r\n"
"IDList=\r\nHotKey=0\r\nIconFile=%s\r\n"
"IconIndex=0\r\n";
if (NS_IsAscii(path.get())) {
LossyCopyUTF16toASCII(path, asciiPath);
shortcutFormatStr = "[InternetShortcut]\r\nURL=%s\r\n"
"IDList=\r\nHotKey=0\r\nIconFile=%s\r\n"
"IconIndex=0\r\n";
} else {
int len = WideCharToMultiByte(CP_UTF7, 0, char16ptr_t(path.BeginReading()),
path.Length(), nullptr, 0, nullptr, nullptr);
NS_ENSURE_TRUE(len > 0, E_FAIL);
asciiPath.SetLength(len);
WideCharToMultiByte(CP_UTF7, 0, char16ptr_t(path.BeginReading()), path.Length(),
asciiPath.BeginWriting(), len, nullptr, nullptr);
shortcutFormatStr = "[InternetShortcut]\r\nURL=%s\r\n"
"IDList=\r\nHotKey=0\r\nIconIndex=0\r\n"
"[InternetShortcut.W]\r\nIconFile=%s\r\n";
}
const int formatLen = strlen(shortcutFormatStr) - 2 * 2; // no %s twice
totalLen = formatLen + asciiUrl.Length() +
path.Length(); // we don't want a null character on the end
asciiPath.Length(); // we don't want a null character on the end
}
// create a global memory area and build up the file contents w/in it
@ -1259,7 +1273,7 @@ nsDataObj :: GetFileContentsInternetShortcut ( FORMATETC& aFE, STGMEDIUM& aSTG )
if (!Preferences::GetBool(kShellIconPref, true)) {
_snprintf(contents, totalLen, shortcutFormatStr, asciiUrl.get());
} else {
_snprintf(contents, totalLen, shortcutFormatStr, asciiUrl.get(), path.get());
_snprintf(contents, totalLen, shortcutFormatStr, asciiUrl.get(), asciiPath.get());
}
::GlobalUnlock(hGlobalMemory);

Просмотреть файл

@ -1043,6 +1043,31 @@ protected:
MOZ_ASSERT_UNREACHABLE("Unrecognized opcode sequence");
return;
}
} else if (origBytes[nOrigBytes] == 0x8d) {
// LEA reg, addr
if ((origBytes[nOrigBytes + 1] & kMaskMod) == 0x0 &&
(origBytes[nOrigBytes + 1] & kMaskRm) == 0x5) {
// [rip+disp32]
// convert 32bit offset to 64bit direct and convert instruction
// to a simple 64-bit mov
BYTE reg = (origBytes[nOrigBytes + 1] & kMaskReg) >> kRegFieldShift;
intptr_t absAddr =
reinterpret_cast<intptr_t>(origBytes + nOrigBytes + 6 +
*reinterpret_cast<int32_t*>(origBytes + nOrigBytes + 2));
nOrigBytes += 6;
tramp[nTrampBytes] = 0xb8 + reg; // mov
++nTrampBytes;
intptr_t* trampOperandPtr = reinterpret_cast<intptr_t*>(tramp + nTrampBytes);
*trampOperandPtr = absAddr;
nTrampBytes += 8;
} else {
// Above we dealt with RIP-relative instructions. Any other
// operand form can simply be copied.
int len = CountModRmSib(origBytes + nOrigBytes + 1);
// We handled the kModOperand64 -- ie RIP-relative -- case above
MOZ_ASSERT(len > 0);
COPY_CODES(len + 1);
}
} else if (origBytes[nOrigBytes] == 0x63 &&
(origBytes[nOrigBytes + 1] & kMaskMod) == kModReg) {
// movsxd r64, r32 (move + sign extend)
@ -1077,6 +1102,17 @@ protected:
MOZ_ASSERT_UNREACHABLE("Unrecognized MOV opcode sequence");
return;
}
} else if (origBytes[nOrigBytes] == 0x44 &&
origBytes[nOrigBytes+1] == 0x89) {
// mov word ptr [reg+disp8], reg
COPY_CODES(2);
int len = CountModRmSib(origBytes + nOrigBytes);
if (len < 0) {
// no way to support this yet.
MOZ_ASSERT_UNREACHABLE("Unrecognized opcode sequence");
return;
}
COPY_CODES(len);
}
} else if ((origBytes[nOrigBytes] & 0xf0) == 0x50) {
// 1-byte push/pop
@ -1222,6 +1258,19 @@ protected:
MOZ_ASSERT_UNREACHABLE("Unrecognized opcode sequence");
return;
}
} else if (origBytes[nOrigBytes] == 0x83 &&
(origBytes[nOrigBytes + 1] & 0xf8) == 0x60) {
// and [r+d], imm8
COPY_CODES(5);
} else if (origBytes[nOrigBytes] == 0xc6) {
// mov [r+d], imm8
int len = CountModRmSib(&origBytes[nOrigBytes + 1]);
if (len < 0) {
// RIP-relative not yet supported
MOZ_ASSERT_UNREACHABLE("Unrecognized opcode sequence");
return;
}
COPY_CODES(len + 1);
} else {
MOZ_ASSERT_UNREACHABLE("Unrecognized opcode sequence");
return;
@ -1352,10 +1401,15 @@ class WindowsDllInterceptor
int mNHooks;
public:
WindowsDllInterceptor()
explicit WindowsDllInterceptor(const char* aModuleName = nullptr,
int aNumHooks = 0)
: mModuleName(nullptr)
, mNHooks(0)
{}
{
if (aModuleName) {
Init(aModuleName, aNumHooks);
}
}
void Init(const char* aModuleName, int aNumHooks = 0)
{

Просмотреть файл

@ -447,6 +447,9 @@ XRE_API(bool,
XRE_API(bool,
XRE_IsGPUProcess, ())
XRE_API(bool,
XRE_IsPluginProcess, ())
/**
* Returns true if the appshell should run its own native event loop. Returns
* false if we should rely solely on the Gecko event loop.