LCOV - app.info - js/src/ctypes/Library.cpp

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