├── .gitignore ├── .jshintrc ├── test ├── binding.gyp ├── test.cc └── test.js ├── .travis.yml ├── package.json ├── History.md ├── appveyor.yml ├── index.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /test/build 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | laxcomma: "false" 3 | } 4 | -------------------------------------------------------------------------------- /test/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'targets': [ 3 | { 4 | 'target_name': 'test', 5 | 'sources': [ 'test.cc' ], 6 | 'include_dirs': [ 7 | ' 2 | #include 3 | #include "nan.h" 4 | 5 | using namespace node; 6 | 7 | namespace { 8 | 9 | static wchar_t w = L'w'; 10 | static wchar_t s[] = L"hello world"; 11 | static wchar_t **str = reinterpret_cast(&s); 12 | 13 | void Initialize(v8::Handle target) { 14 | Nan::HandleScope scope; 15 | 16 | Nan::Set(target, Nan::New("w").ToLocalChecked(), Nan::NewBuffer(reinterpret_cast(&w), sizeof(w)).ToLocalChecked()); 17 | Nan::Set(target, Nan::New("s").ToLocalChecked(), Nan::NewBuffer(reinterpret_cast(&s), sizeof(s)).ToLocalChecked()); 18 | Nan::Set(target, Nan::New("str").ToLocalChecked(), Nan::NewBuffer(reinterpret_cast(&str), sizeof(str)).ToLocalChecked()); 19 | } 20 | 21 | } // anonymous namespace 22 | 23 | NODE_MODULE(test, Initialize); 24 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 2 | var assert = require('assert'); 3 | var ref = require('ref'); 4 | var wchar_t = require('../'); 5 | var wchar_string = wchar_t.string; 6 | var bindings = require('bindings')({ module_root: __dirname, bindings: 'test' }) 7 | 8 | describe('wchar_t', function () { 9 | 10 | afterEach(gc); 11 | 12 | it('should get "w" from the "w" symbol', function () { 13 | var str = ref.get(bindings.w, 0, wchar_t); 14 | assert.equal(str, 'w'); 15 | }); 16 | 17 | }); 18 | 19 | describe('wchar_t *', function () { 20 | 21 | afterEach(gc); 22 | 23 | it('should get "hello world" from the "str" symbol', function () { 24 | var str = ref.get(bindings.str, 0, wchar_string); 25 | assert.equal(str, 'hello world'); 26 | }); 27 | 28 | }); 29 | 30 | describe('toString()', function () { 31 | 32 | afterEach(gc); 33 | 34 | it('should get "hello world" from the "s" symbol', function () { 35 | var str = wchar_t.toString(bindings.s); 36 | assert.equal(str, 'hello world\0'); 37 | }); 38 | 39 | }); 40 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ref-wchar", 3 | "version": "1.0.2", 4 | "description": "A ref \"type\" implementation of `wchar_t *` (a.k.a. wide string) backed by \"node-iconv\"", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node-gyp rebuild --directory test && mocha -gc --reporter spec" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git@github.com:TooTallNate/ref-wchar.git" 12 | }, 13 | "keywords": [ 14 | "ref", 15 | "type", 16 | "wchar", 17 | "wchar_t", 18 | "wide", 19 | "string", 20 | "c", 21 | "c++", 22 | "ffi", 23 | "abi" 24 | ], 25 | "author": "Nathan Rajlich (http://n8.io/)", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/TooTallNate/ref-wchar/issues" 29 | }, 30 | "homepage": "https://github.com/TooTallNate/ref-wchar", 31 | "dependencies": { 32 | "iconv": "2", 33 | "ref": "^1.3.1" 34 | }, 35 | "devDependencies": { 36 | "bindings": "~1.2.0", 37 | "mocha": "2", 38 | "nan": "2" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 1.0.2 / 2016-06-07 3 | ================== 4 | 5 | * Update travis.yml to use node version 6 (#6, @cookiengineer) 6 | * Update appveyor.xml to use node 6 as build target (#5, @cookiengineer) 7 | * package: update `iconv` dependency to use only major version 2 (#4, @cookiengineer) 8 | 9 | 1.0.1 / 2015-12-27 10 | ================== 11 | 12 | * package: update "ref" to v1.3.1 13 | * update for nan v2 / node.js v4 14 | * test: moar tests 15 | * test: test node v5 16 | * README: use SVG for appveyor badge 17 | 18 | 1.0.0 / 2015-03-24 19 | ================== 20 | 21 | * add .travis.yml and appveyor.yml files 22 | * index: use `toString()` in `wchar_t.get()` 23 | * README: add travis and appveyor badges 24 | * README: use C-style cast since we say C library 25 | * README: better example 26 | * package: update "ref" to v1.0.1 27 | 28 | 0.0.1 / 2014-06-19 29 | ================== 30 | 31 | * add initial tests 32 | * add .gitignore file 33 | * index: add lower-level `toString()` function 34 | * remove test.js file 35 | * index: throw a TypeError when a bad value is passed in to wchar_t set() 36 | * index: make `wchar_t` type based off of int16 or int32 37 | * index: add base `wchar_t` type 38 | * add README.md 39 | * beginnings of turning into a proper npm module 40 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # http://www.appveyor.com/docs/appveyor-yml 2 | 3 | # Test against these versions of Node.js. 4 | environment: 5 | # Visual Studio Version 6 | MSVS_VERSION: 2013 7 | # Test against these versions of Node.js and io.js 8 | matrix: 9 | # node.js 10 | - nodejs_version: "0.8" 11 | - nodejs_version: "0.10" 12 | - nodejs_version: "0.12" 13 | - nodejs_version: "2" 14 | - nodejs_version: "3.2" 15 | - nodejs_version: "4" 16 | - nodejs_version: "5" 17 | - nodejs_version: "6" 18 | 19 | platform: 20 | - x86 21 | - x64 22 | 23 | # Install scripts. (runs after repo cloning) 24 | install: 25 | # Get the latest stable version of Node 0.STABLE.latest 26 | - ps: if($env:nodejs_version -eq "0.8") {Install-Product node $env:nodejs_version} 27 | - ps: if($env:nodejs_version -ne "0.8") {Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version)} 28 | # Node 0.8 comes with a too obsolete npm 29 | - IF %nodejs_version% == 0.8 (npm install -g npm@1.4.28) 30 | # Install latest NPM only for node.js versions until built in node-gyp adds io.js support 31 | # Update is required for node.js 0.8 because built in npm(node-gyp) does not know VS2013 32 | - IF %nodejs_version% LSS 1 (npm install -g npm@2) 33 | - IF %nodejs_version% LSS 1 set PATH=%APPDATA%\npm;%PATH% 34 | # Typical npm stuff. 35 | - npm install --msvs_version=%MSVS_VERSION% 36 | 37 | # Post-install test scripts. 38 | test_script: 39 | # Output useful info for debugging. 40 | - node --version 41 | - npm --version 42 | # run tests 43 | - npm test 44 | 45 | # Don't actually build. 46 | build: off 47 | 48 | # Set build version format here instead of in the admin panel. 49 | version: "{build}" 50 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Module dependencies. 4 | */ 5 | 6 | var ref = require('ref'); 7 | var Iconv = require('iconv').Iconv; 8 | 9 | /** 10 | * On Windows they're UTF-16 (2-bytes), 11 | * but on Unix platform they're UTF-32 (4-bytes). 12 | * 13 | * TODO: add a way to optionally enable `-fshort-wchar` for Unix (gcc option). 14 | */ 15 | 16 | var size; 17 | if ('win32' == process.platform) { 18 | size = 2; 19 | } else { 20 | size = 4; 21 | } 22 | 23 | var getter = new Iconv('UTF-' + (8 * size) + ref.endianness, 'UTF-8'); 24 | var setter = new Iconv('UTF-8', 'UTF-' + (8 * size) + ref.endianness); 25 | 26 | 27 | /** 28 | * The `wchar_t` type. 29 | */ 30 | 31 | exports = module.exports = Object.create(ref.types['int' + (8 * size)]); 32 | exports.name = 'wchar_t'; 33 | exports.size = size; 34 | exports.indirection = 1; 35 | exports.get = function get (buf, offset) { 36 | if (offset > 0 || buf.length !== exports.size) { 37 | offset = offset | 0; 38 | buf = buf.slice(offset, offset + size); 39 | } 40 | return exports.toString(buf); 41 | }; 42 | exports.set = function set (buf, offset, val) { 43 | var _buf = val; // assume val is a Buffer by default 44 | if (typeof val === 'string') { 45 | _buf = setter.convert(val[0]); 46 | } else if (typeof val === 'number') { 47 | _buf = setter.convert(String.fromCharCode(val)); 48 | } else if (!_buf) { 49 | throw new TypeError('muss pass a String, Number, or Buffer for `wchar_t`'); 50 | } 51 | return _buf.copy(buf, offset, 0, size); 52 | }; 53 | 54 | 55 | /** 56 | * The "wchar_t *" type. 57 | * 58 | * We use the "CString" type as a base since it's pretty close to what we 59 | * actually want. We just have to define custom "get" and "set" functions. 60 | */ 61 | 62 | exports.string = Object.create(ref.types.CString); 63 | exports.string.name = 'WCString'; 64 | exports.string.get = function get (buf, offset) { 65 | var _buf = buf.readPointer(offset); 66 | if (_buf.isNull()) { 67 | return null; 68 | } 69 | var stringBuf = _buf.reinterpretUntilZeros(exports.size); 70 | return exports.toString(stringBuf); 71 | }; 72 | exports.string.set = function set (buf, offset, val) { 73 | var _buf = val; // val is a Buffer? it better be \0 terminated... 74 | if ('string' == typeof val) { 75 | _buf = setter.convert(val + '\0'); 76 | } 77 | return buf.writePointer(_buf, offset); 78 | }; 79 | 80 | /** 81 | * Turns a `wchar_t *` Buffer instance into a JavaScript String instance. 82 | * 83 | * @param {Buffer} buffer - buffer instance to serialize 84 | * @public 85 | */ 86 | 87 | exports.toString = function toString (buffer) { 88 | return getter.convert(buffer).toString('utf8'); 89 | }; 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ref-wchar 2 | ========== 3 | ### A ref "type" implementation of `wchar_t *` (a.k.a. wide string) backed by "node-iconv" 4 | [![Build Status](https://secure.travis-ci.org/TooTallNate/ref-wchar.svg)](https://travis-ci.org/TooTallNate/ref-wchar) 5 | [![Build Status](https://ci.appveyor.com/api/projects/status/xmne006y9jma3pm0?svg=true)](https://ci.appveyor.com/project/TooTallNate/ref-wchar) 6 | 7 | This module offers a ["wide 8 | strings"](http://en.wikipedia.org/wiki/Wide_character#C.2FC.2B.2B) (`wchar_t *`) 9 | implementation on top of Node.js Buffers using the ref "type" interface. 10 | 11 | 12 | Installation 13 | ------------ 14 | 15 | Install with `npm`: 16 | 17 | ``` bash 18 | $ npm install ref-wchar 19 | ``` 20 | 21 | 22 | Examples 23 | -------- 24 | 25 | Say you have a C library that exports a `wchar_t` char and a `wchar_t *` wide 26 | string: 27 | 28 | ``` c 29 | #if defined(WIN32) || defined(_WIN32) 30 | #define EXPORT __declspec(dllexport) 31 | #else 32 | #define EXPORT 33 | #endif 34 | 35 | EXPORT whcar_t w = L'W'; 36 | 37 | EXPORT wchar_t s[] = L"hello world"; 38 | 39 | EXPORT wchar_t **str = (wchar_t **)(&s); 40 | ``` 41 | 42 | ``` js 43 | var ref = require('ref'); 44 | var dlfcn = require('dlfcn'); 45 | var wchar_t = require('ref-wchar'); 46 | var wchar_string = wchar_t.string; 47 | 48 | var lib = dlfcn('./libexample'); 49 | 50 | // get the "w" symbol as a wchar 51 | var w = lib.get('w', wchar_t.size); 52 | ref.get(w, wchar_t); 53 | // "W" 54 | 55 | // get the "s" symbol as a wide string 56 | var s = ref.reinterpretUntilZeros(lib.get('s'), wchar_t.size); 57 | wchar_t.toString(s); 58 | // "hello world" 59 | 60 | // get the "str" pointer symbol as a wide string 61 | var str = lib.get('str', wchar_string.size); 62 | ref.get(str, wchar_string); 63 | // "hello world" 64 | ``` 65 | 66 | 67 | License 68 | ------- 69 | 70 | (The MIT License) 71 | 72 | Copyright (c) 2014 Nathan Rajlich <nathan@tootallnate.net> 73 | 74 | Permission is hereby granted, free of charge, to any person obtaining 75 | a copy of this software and associated documentation files (the 76 | 'Software'), to deal in the Software without restriction, including 77 | without limitation the rights to use, copy, modify, merge, publish, 78 | distribute, sublicense, and/or sell copies of the Software, and to 79 | permit persons to whom the Software is furnished to do so, subject to 80 | the following conditions: 81 | 82 | The above copyright notice and this permission notice shall be 83 | included in all copies or substantial portions of the Software. 84 | 85 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 88 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 89 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 90 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 91 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 92 | --------------------------------------------------------------------------------