Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added an option to compile a database file using mmmagic. #112

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dummy_magic_file.mgc
node_modules/
build/
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,19 @@ Examples
});
```

* Compile a magic file:
```javascript
var Magic = require('mmmagic').Magic;

var magic = new Magic();

magic.compile("node_modules/mmmagic/test/dummy_magic_file", function(err, result) {
if (err) throw err;
console.log("Compiled magic file successfully. Compile file name: ", result);
// output: Compiled magic file successfully. Compile file name: 'node_modules/mmmagic/test/dummy_magic_file.mgc'
});
```

API
===

Expand Down Expand Up @@ -108,3 +121,5 @@ Magic methods
* **detectFile**(< _String_ >path, < _Function_ >callback) - _(void)_ - Inspects the file pointed at by path. The callback receives two arguments: an < _Error_ > object in case of error (null otherwise), and a < _String_ > containing the result of the inspection.

* **detect**(< _Buffer_ >data, < _Function_ >callback) - _(void)_ - Inspects the contents of data. The callback receives two arguments: an < _Error_ > object in case of error (null otherwise), and a < _String_ > containing the result of the inspection.

* **compile**(< _String_ >path, < _Function_ >callback) - _(void)_ - Compile a single database file. The compiled file can be used later on with one of the other methods. The callback receives two arguments: an < _Error_ > object in case of error (null otherwise), and a < _String_ > containing the name of the compiled magic file.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{ "name": "mmmagic",
"version": "0.5.0",
"version": "0.5.1",
"author": "Brian White <[email protected]>",
"contributors": "Roee Kasher <[email protected]>",
"description": "An async libmagic binding for node.js for detecting content types by data inspection",
"main": "./lib/index",
"dependencies": {
Expand Down
112 changes: 111 additions & 1 deletion src/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -342,14 +342,124 @@ class Magic : public ObjectWrap {
return args.GetReturnValue().Set(args.This());
}

static void Initialize(Handle<Object> target) {
static void Compile(const Nan::FunctionCallbackInfo<v8::Value>& args) {
Nan::HandleScope();
Magic* obj = ObjectWrap::Unwrap<Magic>(args.This());

if (args.Length() < 2)
return Nan::ThrowTypeError("Expecting 2 arguments");
if (!args[0]->IsString())
return Nan::ThrowTypeError("First argument must be a string");
if (!args[1]->IsFunction())
return Nan::ThrowTypeError("Second argument must be a callback function");

Local<Function> callback = Local<Function>::Cast(args[1]);
String::Utf8Value str(args[0]->ToString());

Baton* baton = new Baton();
baton->error = false;
baton->free_error = true;
baton->error_message = NULL;
baton->request.data = baton;
baton->callback = new Nan::Callback(callback);
baton->data = strdup((const char*)*str);
baton->path = obj->mpath;
baton->result = NULL;

int status = uv_queue_work(uv_default_loop(),
&baton->request,
Magic::CompileWork,
(uv_after_work_cb)Magic::CompileAfter);
assert(status == 0);

args.GetReturnValue().Set(Nan::Undefined());
}

static void CompileWork(uv_work_t* req) {
Baton* baton = static_cast<Baton*>(req->data);
struct magic_set *magic = magic_open(baton->flags
| MAGIC_NO_CHECK_COMPRESS
| MAGIC_ERROR);

if (magic == NULL) {
baton->error = true;
#if NODE_MODULE_VERSION <= 0x000B
baton->error_message = strdup(uv_strerror(
uv_last_error(uv_default_loop())));
#else
// XXX libuv 1.x currently has no public cross-platform function to convert an
// OS-specific error number to a libuv error number. `-errno` should work
// for *nix, but just passing GetLastError() on Windows will not work ...
# ifdef _MSC_VER
baton->error_message = strdup(uv_strerror(GetLastError()));
# else
baton->error_message = strdup(uv_strerror(-errno));
# endif
#endif
return;
}

int compile_result = magic_compile(magic, baton->data);

// Compile returns -1 if failed, and 0 if succeeded
if (compile_result == -1) {
const char* error = magic_error(magic);
if (error) {
baton->error = true;
baton->error_message = strdup(error);
}
}

magic_close(magic);
}

static void CompileAfter(uv_work_t* req) {
Nan::HandleScope scope;
Baton* baton = static_cast<Baton*>(req->data);

if (baton->error) {
// In case of error - return it to the user.
Local<Value> err = Nan::Error(baton->error_message);

if (baton->free_error)
free(baton->error_message);

Local<Value> argv[1] = { err };
baton->callback->Call(1, argv);
} else {
Local<Value> argv[2];
// no Error
argv[0] = Nan::Null();

// Preparing result
size_t file_name_length = strlen(baton->data);
size_t mgc_file_name_length = file_name_length + 4;
char* mgc_file_name = new char[mgc_file_name_length + 1];
strcpy(mgc_file_name, baton->data);
strcat(mgc_file_name, ".mgc");
mgc_file_name[mgc_file_name_length] = '\0';
argv[1] = Nan::New<String>(mgc_file_name).ToLocalChecked();
delete[] mgc_file_name;

baton->callback->Call(2, argv);

if (baton->result)
free((void*)baton->result);
}

free(baton->data);
delete baton->callback;
delete baton;
}

static void Initialize(Handle<Object> target) {
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);

tpl->InstanceTemplate()->SetInternalFieldCount(1);
tpl->SetClassName(Nan::New<String>("Magic").ToLocalChecked());
Nan::SetPrototypeMethod(tpl, "detectFile", DetectFile);
Nan::SetPrototypeMethod(tpl, "detect", Detect);
Nan::SetPrototypeMethod(tpl, "compile", Compile);

constructor.Reset(tpl->GetFunction());
target->Set(Nan::New<String>("setFallback").ToLocalChecked(),
Expand Down
3 changes: 3 additions & 0 deletions test/dummy_magic_file
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
0 belong&0xFF5FFF10 0x47400010
>188 byte 0x47 MPEG transport stream data
!:mimevideo/MP2T
11 changes: 11 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,17 @@ var tests = [
},
what: 'detect - Normal operation, mime type'
},
{ run: function() {
var dummy_magic_file = path.join(__dirname, 'dummy_magic_file');
var magic = new mmm.Magic();
magic.compile(dummy_magic_file, function(err, result) {
assert.strictEqual(err, null);
assert.deepEqual(result, dummy_magic_file + '.mgc');
next();
});
},
what: 'compile'
}
];

function next() {
Expand Down