зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
11d0ff9f36
|
@ -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('&', '&').replace('<', '<').replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
||||
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
||||
}
|
||||
|
||||
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
|
|
@ -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.
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче