mirror of
https://github.com/dart-lang/sdk
synced 2024-09-19 14:32:49 +00:00
0cbfef976d
Review URL: https://chromiumcodereview.appspot.com//10824210 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@10362 260f80e4-7a28-3924-810f-c04153c831b5
416 lines
14 KiB
C
416 lines
14 KiB
C
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "dart_archive.h"
|
|
#include "entry.h"
|
|
#include "messaging.h"
|
|
#include "reader.h"
|
|
|
|
/** The enumeration of request types for communicating with Dart. */
|
|
enum RequestType {
|
|
kArchiveReadNew = 0,
|
|
kArchiveReadSupportFilterAll,
|
|
kArchiveReadSupportFilterBzip2,
|
|
kArchiveReadSupportFilterCompress,
|
|
kArchiveReadSupportFilterGzip,
|
|
kArchiveReadSupportFilterLzma,
|
|
kArchiveReadSupportFilterXz,
|
|
kArchiveReadSupportFilterProgram,
|
|
kArchiveReadSupportFilterProgramSignature,
|
|
kArchiveReadSupportFormatAll,
|
|
kArchiveReadSupportFormatAr,
|
|
kArchiveReadSupportFormatCpio,
|
|
kArchiveReadSupportFormatEmpty,
|
|
kArchiveReadSupportFormatIso9660,
|
|
kArchiveReadSupportFormatMtree,
|
|
kArchiveReadSupportFormatRaw,
|
|
kArchiveReadSupportFormatTar,
|
|
kArchiveReadSupportFormatZip,
|
|
kArchiveReadSetFilterOption,
|
|
kArchiveReadSetFormatOption,
|
|
kArchiveReadSetOption,
|
|
kArchiveReadOpenFilename,
|
|
kArchiveReadOpenMemory,
|
|
kArchiveReadNextHeader,
|
|
kArchiveReadDataBlock,
|
|
kArchiveReadDataSkip,
|
|
kArchiveReadClose,
|
|
kArchiveReadFree,
|
|
kArchiveEntryClone,
|
|
kArchiveEntryFree,
|
|
kArchiveEntryNew,
|
|
kArchiveEntrySetHardlink,
|
|
kArchiveEntrySetPathname,
|
|
kArchiveEntrySetSymlink,
|
|
kArchiveEntrySetGid,
|
|
kArchiveEntrySetUid,
|
|
kArchiveEntrySetPerm,
|
|
kArchiveEntrySetGname,
|
|
kArchiveEntrySetUname,
|
|
kArchiveEntrySetFflagsSet,
|
|
kArchiveEntrySetFflagsClear,
|
|
kArchiveEntrySetFflagsText,
|
|
kArchiveEntrySetFiletype,
|
|
kArchiveEntrySetMode,
|
|
kArchiveEntrySetSize,
|
|
kArchiveEntrySetDev,
|
|
kArchiveEntrySetDevmajor,
|
|
kArchiveEntrySetDevminor,
|
|
kArchiveEntrySetIno,
|
|
kArchiveEntrySetNlink,
|
|
kArchiveEntrySetRdev,
|
|
kArchiveEntrySetRdevmajor,
|
|
kArchiveEntrySetRdevminor,
|
|
kArchiveEntrySetAtime,
|
|
kArchiveEntrySetBirthtime,
|
|
kArchiveEntrySetCtime,
|
|
kArchiveEntrySetMtime,
|
|
kNumberOfRequestTypes
|
|
};
|
|
|
|
/**
|
|
* Dispatches a message from Dart to its native function equivalent.
|
|
*
|
|
* In addition to matching up a message with its respective function, this
|
|
* parses out the standard archive struct argument from the message and resolves
|
|
* it to an actual pointer to an archive struct.
|
|
*/
|
|
static void archiveDispatch(Dart_Port dest_port_id,
|
|
Dart_Port reply_port_id,
|
|
Dart_CObject* message) {
|
|
if (message->type != kArray) {
|
|
postInvalidArgument(reply_port_id, "Message was not an array.");
|
|
return;
|
|
} else if (message->value.as_array.length < 2) {
|
|
postInvalidArgument(reply_port_id, "Message array had %d elements, " \
|
|
"expected at least 2.", message->value.as_array.length);
|
|
return;
|
|
}
|
|
|
|
Dart_CObject* wrapped_request_type = message->value.as_array.values[0];
|
|
if (wrapped_request_type->type != kInt32) {
|
|
postInvalidArgument(reply_port_id, "Invalid request type %d.",
|
|
wrapped_request_type->type);
|
|
return;
|
|
}
|
|
enum RequestType request_type = wrapped_request_type->value.as_int32;
|
|
|
|
Dart_CObject* id = message->value.as_array.values[1];
|
|
void* ptr;
|
|
if (id->type == kNull) {
|
|
ptr = NULL;
|
|
} else if (id->type == kInt64 || id->type == kInt32) {
|
|
ptr = (void*) (intptr_t) getInteger(id);
|
|
} else {
|
|
postInvalidArgument(reply_port_id, "Invalid id type %d.", id->type);
|
|
return;
|
|
}
|
|
|
|
switch (request_type) {
|
|
case kArchiveReadNew:
|
|
archiveReadNew(reply_port_id);
|
|
break;
|
|
case kArchiveReadSupportFilterAll:
|
|
archiveReadSupportFilterAll(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSupportFilterBzip2:
|
|
archiveReadSupportFilterBzip2(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSupportFilterCompress:
|
|
archiveReadSupportFilterCompress(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSupportFilterGzip:
|
|
archiveReadSupportFilterGzip(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSupportFilterLzma:
|
|
archiveReadSupportFilterLzma(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSupportFilterXz:
|
|
archiveReadSupportFilterXz(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSupportFilterProgram:
|
|
archiveReadSupportFilterProgram(
|
|
reply_port_id, (struct archive*) ptr, message);
|
|
break;
|
|
case kArchiveReadSupportFilterProgramSignature:
|
|
archiveReadSupportFilterProgramSignature(
|
|
reply_port_id, (struct archive*) ptr, message);
|
|
break;
|
|
case kArchiveReadSupportFormatAll:
|
|
archiveReadSupportFormatAll(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSupportFormatAr:
|
|
archiveReadSupportFormatAr(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSupportFormatCpio:
|
|
archiveReadSupportFormatCpio(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSupportFormatEmpty:
|
|
archiveReadSupportFormatEmpty(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSupportFormatIso9660:
|
|
archiveReadSupportFormatIso9660(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSupportFormatMtree:
|
|
archiveReadSupportFormatMtree(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSupportFormatRaw:
|
|
archiveReadSupportFormatRaw(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSupportFormatTar:
|
|
archiveReadSupportFormatTar(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSupportFormatZip:
|
|
archiveReadSupportFormatZip(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadSetFilterOption:
|
|
archiveReadSetFilterOption(reply_port_id, (struct archive*) ptr, message);
|
|
break;
|
|
case kArchiveReadSetFormatOption:
|
|
archiveReadSetFormatOption(reply_port_id, (struct archive*) ptr, message);
|
|
break;
|
|
case kArchiveReadSetOption:
|
|
archiveReadSetOption(reply_port_id, (struct archive*) ptr, message);
|
|
break;
|
|
case kArchiveReadOpenFilename:
|
|
archiveReadOpenFilename(reply_port_id, (struct archive*) ptr, message);
|
|
break;
|
|
case kArchiveReadOpenMemory:
|
|
archiveReadOpenMemory(reply_port_id, (struct archive*) ptr, message);
|
|
break;
|
|
case kArchiveReadNextHeader:
|
|
archiveReadNextHeader(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadDataBlock:
|
|
archiveReadDataBlock(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadDataSkip:
|
|
archiveReadDataSkip(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadClose:
|
|
archiveReadClose(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveReadFree:
|
|
archiveReadFree(reply_port_id, (struct archive*) ptr);
|
|
break;
|
|
case kArchiveEntryClone:
|
|
archiveEntryClone(reply_port_id, (struct archive_entry*) ptr);
|
|
break;
|
|
case kArchiveEntryFree:
|
|
archiveEntryFree(reply_port_id, (struct archive_entry*) ptr);
|
|
break;
|
|
case kArchiveEntryNew:
|
|
archiveEntryNew(reply_port_id);
|
|
break;
|
|
case kArchiveEntrySetHardlink:
|
|
archiveEntrySetHardlink(
|
|
reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetPathname:
|
|
archiveEntrySetPathname(
|
|
reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetSymlink:
|
|
archiveEntrySetSymlink(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetGid:
|
|
archiveEntrySetGid(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetUid:
|
|
archiveEntrySetUid(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetPerm:
|
|
archiveEntrySetPerm(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetGname:
|
|
archiveEntrySetGname(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetUname:
|
|
archiveEntrySetUname(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetFflagsSet:
|
|
archiveEntrySetFflagsSet(
|
|
reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetFflagsClear:
|
|
archiveEntrySetFflagsClear(
|
|
reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetFiletype:
|
|
archiveEntrySetFiletype(
|
|
reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetMode:
|
|
archiveEntrySetMode(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetSize:
|
|
archiveEntrySetSize(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetDev:
|
|
archiveEntrySetDev(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetDevmajor:
|
|
archiveEntrySetDevmajor(
|
|
reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetDevminor:
|
|
archiveEntrySetDevminor(
|
|
reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetIno:
|
|
archiveEntrySetIno(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetNlink:
|
|
archiveEntrySetNlink(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetRdev:
|
|
archiveEntrySetRdev(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetRdevmajor:
|
|
archiveEntrySetRdevmajor(
|
|
reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetRdevminor:
|
|
archiveEntrySetRdevminor(
|
|
reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetAtime:
|
|
archiveEntrySetAtime(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetBirthtime:
|
|
archiveEntrySetBirthtime(
|
|
reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetCtime:
|
|
archiveEntrySetCtime(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
case kArchiveEntrySetMtime:
|
|
archiveEntrySetMtime(reply_port_id, (struct archive_entry*) ptr, message);
|
|
break;
|
|
default:
|
|
postInvalidArgument(reply_port_id, "Invalid request id %d.", request_type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if [handle] represents an error and, if so, propagates it to Dart.
|
|
* Otherwise, returns [handle].
|
|
*/
|
|
static Dart_Handle handleError(Dart_Handle handle) {
|
|
if (Dart_IsError(handle)) Dart_PropagateError(handle);
|
|
return handle;
|
|
}
|
|
|
|
/**
|
|
* A function exposed to Dart that creates a [ServicePort] for two-way
|
|
* communication between Dart and C.
|
|
*
|
|
* Takes no arguments and returns a [ServicePort].
|
|
*/
|
|
static void archiveServicePort(Dart_NativeArguments arguments) {
|
|
Dart_EnterScope();
|
|
Dart_SetReturnValue(arguments, Dart_Null());
|
|
Dart_Port service_port =
|
|
Dart_NewNativePort("ArchiveService", archiveDispatch, false);
|
|
if (service_port != ILLEGAL_PORT) {
|
|
Dart_Handle send_port = handleError(Dart_NewSendPort(service_port));
|
|
Dart_SetReturnValue(arguments, send_port);
|
|
}
|
|
Dart_ExitScope();
|
|
}
|
|
|
|
/**
|
|
* The C callback that runs the Dart finalizer for an object. Set up by
|
|
* [attachDartFinalizer]. [handle] is the object that's been collected, and
|
|
* [peerPtr] is a Dart list containing the callback and its argument.
|
|
*/
|
|
static void runDartFinalizer(Dart_Handle handle, void* peerPtr) {
|
|
Dart_EnterScope();
|
|
Dart_Handle wrappedPeer = (Dart_Handle) peerPtr;
|
|
Dart_Handle callback = handleError(Dart_ListGetAt(wrappedPeer, 0));
|
|
Dart_Handle peer = handleError(Dart_ListGetAt(wrappedPeer, 1));
|
|
|
|
handleError(Dart_InvokeClosure(callback, 1, &peer));
|
|
Dart_DeletePersistentHandle(wrappedPeer);
|
|
Dart_ExitScope();
|
|
}
|
|
|
|
/**
|
|
* Attaches a finalizer callback to a Dart object.
|
|
*
|
|
* This takes a Dart object, a callback function, and an argument to pass to the
|
|
* callback function. The callback will be called with the given argument some
|
|
* time after the object has been garbage collected.
|
|
*/
|
|
static void attachDartFinalizer(Dart_NativeArguments arguments) {
|
|
Dart_EnterScope();
|
|
Dart_SetReturnValue(arguments, Dart_Null());
|
|
Dart_Handle object = handleError(Dart_GetNativeArgument(arguments, 0));
|
|
Dart_Handle callback = handleError(Dart_GetNativeArgument(arguments, 1));
|
|
Dart_Handle peer = handleError(Dart_GetNativeArgument(arguments, 2));
|
|
|
|
Dart_Handle wrappedPeer = handleError(Dart_NewList(2));
|
|
handleError(Dart_ListSetAt(wrappedPeer, 0, callback));
|
|
handleError(Dart_ListSetAt(wrappedPeer, 1, peer));
|
|
wrappedPeer = handleError(Dart_NewPersistentHandle(wrappedPeer));
|
|
|
|
handleError(Dart_NewWeakPersistentHandle(
|
|
object, wrappedPeer, runDartFinalizer));
|
|
Dart_ExitScope();
|
|
}
|
|
|
|
/**
|
|
* A struct representing a function exposed to Dart and the name under which it
|
|
* can be looked up.
|
|
*/
|
|
struct FunctionLookup {
|
|
const char* name;
|
|
Dart_NativeFunction function;
|
|
};
|
|
|
|
/** The list of functions exposed to Dart. */
|
|
struct FunctionLookup function_list[] = {
|
|
{"Archive_ServicePort", archiveServicePort},
|
|
{"Archive_AttachFinalizer", attachDartFinalizer},
|
|
{NULL, NULL}
|
|
};
|
|
|
|
/**
|
|
* Resolves a Dart name as provided in a `native` declaration and returns the
|
|
* C function that should be invoked for that name.
|
|
*/
|
|
static Dart_NativeFunction resolveName(Dart_Handle name, int argc) {
|
|
if (!Dart_IsString8(name)) return NULL;
|
|
Dart_EnterScope();
|
|
const char* cname;
|
|
handleError(Dart_StringToCString(name, &cname));
|
|
|
|
Dart_NativeFunction result = NULL;
|
|
int i;
|
|
for (i = 0; function_list[i].name != NULL; ++i) {
|
|
if (strcmp(function_list[i].name, cname) == 0) {
|
|
result = function_list[i].function;
|
|
break;
|
|
}
|
|
}
|
|
Dart_ExitScope();
|
|
return result;
|
|
}
|
|
|
|
/** Initializes the C extension. */
|
|
DART_EXPORT Dart_Handle dart_archive_Init(Dart_Handle parent_library) {
|
|
if (Dart_IsError(parent_library)) return parent_library;
|
|
|
|
Dart_Handle result_code = Dart_SetNativeResolver(parent_library, resolveName);
|
|
if (Dart_IsError(result_code)) return result_code;
|
|
|
|
return Dart_Null();
|
|
}
|