Mitchi wrote: > i was trying to understand it line to line. > But my problem is with the C++ version, > where things aren't as clear as in the sidebar implementation.
your problem is trying to use the C++ version instead of finding the one to one mapping between JS and C++. Not every line in here is annotated, but almost all of them are obvious one to one mappings. Note that many lines in JS or C++ need an additional line in the other language. I might note that in some cases, in others, well.... if the line counts don't match, assume that one of them expanded :). it goes something like this: /* IDL file myIFoopy.idl */ [scriptable] interface myIFoopy : nsISupports { /* method * @param foopy something to think about * * @return a randomish number based on howtever the implementation feels about foopy */ long method(in AString foopy); /* dohtem * @param out ypoof something to get * @bugs this should just be long dohtem() but that wouldn't demo outs in js. * as such, using this method in js is a royal pain */ void dohtem(out long ypoof); /* cupid is not readonly, it has both a setter and a getter. * it stores a cupid. * how cupid is used is entirely implementation specific. */ attribute nsISupports cupid; attribute nsISupports dipuc; } /* JS impl myFoopy.js */ function myFoopy(){} myFoopy.prototype = { /* this is the dirty definition approach, objects normally like to know who their * constructor is, but we're destroying the object here, so it doesn't unless we * store it by hand. * * this is xpcom private */ constructor: myFoopy, /* * this is xpcom public if you QI to nsISupports (and everything derives from * nsISupports, so you don't actually need to QI to it unless you have a tearoff * which you could have in c++ [js is protected from that problem by xpconnect * magic]. */ QueryInterface: function /* what matters to xpcom is the public name before the colon. * the name of the function is an internal name used by things like debuggers * and profilers, and people who want to read and understand your code. */ myFoopy_QueryInterface(iid) { /* I refuse to use sugar: for each (i in this.interfaces) * here because when someone pollutes Object.prototype or Array.prototype, * the sugar breaks and people wonder why things stopped working. * this happens often enough that the sugar is just dangerous. * plus that sugar can't be converted to C++, and it is possible to write this sugar free * version in C++, although it isn't recommended. */ for (var i = 0; i < this.interfaces; ++i) { if (iid.equals(this.interfaces[i])) return this; throw Components.results.NS_ERROR_NO_INTERFACE; } }, /* this is as close to table driven qi as js can get, and it's conveniently a first step * to nsIClassInfo. * * this is xpcom private */ interfaces: [ Components.interfaces.nsISupports, Components.interfaces.myIFoopy ], /* storage for cupid * * this is xpcom private */ _cupid: null, /* myIFoopy.method * note that the case for method here matches the case in the idl file. * * this is xpcom public if you QI to myIFoopy */ method: function myFoopy_method(foopy) { if (foopy.charAt(0) == "f" && foopy.charAt(1) == "o" && !foopy.charAt(2)) return 10; if (foopy == 'of') { /* it sucks, but this is how you get the result of an out value for an xpcom method. * this is also why this.dohtem should be a long dohtem(); * instead of void dohtem(out long ypoof); * * first you need an object */ var ypoof = {}; /* then you pass it to the C++; this feels so much like visual basic.... */ this.dohtem(ypoof); /* then you grab the magically populated value from the object, * that's your out-ed value. */ return ypoof.value; } return 19; }, /* myIFoopy.dohtem * note that the case for method here matches the case in the idl file. * * this is xpcom public if you QI to myIFoopy */ dohtem: function myFoopy_dohtem(foopy) { foopy.value = 15; }, /* getter myIFoopy.cupid * this is written using syntactic sugar * this is xpcom public if you QI to myIFoopy */ get cupid() { return this._cupid; }, /* setter myIFoopy.cupid * this is written using syntactic sugar * this is xpcom public if you QI to myIFoopy */ set cupid(cupid) { this._cupid = cupid; /* this is only in case someone calls our setter from js and it only makes sense */ }, /* getter myIFoopy.dipuc * this is not written using syntactic sugar * this is xpcom public if you QI to myIFoopy */ getDipuc() { return this.cupid; }, /* setter myIFoopy.dipuc * this is not written using syntactic sugar * this is xpcom public if you QI to myIFoopy */ setDipuc: function myFoopy_SetDipuc (cupid) { /* the use of this. is here is required for js, * and can be conveniently seen as related to the C++ * example if you pretend that this is an xpcom pointer instead of a native pointer */ return this.cupid = cupid; } } /* the implementation of nsIModule is already documented elsewhere and is beyond the scope of this mapping */ /* C++ impl myFoopy.cpp */ class myFoopy : public myIFoopy { private: /* constructor * * this is xpcom private */ myFoopy(); /* storage for cupid * * this is xpcom private */ nsCOMPtr<nsISupports> mCupid; public: NS_DECL_MYIFOOPY; NS_DECL_ISUPPORTS; } myFoopy::myFoopy(){} /* note that you can only have one of these per class since they define the same methods /* this is the standard syntatic sugar approach */ NS_IMPL_ISUPPORTS1(myFoopy, myIFoopy) /* end standard sugar */ /* this is a more flexible slightly sugary approach */ NS_IMPL_ADDREF(myFoopy) NS_IMPL_RELEASE(myFoopy) NS_INTERFACE_MAP_BEGIN(myFoopy) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_ENTRY(nsIFoopy) NS_INTERFACE_MAP_END(myFoopy) /* end rarer alternate sugary approach */ /* * this is xpcom public if you QI to myIFoopy */ NS_IMETHODIMP /* myIFoopy.method * note the lack of any special prefix but that method is InitialCaps, * unlike the idl declaration. */ myFoopy::Method(/*in strings are a bit special*/ const nsAString &foopy, PRInt32 *aRetval) { if (foopy.CharAt(0) == "f" && foopy.CharAt(1) == "o" && foopy.CharAt(2) == "") { /* note that it takes two lines to express a return */ *aRetval = 10; return NS_OK; } /* but this allows us to not use 'else', just as the js doesn't need it ... */ if (foopy.EqualsLiteral("of")) { /* sometimes C++ is shorter ... */ Dohtem(aRetval); return NS_OK; } *aRetval = 19; return NS_OK; } NS_IMETHODIMP /* myIFoopy.dohtem * note the lack of any special prefix but that method is InitialCaps, * unlike the idl declaration. */ myFoopy::Dohtem(PRInt32 *aYpoof) { *aYpoof = 15; return NS_OK; } /* * this is xpcom public if you QI to myIFoopy */ NS_IMETHODIMP /* getter myIFoopy.cupid * note that Get is part of the name and both Get and Cupid are InitialCaps * note the double pointer since we need to be able to pass out a pointer */ myFoopy::GetCupid(nsISupports **aResult) { /* xpcom says we addref for getters... */ NS_IF_ADDREF(*aResult = mCupid); return NS_OK; } /* * this is xpcom public if you QI to myIFoopy */ NS_IMETHODIMP /* setter myIFoopy.cupid * note that Set is part of the name and both Set and Cupid are InitialCaps * note the single pointer since we only need to be given a pointer */ myFoopy::SetCupid(nsISupports *aCupid) { mCupid = aCupid; } /* * this is xpcom public if you QI to myIFoopy */ NS_IMETHODIMP /* getter myIFoopy.dipuc * note that Get is part of the name and both Get and Dipuc are InitialCaps * note the double pointer since we need to be able to pass out a pointer */ myFoopy::GetDipuc(nsISupports **aResult) { /* xpcom says we addref for getters... */ /* but the code we're calling does that, so we just let it manage the reference * since we aren't dropping it or holding it or otherwise influencing the one it * returns. */ return GetCupid(aResult); } /* * this is xpcom public if you QI to myIFoopy */ NS_IMETHODIMP /* setter myIFoopy.dipuc * note that Set is part of the name and both Set and Dipuc are InitialCaps * note the single pointer since we only need to be given a pointer */ myFoopy::SetDipuc(nsISupports *aCupid) { /* the useless use of this-> is here for equivalence * to the use of this. in js, * and can be conveniently seen as related to the JS * example if you pretend that this is an xpcom pointer to myIFoopy * instead of a pointer to myFoopy. */ * to the useless use of this. in the js example */ return this->SetCupid(aCupid); } /* the implementation of nsIModule is already documented elsewhere and is beyond the scope of this mapping */ /* XPCOM Exception handling (JavaScript) eh.js: */ function eh_js() { try { xpcom_wrapped_object.method(); } catch (e) { switch (e.result) { case Components.results.NS_ERROR_FILE_UNRECOGNIZED_PATH: doSomething(); return; case Components.results.NS_ERROR_FILE_UNRESOLVABLE_SYMLINK: throw Components.results.NS_ERROR_FILE_EXECUTION_FAILED; case Components.results.NS_ERROR_FILE_UNKNOWN_TYPE: throw e.result; default: doSomethingElse(); return; } } } /* XPCOM Exception handling (C++) eh.cpp: */ nsresult Eh_js() { /* this is equivalent to e.result */ nsresult rv; /* this is the method call */ rv = xpcom_object->Method(); /* this is the catch block */ if (NS_FAILED(rv)) { switch (rv) { /* Components.results is a bad reflection of a limited set of nsresult values, in C++, * you get as many as you include, in JS you need to do something like * http://viper.haque.net/~timeless/nsError.js if you want things that aren't reflected. */ case NS_ERROR_FILE_UNRECOGNIZED_PATH: /* Assuming DoSomething is an XPCOM type method we need to catch its return value * since in js that would automatically result in a throw. */ rv = DoSomething(); /* if the return value from DoSomething() is NS_OK, * then we're returning that non exceptional value * otherwise we're returning the thrown exception. */ return rv; case NS_ERROR_FILE_UNRESOLVABLE_SYMLINK: /* here we're throwing a different exception value, just as the js does */ return NS_ERROR_FILE_EXECUTION_FAILED: case NS_ERROR_FILE_UNKNOWN_TYPE: /* here we're rethrowing the same exception value we got, just as the js does */ return rv; default: /* this is equivalent to if (NS_FAILED(rv)) { DoSomethingElse() } which is what you would * normally see in C++ code, but I've left it in a default just to show that you can make life * complicated if you want to. */ rv = DoSomethingElse(); return rv; } } } /* this is equivalent to any non throw in JS, * which is the normal implicit return undefined at the end of the js function. */ return NS_OK; } _______________________________________________ dev-security mailing list dev-security@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-security