LCOV - code coverage report
Current view: directory - js/src/ctypes - Library.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 154 0 0.0 %
Date: 2012-04-07 Functions: 9 0 0.0 %

       1                 : /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is js-ctypes.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * The Mozilla Foundation <http://www.mozilla.org/>.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *  Mark Finkle <mark.finkle@gmail.com>, <mfinkle@mozilla.com>
      24                 :  *  Fredrik Larsson <nossralf@gmail.com>
      25                 :  *  Dan Witte <dwitte@mozilla.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "jscntxt.h"
      42                 : #include "jsstr.h"
      43                 : #include "Library.h"
      44                 : #include "CTypes.h"
      45                 : #include "prlink.h"
      46                 : 
      47                 : namespace js {
      48                 : namespace ctypes {
      49                 : 
      50                 : /*******************************************************************************
      51                 : ** JSAPI function prototypes
      52                 : *******************************************************************************/
      53                 : 
      54                 : namespace Library
      55                 : {
      56                 :   static void Finalize(JSFreeOp *fop, JSObject* obj);
      57                 : 
      58                 :   static JSBool Close(JSContext* cx, unsigned argc, jsval* vp);
      59                 :   static JSBool Declare(JSContext* cx, unsigned argc, jsval* vp);
      60                 : }
      61                 : 
      62                 : /*******************************************************************************
      63                 : ** JSObject implementation
      64                 : *******************************************************************************/
      65                 : 
      66                 : static JSClass sLibraryClass = {
      67                 :   "Library",
      68                 :   JSCLASS_HAS_RESERVED_SLOTS(LIBRARY_SLOTS),
      69                 :   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
      70                 :   JS_EnumerateStub,JS_ResolveStub, JS_ConvertStub, Library::Finalize
      71                 : };
      72                 : 
      73                 : #define CTYPESFN_FLAGS \
      74                 :   (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
      75                 : 
      76                 : static JSFunctionSpec sLibraryFunctions[] = {
      77                 :   JS_FN("close",   Library::Close,   0, CTYPESFN_FLAGS),
      78                 :   JS_FN("declare", Library::Declare, 0, CTYPESFN_FLAGS),
      79                 :   JS_FS_END
      80                 : };
      81                 : 
      82                 : JSBool
      83               0 : Library::Name(JSContext* cx, unsigned argc, jsval *vp)
      84                 : {
      85               0 :   if (argc != 1) {
      86               0 :     JS_ReportError(cx, "libraryName takes one argument");
      87               0 :     return JS_FALSE;
      88                 :   }
      89                 : 
      90               0 :   jsval arg = JS_ARGV(cx, vp)[0];
      91               0 :   JSString* str = NULL;
      92               0 :   if (JSVAL_IS_STRING(arg)) {
      93               0 :     str = JSVAL_TO_STRING(arg);
      94                 :   }
      95                 :   else {
      96               0 :     JS_ReportError(cx, "name argument must be a string");
      97               0 :       return JS_FALSE;
      98                 :   }
      99                 : 
     100               0 :   AutoString resultString;
     101               0 :   AppendString(resultString, DLL_PREFIX);
     102               0 :   AppendString(resultString, str);
     103               0 :   AppendString(resultString, DLL_SUFFIX);
     104                 : 
     105               0 :   JSString *result = JS_NewUCStringCopyN(cx, resultString.begin(),
     106               0 :                                          resultString.length());
     107               0 :   if (!result)
     108               0 :     return JS_FALSE;
     109                 : 
     110               0 :   JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(result));
     111               0 :   return JS_TRUE;
     112                 : }
     113                 : 
     114                 : JSObject*
     115               0 : Library::Create(JSContext* cx, jsval path, JSCTypesCallbacks* callbacks)
     116                 : {
     117               0 :   JSObject* libraryObj = JS_NewObject(cx, &sLibraryClass, NULL, NULL);
     118               0 :   if (!libraryObj)
     119               0 :     return NULL;
     120               0 :   js::AutoObjectRooter root(cx, libraryObj);
     121                 : 
     122                 :   // initialize the library
     123               0 :   JS_SetReservedSlot(libraryObj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(NULL));
     124                 : 
     125                 :   // attach API functions
     126               0 :   if (!JS_DefineFunctions(cx, libraryObj, sLibraryFunctions))
     127               0 :     return NULL;
     128                 : 
     129               0 :   if (!JSVAL_IS_STRING(path)) {
     130               0 :     JS_ReportError(cx, "open takes a string argument");
     131               0 :     return NULL;
     132                 :   }
     133                 : 
     134                 :   PRLibSpec libSpec;
     135               0 :   JSFlatString* pathStr = JS_FlattenString(cx, JSVAL_TO_STRING(path));
     136               0 :   if (!pathStr)
     137               0 :     return NULL;
     138                 : #ifdef XP_WIN
     139                 :   // On Windows, converting to native charset may corrupt path string.
     140                 :   // So, we have to use Unicode path directly.
     141                 :   const PRUnichar* pathChars = JS_GetFlatStringChars(pathStr);
     142                 :   if (!pathChars)
     143                 :     return NULL;
     144                 : 
     145                 :   libSpec.value.pathname_u = pathChars;
     146                 :   libSpec.type = PR_LibSpec_PathnameU;
     147                 : #else
     148                 :   // Convert to platform native charset if the appropriate callback has been
     149                 :   // provided.
     150                 :   char* pathBytes;
     151               0 :   if (callbacks && callbacks->unicodeToNative) {
     152                 :     pathBytes = 
     153               0 :       callbacks->unicodeToNative(cx, pathStr->chars(), pathStr->length());
     154               0 :     if (!pathBytes)
     155               0 :       return NULL;
     156                 : 
     157                 :   } else {
     158                 :     // Fallback: assume the platform native charset is UTF-8. This is true
     159                 :     // for Mac OS X, Android, and probably Linux.
     160                 :     size_t nbytes =
     161               0 :       GetDeflatedUTF8StringLength(cx, pathStr->chars(), pathStr->length());
     162               0 :     if (nbytes == (size_t) -1)
     163               0 :       return NULL;
     164                 : 
     165               0 :     pathBytes = static_cast<char*>(JS_malloc(cx, nbytes + 1));
     166               0 :     if (!pathBytes)
     167               0 :       return NULL;
     168                 : 
     169                 :     ASSERT_OK(DeflateStringToUTF8Buffer(cx, pathStr->chars(),
     170               0 :                 pathStr->length(), pathBytes, &nbytes));
     171               0 :     pathBytes[nbytes] = 0;
     172                 :   }
     173                 : 
     174               0 :   libSpec.value.pathname = pathBytes;
     175               0 :   libSpec.type = PR_LibSpec_Pathname;
     176                 : #endif
     177                 : 
     178               0 :   PRLibrary* library = PR_LoadLibraryWithFlags(libSpec, 0);
     179                 : #ifndef XP_WIN
     180               0 :   JS_free(cx, pathBytes);
     181                 : #endif
     182               0 :   if (!library) {
     183               0 :     JS_ReportError(cx, "couldn't open library");
     184               0 :     return NULL;
     185                 :   }
     186                 : 
     187                 :   // stash the library
     188               0 :   JS_SetReservedSlot(libraryObj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(library));
     189                 : 
     190               0 :   return libraryObj;
     191                 : }
     192                 : 
     193                 : bool
     194               0 : Library::IsLibrary(JSObject* obj)
     195                 : {
     196               0 :   return JS_GetClass(obj) == &sLibraryClass;
     197                 : }
     198                 : 
     199                 : PRLibrary*
     200               0 : Library::GetLibrary(JSObject* obj)
     201                 : {
     202               0 :   JS_ASSERT(IsLibrary(obj));
     203                 : 
     204               0 :   jsval slot = JS_GetReservedSlot(obj, SLOT_LIBRARY);
     205               0 :   return static_cast<PRLibrary*>(JSVAL_TO_PRIVATE(slot));
     206                 : }
     207                 : 
     208                 : static void
     209               0 : UnloadLibrary(JSObject* obj)
     210                 : {
     211               0 :   PRLibrary* library = Library::GetLibrary(obj);
     212               0 :   if (library)
     213               0 :     PR_UnloadLibrary(library);
     214               0 : }
     215                 : 
     216                 : void
     217               0 : Library::Finalize(JSFreeOp *fop, JSObject* obj)
     218                 : {
     219               0 :   UnloadLibrary(obj);
     220               0 : }
     221                 : 
     222                 : JSBool
     223               0 : Library::Open(JSContext* cx, unsigned argc, jsval *vp)
     224                 : {
     225               0 :   JSObject* ctypesObj = JS_THIS_OBJECT(cx, vp);
     226               0 :   if (!ctypesObj || !IsCTypesGlobal(ctypesObj)) {
     227               0 :     JS_ReportError(cx, "not a ctypes object");
     228               0 :     return JS_FALSE;
     229                 :   }
     230                 : 
     231               0 :   if (argc != 1 || JSVAL_IS_VOID(JS_ARGV(cx, vp)[0])) {
     232               0 :     JS_ReportError(cx, "open requires a single argument");
     233               0 :     return JS_FALSE;
     234                 :   }
     235                 : 
     236               0 :   JSObject* library = Create(cx, JS_ARGV(cx, vp)[0], GetCallbacks(ctypesObj));
     237               0 :   if (!library)
     238               0 :     return JS_FALSE;
     239                 : 
     240               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(library));
     241               0 :   return JS_TRUE;
     242                 : }
     243                 : 
     244                 : JSBool
     245               0 : Library::Close(JSContext* cx, unsigned argc, jsval* vp)
     246                 : {
     247               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
     248               0 :   if (!obj || !IsLibrary(obj)) {
     249               0 :     JS_ReportError(cx, "not a library");
     250               0 :     return JS_FALSE;
     251                 :   }
     252                 : 
     253               0 :   if (argc != 0) {
     254               0 :     JS_ReportError(cx, "close doesn't take any arguments");
     255               0 :     return JS_FALSE;
     256                 :   }
     257                 : 
     258                 :   // delete our internal objects
     259               0 :   UnloadLibrary(obj);
     260               0 :   JS_SetReservedSlot(obj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(NULL));
     261                 : 
     262               0 :   JS_SET_RVAL(cx, vp, JSVAL_VOID);
     263               0 :   return JS_TRUE;
     264                 : }
     265                 : 
     266                 : JSBool
     267               0 : Library::Declare(JSContext* cx, unsigned argc, jsval* vp)
     268                 : {
     269               0 :   JSObject* obj = JS_THIS_OBJECT(cx, vp);
     270               0 :   if (!obj || !IsLibrary(obj)) {
     271               0 :     JS_ReportError(cx, "not a library");
     272               0 :     return JS_FALSE;
     273                 :   }
     274                 : 
     275               0 :   PRLibrary* library = GetLibrary(obj);
     276               0 :   if (!library) {
     277               0 :     JS_ReportError(cx, "library not open");
     278               0 :     return JS_FALSE;
     279                 :   }
     280                 : 
     281                 :   // We allow two API variants:
     282                 :   // 1) library.declare(name, abi, returnType, argType1, ...)
     283                 :   //    declares a function with the given properties, and resolves the symbol
     284                 :   //    address in the library.
     285                 :   // 2) library.declare(name, type)
     286                 :   //    declares a symbol of 'type', and resolves it. The object that comes
     287                 :   //    back will be of type 'type', and will point into the symbol data.
     288                 :   //    This data will be both readable and writable via the usual CData
     289                 :   //    accessors. If 'type' is a PointerType to a FunctionType, the result will
     290                 :   //    be a function pointer, as with 1). 
     291               0 :   if (argc < 2) {
     292               0 :     JS_ReportError(cx, "declare requires at least two arguments");
     293               0 :     return JS_FALSE;
     294                 :   }
     295                 : 
     296               0 :   jsval* argv = JS_ARGV(cx, vp);
     297               0 :   if (!JSVAL_IS_STRING(argv[0])) {
     298               0 :     JS_ReportError(cx, "first argument must be a string");
     299               0 :     return JS_FALSE;
     300                 :   }
     301                 : 
     302               0 :   JSObject* fnObj = NULL;
     303                 :   JSObject* typeObj;
     304               0 :   js::AutoObjectRooter root(cx);
     305               0 :   bool isFunction = argc > 2;
     306               0 :   if (isFunction) {
     307                 :     // Case 1).
     308                 :     // Create a FunctionType representing the function.
     309                 :     fnObj = FunctionType::CreateInternal(cx,
     310               0 :               argv[1], argv[2], &argv[3], argc - 3);
     311               0 :     if (!fnObj)
     312               0 :       return JS_FALSE;
     313               0 :     root.setObject(fnObj);
     314                 : 
     315                 :     // Make a function pointer type.
     316               0 :     typeObj = PointerType::CreateInternal(cx, fnObj);
     317               0 :     if (!typeObj)
     318               0 :       return JS_FALSE;
     319               0 :     root.setObject(typeObj);
     320                 : 
     321                 :   } else {
     322                 :     // Case 2).
     323               0 :     if (JSVAL_IS_PRIMITIVE(argv[1]) ||
     324               0 :         !CType::IsCType(JSVAL_TO_OBJECT(argv[1])) ||
     325               0 :         !CType::IsSizeDefined(JSVAL_TO_OBJECT(argv[1]))) {
     326               0 :       JS_ReportError(cx, "second argument must be a type of defined size");
     327               0 :       return JS_FALSE;
     328                 :     }
     329                 : 
     330               0 :     typeObj = JSVAL_TO_OBJECT(argv[1]);
     331               0 :     if (CType::GetTypeCode(typeObj) == TYPE_pointer) {
     332               0 :       fnObj = PointerType::GetBaseType(typeObj);
     333               0 :       isFunction = fnObj && CType::GetTypeCode(fnObj) == TYPE_function;
     334                 :     }
     335                 :   }
     336                 : 
     337                 :   void* data;
     338                 :   PRFuncPtr fnptr;
     339               0 :   JSString* nameStr = JSVAL_TO_STRING(argv[0]);
     340               0 :   AutoCString symbol;
     341               0 :   if (isFunction) {
     342                 :     // Build the symbol, with mangling if necessary.
     343               0 :     FunctionType::BuildSymbolName(nameStr, fnObj, symbol);
     344               0 :     AppendString(symbol, "\0");
     345                 : 
     346                 :     // Look up the function symbol.
     347               0 :     fnptr = PR_FindFunctionSymbol(library, symbol.begin());
     348               0 :     if (!fnptr) {
     349               0 :       JS_ReportError(cx, "couldn't find function symbol in library");
     350               0 :       return JS_FALSE;
     351                 :     }
     352               0 :     data = &fnptr;
     353                 : 
     354                 :   } else {
     355                 :     // 'typeObj' is another data type. Look up the data symbol.
     356               0 :     AppendString(symbol, nameStr);
     357               0 :     AppendString(symbol, "\0");
     358                 : 
     359               0 :     data = PR_FindSymbol(library, symbol.begin());
     360               0 :     if (!data) {
     361               0 :       JS_ReportError(cx, "couldn't find symbol in library");
     362               0 :       return JS_FALSE;
     363                 :     }
     364                 :   }
     365                 : 
     366               0 :   JSObject* result = CData::Create(cx, typeObj, obj, data, isFunction);
     367               0 :   if (!result)
     368               0 :     return JS_FALSE;
     369                 : 
     370               0 :   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(result));
     371                 : 
     372                 :   // Seal the CData object, to prevent modification of the function pointer.
     373                 :   // This permanently associates this object with the library, and avoids
     374                 :   // having to do things like reset SLOT_REFERENT when someone tries to
     375                 :   // change the pointer value.
     376                 :   // XXX This will need to change when bug 541212 is fixed -- CData::ValueSetter
     377                 :   // could be called on a sealed object.
     378               0 :   if (isFunction && !JS_FreezeObject(cx, result))
     379               0 :     return JS_FALSE;
     380                 : 
     381               0 :   return JS_TRUE;
     382                 : }
     383                 : 
     384                 : }
     385                 : }
     386                 : 

Generated by: LCOV version 1.7