From 506d2257cc7c49f3ed61bd8ea3b667a353ae59a3 Mon Sep 17 00:00:00 2001 From: Roee Kasher Date: Sat, 22 Jul 2017 23:04:36 +0300 Subject: [PATCH 1/3] Added an option to compile a magic file using mmmagic. --- .gitignore | 4 ++ README.md | 15 +++++ package.json | 3 +- src/binding.cc | 136 ++++++++++++++++++++++++++++++++++++++++- test/dummy_magic_file | 3 + test/dummy_magic_file2 | 3 + test/test.js | 24 ++++++++ 7 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 test/dummy_magic_file create mode 100644 test/dummy_magic_file2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89adcde --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +dummy_magic_file.mgc +dummy_magic_file2.mgc +node_modules/ +build/ diff --git a/README.md b/README.md index 13fabc9..38466fd 100644 --- a/README.md +++ b/README.md @@ -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: [ 'dummy_magic_file.mgc' ] + }); +``` + API === @@ -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 colon separated list of database files. The compiled files 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 an array of < _String_ > containing the names of the compiled files. diff --git a/package.json b/package.json index aaecebc..37a7377 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "mmmagic", - "version": "0.4.5", + "version": "0.4.6", "author": "Brian White ", + "contributors": "Roee Kasher ", "description": "An async libmagic binding for node.js for detecting content types by data inspection", "main": "./lib/index", "dependencies": { diff --git a/src/binding.cc b/src/binding.cc index 6fb43a0..a68dfdc 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -342,14 +342,148 @@ class Magic : public ObjectWrap { return args.GetReturnValue().Set(args.This()); } - static void Initialize(Handle target) { + static void Compile(const Nan::FunctionCallbackInfo& args) { + Nan::HandleScope(); + Magic* obj = ObjectWrap::Unwrap(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 callback = Local::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(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(req->data); + + if (baton->error) { + // In case of error - return it to the user. + Local err = Nan::Error(baton->error_message); + + if (baton->free_error) + free(baton->error_message); + + Local argv[1] = { err }; + baton->callback->Call(1, argv); + } else { + Local argv[2]; + // no Error + argv[0] = Nan::Null(); + + // Creating the list of the compiled magic files + Local results = Nan::New(); + uint32_t i = 0; + char *file_path = strtok(baton->data, ":"); + + while(file_path != NULL) + { + // Getting the file name from the source + const char* file_path_dup = strdup(file_path); + const char* file_name = basename(file_path_dup); + + // Creating the name of the mgc file (which is the magic file name + ".mgc") + size_t file_name_length = strlen(file_name); + 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, file_name); + strcat(mgc_file_name, ".mgc"); + mgc_file_name[mgc_file_name_length] = '\0'; + + // Adding to results + Nan::Set(Local::Cast(results), + i++, + Nan::New(mgc_file_name).ToLocalChecked()); + + // Cleaning + free((void*)file_path_dup); + delete[] mgc_file_name; + + // Looking for the next file name + file_path=strtok(NULL, ":"); + } + + argv[1] = Local(results); + + if (baton->result) + free((void*)baton->result); + + baton->callback->Call(2, argv); + } + + free(baton->data); + delete baton->callback; + delete baton; + } + + static void Initialize(Handle target) { Local tpl = Nan::New(New); tpl->InstanceTemplate()->SetInternalFieldCount(1); tpl->SetClassName(Nan::New("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("setFallback").ToLocalChecked(), diff --git a/test/dummy_magic_file b/test/dummy_magic_file new file mode 100644 index 0000000..8ee8eb1 --- /dev/null +++ b/test/dummy_magic_file @@ -0,0 +1,3 @@ +0 belong&0xFF5FFF10 0x47400010 +>188 byte 0x47 MPEG transport stream data +!:mimevideo/MP2T diff --git a/test/dummy_magic_file2 b/test/dummy_magic_file2 new file mode 100644 index 0000000..8ee8eb1 --- /dev/null +++ b/test/dummy_magic_file2 @@ -0,0 +1,3 @@ +0 belong&0xFF5FFF10 0x47400010 +>188 byte 0x47 MPEG transport stream data +!:mimevideo/MP2T diff --git a/test/test.js b/test/test.js index 934b011..0b0e3fb 100644 --- a/test/test.js +++ b/test/test.js @@ -98,6 +98,30 @@ 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 - one file' + }, + { run: function() { + var dummy_magic_file = path.join(__dirname, 'dummy_magic_file'); + var dummy_magic_file2 = dummy_magic_file + "2"; + var colon_seperated_magic_files = dummy_magic_file + ":" + dummy_magic_file2; + var magic = new mmm.Magic(mmm.MAGIC_MIME_TYPE); + magic.compile(colon_seperated_magic_files, function(err, result) { + assert.strictEqual(err, null); + assert.deepEqual(result, ['dummy_magic_file' + '.mgc', 'dummy_magic_file2' + '.mgc']); + next(); + }); + }, + what: 'compile - several files' + } ]; function next() { From cc4a0749c7b437c4e4ceb186cca1d42f5784b723 Mon Sep 17 00:00:00 2001 From: Roee Kasher Date: Mon, 5 Mar 2018 13:55:47 +0200 Subject: [PATCH 2/3] CI fixes --- README.md | 4 ++-- src/binding.cc | 18 +++++++++++++++--- test/test.js | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 28c9b7e..03db72b 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ Examples var magic = new Magic(); - magic.compile("node_modules/mmmagic/test/dummy_magic_file", function(err, result) { + magic.compile("node_modules/mmmagic/test/dummy_magic_file;node_modules/mmmagic/test/dummy_magic_file2", 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: [ 'dummy_magic_file.mgc' ] @@ -122,4 +122,4 @@ Magic methods * **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 colon separated list of database files. The compiled files 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 an array of < _String_ > containing the names of the compiled files. +* **compile**(< _String_ >path, < _Function_ >callback) - _(void)_ - Compile a semicolon separated list of database files. The compiled files 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 an array of < _String_ > containing the names of the compiled files. diff --git a/src/binding.cc b/src/binding.cc index a68dfdc..d339ecf 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -8,6 +8,8 @@ # include # include # include +#else +# include #endif #include "magic.h" @@ -434,13 +436,23 @@ class Magic : public ObjectWrap { // Creating the list of the compiled magic files Local results = Nan::New(); uint32_t i = 0; - char *file_path = strtok(baton->data, ":"); + char *file_path = strtok(baton->data, ";"); while(file_path != NULL) { // Getting the file name from the source const char* file_path_dup = strdup(file_path); - const char* file_name = basename(file_path_dup); + const char* file_name; +#ifdef _WIN32 + char drive[_MAX_DRIVE]; + char dir[_MAX_DIR]; + char fname[_MAX_FNAME]; + char ext[_MAX_EXT]; + _splitpath_s(file_path_dup, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT); + file_name = fname; +#else + file_name = basename(file_path_dup); +#endif // Creating the name of the mgc file (which is the magic file name + ".mgc") size_t file_name_length = strlen(file_name); @@ -460,7 +472,7 @@ class Magic : public ObjectWrap { delete[] mgc_file_name; // Looking for the next file name - file_path=strtok(NULL, ":"); + file_path=strtok(NULL, ";"); } argv[1] = Local(results); diff --git a/test/test.js b/test/test.js index 0b0e3fb..9b71b34 100644 --- a/test/test.js +++ b/test/test.js @@ -112,7 +112,7 @@ var tests = [ { run: function() { var dummy_magic_file = path.join(__dirname, 'dummy_magic_file'); var dummy_magic_file2 = dummy_magic_file + "2"; - var colon_seperated_magic_files = dummy_magic_file + ":" + dummy_magic_file2; + var colon_seperated_magic_files = dummy_magic_file + ";" + dummy_magic_file2; var magic = new mmm.Magic(mmm.MAGIC_MIME_TYPE); magic.compile(colon_seperated_magic_files, function(err, result) { assert.strictEqual(err, null); From c8ab633f98b67fe3b6985f31bebb5f99b8ca2808 Mon Sep 17 00:00:00 2001 From: Roee Kasher Date: Mon, 5 Mar 2018 15:51:38 +0200 Subject: [PATCH 3/3] CI fixes --- .gitignore | 1 - README.md | 6 ++--- src/binding.cc | 56 ++++++++---------------------------------- test/dummy_magic_file2 | 3 --- test/test.js | 17 ++----------- 5 files changed, 15 insertions(+), 68 deletions(-) delete mode 100644 test/dummy_magic_file2 diff --git a/.gitignore b/.gitignore index 89adcde..657db46 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ dummy_magic_file.mgc -dummy_magic_file2.mgc node_modules/ build/ diff --git a/README.md b/README.md index 03db72b..e7c1812 100644 --- a/README.md +++ b/README.md @@ -82,10 +82,10 @@ Examples var magic = new Magic(); - magic.compile("node_modules/mmmagic/test/dummy_magic_file;node_modules/mmmagic/test/dummy_magic_file2", function(err, result) { + 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: [ 'dummy_magic_file.mgc' ] + // output: Compiled magic file successfully. Compile file name: 'node_modules/mmmagic/test/dummy_magic_file.mgc' }); ``` @@ -122,4 +122,4 @@ Magic methods * **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 semicolon separated list of database files. The compiled files 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 an array of < _String_ > containing the names of the compiled files. +* **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. diff --git a/src/binding.cc b/src/binding.cc index d339ecf..82b882a 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -8,8 +8,6 @@ # include # include # include -#else -# include #endif #include "magic.h" @@ -432,55 +430,21 @@ class Magic : public ObjectWrap { Local argv[2]; // no Error argv[0] = Nan::Null(); - - // Creating the list of the compiled magic files - Local results = Nan::New(); - uint32_t i = 0; - char *file_path = strtok(baton->data, ";"); - - while(file_path != NULL) - { - // Getting the file name from the source - const char* file_path_dup = strdup(file_path); - const char* file_name; -#ifdef _WIN32 - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char fname[_MAX_FNAME]; - char ext[_MAX_EXT]; - _splitpath_s(file_path_dup, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT); - file_name = fname; -#else - file_name = basename(file_path_dup); -#endif - // Creating the name of the mgc file (which is the magic file name + ".mgc") - size_t file_name_length = strlen(file_name); - 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, file_name); - strcat(mgc_file_name, ".mgc"); - mgc_file_name[mgc_file_name_length] = '\0'; - - // Adding to results - Nan::Set(Local::Cast(results), - i++, - Nan::New(mgc_file_name).ToLocalChecked()); - - // Cleaning - free((void*)file_path_dup); - delete[] mgc_file_name; - - // Looking for the next file name - file_path=strtok(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(mgc_file_name).ToLocalChecked(); + delete[] mgc_file_name; - argv[1] = Local(results); + baton->callback->Call(2, argv); if (baton->result) free((void*)baton->result); - - baton->callback->Call(2, argv); } free(baton->data); diff --git a/test/dummy_magic_file2 b/test/dummy_magic_file2 deleted file mode 100644 index 8ee8eb1..0000000 --- a/test/dummy_magic_file2 +++ /dev/null @@ -1,3 +0,0 @@ -0 belong&0xFF5FFF10 0x47400010 ->188 byte 0x47 MPEG transport stream data -!:mimevideo/MP2T diff --git a/test/test.js b/test/test.js index 9b71b34..bc1bd24 100644 --- a/test/test.js +++ b/test/test.js @@ -103,24 +103,11 @@ var tests = [ var magic = new mmm.Magic(); magic.compile(dummy_magic_file, function(err, result) { assert.strictEqual(err, null); - assert.deepEqual(result, ['dummy_magic_file' + '.mgc']); + assert.deepEqual(result, dummy_magic_file + '.mgc'); next(); }); }, - what: 'compile - one file' - }, - { run: function() { - var dummy_magic_file = path.join(__dirname, 'dummy_magic_file'); - var dummy_magic_file2 = dummy_magic_file + "2"; - var colon_seperated_magic_files = dummy_magic_file + ";" + dummy_magic_file2; - var magic = new mmm.Magic(mmm.MAGIC_MIME_TYPE); - magic.compile(colon_seperated_magic_files, function(err, result) { - assert.strictEqual(err, null); - assert.deepEqual(result, ['dummy_magic_file' + '.mgc', 'dummy_magic_file2' + '.mgc']); - next(); - }); - }, - what: 'compile - several files' + what: 'compile' } ];