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

Reply via email to