├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── bufferpack.js ├── package.json └── test ├── cstring.test.js └── keys.test.js /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | node_modules/ 3 | *~ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | 2 | .gitignore 3 | *.md 4 | test/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008, Fair Oaks Labs, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are 5 | permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this list 8 | of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or other 12 | materials provided with the distribution. 13 | 14 | * Neither the name of Fair Oaks Labs, Inc. nor the names of its contributors may be 15 | used to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 19 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 20 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 | THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 26 | THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | bufferpack - Module to pack primitives and C strings to buffers 2 | ==================================================== 3 | ## Disclaimer 4 | 5 | The jspack module and documentation are essentially ports of the 6 | Python struct module and documentation, with such changes as were necessary. The port 7 | was originaly made by Fair Oaks Labs, Inc. and published at http://code.google.com/p/jspack/ 8 | If any Python people are miffed that their documentation got ripped off, let me know, 9 | and I'll gladly revise them. The original port to Node.js was done by pgriess. This 10 | is a fork of node-jspack (https://github.com/pgriess/node-jspack && https://github.com/birchroad/node-jspack). 11 | 12 | This module performs conversions between JavaScript values and C structs 13 | represented as octet arrays (i.e. JavaScript arrays of integral numbers 14 | between 0 and 255, inclusive). It uses format strings (explained below) as 15 | compact descriptions of the layout of the C structs and the intended conversion 16 | to/from JavaScript values. This can be used to handle binary data stored in 17 | files, or received from network connections or other sources. 18 | 19 | ## Install 20 | 21 | npm install bufferpack 22 | 23 | ## Reference 24 | 25 | The module defines the following functions: 26 | 27 | ### unpack(format, buffer, position) 28 | 29 | Return an array or object containing values unpacked from the octet array a, 30 | beginning at position p, according to the supplied format string. If there 31 | are more octets in a than required by the format string, the excess is 32 | ignored. If there are fewer octets than required, unpack() will return 33 | undefined. If no value is supplied for the p argument, zero is assumed. By default 34 | an array of values is returned. However, if all format characters are assigned 35 | a name/key an object containing all key/value pairs will returned. 36 | 37 | ### packTo(format, buffer, position, values) 38 | 39 | Pack and store the values array into the supplied octet array a, beginning 40 | at position p. If there are more values supplied than are specified in the 41 | format string, the excess is ignored. If there are fewer values supplied, 42 | packTo() will return false. If there is insufficient space in a to store 43 | the packed values, packTo() will return false. On success, packTo() returns 44 | the a argument. If any value is of an inappropriate type, the results are 45 | undefined. 46 | 47 | ### pack(format, values) 48 | 49 | Return an octet array containing the packed values array. If there are 50 | more values supplied than are specified in the format string, the excess is 51 | ignored. If there are fewer values supplied, pack() will return false. If 52 | any value is of an inappropriate type, the results are undefined. 53 | 54 | ### calcLength(format, values) 55 | 56 | Return the number of octets required to store the given format string. 57 | 58 | ## Formats 59 | 60 | Format characters have the following meanings; the conversion between C and 61 | JavaScript values should be obvious given their types: 62 | 63 | Format | C Type | JavaScript Type | Size (octets) | Notes 64 | ------------------------------------------------------------------- 65 | A | char[] | Array | Length | (1) 66 | x | pad byte | N/A | 1 | 67 | c | char | string (length 1) | 1 | (2) 68 | b | signed char | number | 1 | (3) 69 | B | unsigned char | number | 1 | (3) 70 | h | signed short | number | 2 | (3) 71 | H | unsigned short | number | 2 | (3) 72 | i | signed long | number | 4 | (3) 73 | I | unsigned long | number | 4 | (3) 74 | l | signed long | number | 4 | (3) 75 | L | unsigned long | number | 4 | (3) 76 | S | C string | string | * | (6) 77 | s | char[] | string | Length | (2) 78 | f | float | number | 4 | (4) 79 | d | double | number | 8 | (5) 80 | 81 | Notes: 82 | 83 | (1) The "A" code simply returns a slice of the source octet array. This is 84 | primarily useful when a data structure contains bytes which are subject to 85 | multiple intepretations (e.g. unions), and the data structure is being 86 | decoded in multiple passes. 87 | 88 | (2) The "c" and "s" codes handle strings with codepoints between 0 and 255, 89 | inclusive. The data are not bounds-checked, so strings containing characters 90 | with codepoints outside this range will encode to "octet" arrays that contain 91 | values outside the range of an octet. Furthermore, since these codes decode 92 | octet arrays by assuming the octets represent UNICODE codepoints, they may 93 | not "correctly" decode bytes in the range 128-255, since that range is subject 94 | to multiple interpretations. Caveat coder! 95 | 96 | (3) The 8 "integer" codes clip their encoded values to the minima and maxmima 97 | of their respective types: If you invoke Struct.pack('b', [-129]), for 98 | instance, the result will be [128], which is the octet encoding of -128, 99 | which is the minima of a signed char. Similarly, Struct.pack('h', [-32769]) 100 | returns [128, 0]. Fractions are truncated. 101 | 102 | (4) Since JavaScript doesn't natively support 32-bit floats, whenever a float 103 | is stored, the source JavaScript number must be rounded. This module applies 104 | correct rounding during this process. Numbers with magnitude greater than or 105 | equal to 2^128-2^103 round to either positive or negative Infinity. The 106 | rounding algorithm assumes that JavsScript is using exactly 64 bits of 107 | floating point precision; 128-bit floating point will result in subtle errors. 108 | 109 | (5) This module assumes that JavaScript is using 64 bits of floating point 110 | precision, so the "d" code performs no rounding. 128-bit floating point will 111 | cause the "d" code to simply truncate significands to 52 bits. 112 | 113 | (6) Same handling as (2), but with varible length. Length of c strings is 114 | variable, C strings are length + 1 (null byte). 115 | 116 | 117 | A format character may be preceded by an integral repeat count. For example, 118 | the format string "4h" means exactly the same thing as "hhhh". 119 | 120 | Whitespace characters between formats are ignored; a count and its format must 121 | not be separated by whitespace, however. 122 | 123 | For the "A" format character, the count is interpreted as the size of the 124 | array, not a repeat count as for the other format characters; for example, "10A" 125 | means a single 10-octet array. When packing, the Array is truncated or padded 126 | with 0 bytes as appropriate to make it conform to the specified length. When 127 | unpacking, the resulting Array always has exactly the specified number of bytes. 128 | As a special case, "0A" means a single, empty Array. 129 | 130 | For the "s" format character, the count is interpreted as the size of the 131 | string, not a repeat count as for the other format characters; for example, 132 | "10s" means a single 10-byte string, while "10c" means 10 characters. When 133 | packing, the string is truncated or padded with 0 bytes as appropriate to make 134 | it conform to the specified length. When unpacking, the resulting string always 135 | has exactly the specified number of bytes. As a special case, "0s" means a 136 | single, empty string (while "0c" means 0 characters). If variable length strings 137 | required use the "S" format character, values decoded/encoded this way must be null 138 | terminated. 139 | 140 | A name/key can be assigned to each format character using "(name)". For unpack to 141 | use names each format character in the format string must be assigned a name. 142 | Example: "S(firstName)S(lastName)B(age)". This would result in unpack returning 143 | {"firstName": "Ryan", "lastName": "Olds", "age": 28} 144 | 145 | By default, C numbers are represented in network (or big-endian) byte order. 146 | Alternatively, the first character of the format string can be used to indicate 147 | byte order of the packed data, according to the following table: 148 | 149 | Character | Byte Order 150 | ---------------------------------- 151 | < | little-endian 152 | > | big-endian 153 | ! | network (= big-endian) 154 | 155 | If the first character is not one of these, "!" is assumed. 156 | 157 | ## Running Tests 158 | 159 | To run the test suite first invoke the following command within the repo, installing the development dependencies: 160 | 161 | $ npm install 162 | 163 | then run the tests: 164 | 165 | $ npm test -------------------------------------------------------------------------------- /bufferpack.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright 2008 Fair Oaks Labs, Inc. 3 | * All rights reserved. 4 | */ 5 | 6 | // Utility object: Encode/Decode C-style binary primitives to/from octet arrays 7 | function BufferPack() { 8 | // Module-level (private) variables 9 | var el, bBE = false, m = this; 10 | 11 | // Raw byte arrays 12 | m._DeArray = function (a, p, l) { 13 | return [a.slice(p,p+l)]; 14 | }; 15 | m._EnArray = function (a, p, l, v) { 16 | for (var i = 0; i < l; a[p+i] = v[i]?v[i]:0, i++); 17 | }; 18 | 19 | // ASCII characters 20 | m._DeChar = function (a, p) { 21 | return String.fromCharCode(a[p]); 22 | }; 23 | m._EnChar = function (a, p, v) { 24 | a[p] = v.charCodeAt(0); 25 | }; 26 | 27 | // Little-endian (un)signed N-byte integers 28 | m._DeInt = function (a, p) { 29 | var lsb = bBE?(el.len-1):0, nsb = bBE?-1:1, stop = lsb+nsb*el.len, rv, i, f; 30 | for (rv = 0, i = lsb, f = 1; i != stop; rv+=(a[p+i]*f), i+=nsb, f*=256); 31 | if (el.bSigned && (rv & Math.pow(2, el.len*8-1))) { 32 | rv -= Math.pow(2, el.len*8); 33 | } 34 | return rv; 35 | }; 36 | m._EnInt = function (a, p, v) { 37 | var lsb = bBE?(el.len-1):0, nsb = bBE?-1:1, stop = lsb+nsb*el.len, i; 38 | v = (vel.max)?el.max:v; 39 | for (i = lsb; i != stop; a[p+i]=v&0xff, i+=nsb, v>>=8); 40 | }; 41 | 42 | // ASCII character strings 43 | m._DeString = function (a, p, l) { 44 | for (var rv = new Array(l), i = 0; i < l; rv[i] = String.fromCharCode(a[p+i]), i++); 45 | return rv.join(''); 46 | }; 47 | m._EnString = function (a, p, l, v) { 48 | for (var t, i = 0; i < l; a[p+i] = (t=v.charCodeAt(i))?t:0, i++); 49 | }; 50 | 51 | // ASCII character strings null terminated 52 | m._DeNullString = function (a, p, l, v) { 53 | var str = m._DeString(a, p, l, v); 54 | return str.substring(0, str.length - 1); 55 | }; 56 | 57 | // Little-endian N-bit IEEE 754 floating point 58 | m._De754 = function (a, p) { 59 | var s, e, m, i, d, nBits, mLen, eLen, eBias, eMax; 60 | mLen = el.mLen, eLen = el.len*8-el.mLen-1, eMax = (1<>1; 61 | 62 | i = bBE?0:(el.len-1); d = bBE?1:-1; s = a[p+i]; i+=d; nBits = -7; 63 | for (e = s&((1<<(-nBits))-1), s>>=(-nBits), nBits += eLen; nBits > 0; e=e*256+a[p+i], i+=d, nBits-=8); 64 | for (m = e&((1<<(-nBits))-1), e>>=(-nBits), nBits += mLen; nBits > 0; m=m*256+a[p+i], i+=d, nBits-=8); 65 | 66 | switch (e) { 67 | case 0: 68 | // Zero, or denormalized number 69 | e = 1-eBias; 70 | break; 71 | case eMax: 72 | // NaN, or +/-Infinity 73 | return m?NaN:((s?-1:1)*Infinity); 74 | default: 75 | // Normalized number 76 | m = m + Math.pow(2, mLen); 77 | e = e - eBias; 78 | break; 79 | } 80 | return (s?-1:1) * m * Math.pow(2, e-mLen); 81 | }; 82 | m._En754 = function (a, p, v) { 83 | var s, e, m, i, d, c, mLen, eLen, eBias, eMax; 84 | mLen = el.mLen, eLen = el.len*8-el.mLen-1, eMax = (1<>1; 85 | 86 | s = v<0?1:0; 87 | v = Math.abs(v); 88 | if (isNaN(v) || (v == Infinity)) { 89 | m = isNaN(v)?1:0; 90 | e = eMax; 91 | } else { 92 | e = Math.floor(Math.log(v)/Math.LN2); // Calculate log2 of the value 93 | 94 | if (v*(c = Math.pow(2, -e)) < 1) { 95 | e--; c*=2; // Math.log() isn't 100% reliable 96 | } 97 | 98 | // Round by adding 1/2 the significand's LSD 99 | if (e+eBias >= 1) { 100 | v += el.rt/c; // Normalized: mLen significand digits 101 | } else { 102 | v += el.rt*Math.pow(2, 1-eBias); // Denormalized: <= mLen significand digits 103 | } 104 | 105 | if (v*c >= 2) { 106 | e++; c/=2; // Rounding can increment the exponent 107 | } 108 | 109 | if (e+eBias >= eMax) { 110 | // Overflow 111 | m = 0; 112 | e = eMax; 113 | } else if (e+eBias >= 1) { 114 | // Normalized - term order matters, as Math.pow(2, 52-e) and v*Math.pow(2, 52) can overflow 115 | m = (v*c-1)*Math.pow(2, mLen); 116 | e = e + eBias; 117 | } else { 118 | // Denormalized - also catches the '0' case, somewhat by chance 119 | m = v*Math.pow(2, eBias-1)*Math.pow(2, mLen); 120 | e = 0; 121 | } 122 | } 123 | 124 | for (i = bBE?(el.len-1):0, d=bBE?-1:1; mLen >= 8; a[p+i]=m&0xff, i+=d, m/=256, mLen-=8); 125 | for (e=(e< 0; a[p+i]=e&0xff, i+=d, e/=256, eLen-=8); 126 | a[p+i-d] |= s*128; 127 | }; 128 | 129 | // Class data 130 | m._sPattern = '(\\d+)?([AxcbBhHsSfdiIlL])(\\(([a-zA-Z0-9]+)\\))?'; 131 | m._lenLut = {'A': 1, 'x': 1, 'c': 1, 'b': 1, 'B': 1, 'h': 2, 'H': 2, 's': 1, 132 | 'S': 1, 'f': 4, 'd': 8, 'i': 4, 'I': 4, 'l': 4, 'L': 4}; 133 | m._elLut = {'A': {en: m._EnArray, de: m._DeArray}, 134 | 's': {en: m._EnString, de: m._DeString}, 135 | 'S': {en: m._EnString, de: m._DeNullString}, 136 | 'c': {en: m._EnChar, de: m._DeChar}, 137 | 'b': {en: m._EnInt, de: m._DeInt, len: 1, bSigned: true, min: -Math.pow(2, 7), max: Math.pow(2, 7) - 1}, 138 | 'B': {en: m._EnInt, de: m._DeInt, len: 1, bSigned: false, min: 0, max: Math.pow(2, 8) - 1}, 139 | 'h': {en: m._EnInt, de: m._DeInt, len: 2, bSigned: true, min: -Math.pow(2, 15), max: Math.pow(2, 15) - 1}, 140 | 'H': {en: m._EnInt, de: m._DeInt, len: 2, bSigned: false, min: 0, max: Math.pow(2, 16) - 1}, 141 | 'i': {en: m._EnInt, de: m._DeInt, len: 4, bSigned: true, min: -Math.pow(2, 31), max: Math.pow(2, 31) - 1}, 142 | 'I': {en: m._EnInt, de: m._DeInt, len: 4, bSigned: false, min: 0, max: Math.pow(2, 32) - 1}, 143 | 'l': {en: m._EnInt, de: m._DeInt, len: 4, bSigned: true, min: -Math.pow(2, 31), max: Math.pow(2, 31) - 1}, 144 | 'L': {en: m._EnInt, de: m._DeInt, len: 4, bSigned: false, min: 0, max: Math.pow(2, 32) - 1}, 145 | 'f': {en: m._En754, de: m._De754, len: 4, mLen: 23, rt: Math.pow(2, -24) - Math.pow(2, -77)}, 146 | 'd': {en: m._En754, de: m._De754, len: 8, mLen: 52, rt: 0}}; 147 | 148 | // Unpack a series of n elements of size s from array a at offset p with fxn 149 | m._UnpackSeries = function (n, s, a, p) { 150 | for (var fxn = el.de, rv = [], i = 0; i < n; rv.push(fxn(a, p+i*s)), i++); 151 | return rv; 152 | }; 153 | 154 | // Pack a series of n elements of size s from array v at offset i to array a at offset p with fxn 155 | m._PackSeries = function (n, s, a, p, v, i) { 156 | for (var fxn = el.en, o = 0; o < n; fxn(a, p+o*s, v[i+o]), o++); 157 | }; 158 | 159 | m._zip = function (keys, values) { 160 | var result = {}; 161 | 162 | for (var i = 0; i < keys.length; i++) { 163 | result[keys[i]] = values[i]; 164 | } 165 | 166 | return result; 167 | } 168 | 169 | // Unpack the octet array a, beginning at offset p, according to the fmt string 170 | m.unpack = function (fmt, a, p) { 171 | // Set the private bBE flag based on the format string - assume big-endianness 172 | bBE = (fmt.charAt(0) != '<'); 173 | 174 | p = p?p:0; 175 | var re = new RegExp(this._sPattern, 'g'); 176 | var m; 177 | var n; 178 | var s; 179 | var rk = []; 180 | var rv = []; 181 | 182 | while (m = re.exec(fmt)) { 183 | n = ((m[1]==undefined)||(m[1]==''))?1:parseInt(m[1]); 184 | 185 | if(m[2] === 'S') { // Null term string support 186 | n = 0; // Need to deal with empty null term strings 187 | while(a[p + n] !== 0) { 188 | n++; 189 | } 190 | n++; // Add one for null byte 191 | } 192 | 193 | s = this._lenLut[m[2]]; 194 | 195 | if ((p + n*s) > a.length) { 196 | return undefined; 197 | } 198 | 199 | switch (m[2]) { 200 | case 'A': case 's': case 'S': 201 | rv.push(this._elLut[m[2]].de(a, p, n)); 202 | break; 203 | case 'c': case 'b': case 'B': case 'h': case 'H': 204 | case 'i': case 'I': case 'l': case 'L': case 'f': case 'd': 205 | el = this._elLut[m[2]]; 206 | rv.push(this._UnpackSeries(n, s, a, p)); 207 | break; 208 | } 209 | 210 | rk.push(m[4]); // Push key on to array 211 | 212 | p += n*s; 213 | } 214 | 215 | rv = Array.prototype.concat.apply([], rv) 216 | 217 | if(rk.indexOf(undefined) !== -1) { 218 | return rv; 219 | } else { 220 | return this._zip(rk, rv); 221 | } 222 | }; 223 | 224 | // Pack the supplied values into the octet array a, beginning at offset p, according to the fmt string 225 | m.packTo = function (fmt, a, p, values) { 226 | // Set the private bBE flag based on the format string - assume big-endianness 227 | bBE = (fmt.charAt(0) != '<'); 228 | 229 | var re = new RegExp(this._sPattern, 'g'); 230 | var m; 231 | var n; 232 | var s; 233 | var i = 0; 234 | var j; 235 | 236 | while (m = re.exec(fmt)) { 237 | n = ((m[1]==undefined)||(m[1]==''))?1:parseInt(m[1]); 238 | 239 | // Null term string support 240 | if(m[2] === 'S') { 241 | n = values[i].length + 1; // Add one for null byte 242 | } 243 | 244 | s = this._lenLut[m[2]]; 245 | 246 | if ((p + n*s) > a.length) { 247 | return false; 248 | } 249 | 250 | switch (m[2]) { 251 | case 'A': case 's': case 'S': 252 | if ((i + 1) > values.length) { return false; } 253 | this._elLut[m[2]].en(a, p, n, values[i]); 254 | i += 1; 255 | break; 256 | case 'c': case 'b': case 'B': case 'h': case 'H': 257 | case 'i': case 'I': case 'l': case 'L': case 'f': case 'd': 258 | el = this._elLut[m[2]]; 259 | if ((i + n) > values.length) { return false; } 260 | this._PackSeries(n, s, a, p, values, i); 261 | i += n; 262 | break; 263 | case 'x': 264 | for (j = 0; j < n; j++) { a[p+j] = 0; } 265 | break; 266 | } 267 | p += n*s; 268 | } 269 | 270 | return a; 271 | }; 272 | 273 | // Pack the supplied values into a new octet array, according to the fmt string 274 | m.pack = function (fmt, values) { 275 | return this.packTo(fmt, new Buffer(this.calcLength(fmt, values)), 0, values); 276 | }; 277 | 278 | // Determine the number of bytes represented by the format string 279 | m.calcLength = function (format, values) { 280 | var re = new RegExp(this._sPattern, 'g'), m, sum = 0, i = 0; 281 | while (m = re.exec(format)) { 282 | var n = (((m[1]==undefined)||(m[1]==''))?1:parseInt(m[1])) * this._lenLut[m[2]]; 283 | 284 | if(m[2] === 'S') { 285 | n = values[i].length + 1; // Add one for null byte 286 | } 287 | 288 | sum += n; 289 | if(m[2] !== 'x') { 290 | i++; 291 | } 292 | } 293 | return sum; 294 | }; 295 | }; 296 | 297 | module.exports = new BufferPack(); 298 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bufferpack", 3 | "description": "Module to pack/unpack primitives and c strings into/out of a Node.js buffer", 4 | "version": "0.0.5", 5 | "keywords": ["jspack", "buffer", "octet", "primitive", "string"], 6 | "homepage": "https://github.com/ryanrolds/bufferpack", 7 | "repository": { 8 | "type": "git", 9 | "url": "git://github.com/ryanrolds/bufferpack.git" 10 | }, 11 | "main": "./bufferpack.js", 12 | "author": "Ryan Olds ", 13 | "maintainers": [ 14 | { 15 | "name": "Peter Griess", 16 | "web": "https://github.com/pgriess" 17 | }, 18 | { 19 | "name": "Peter Magnusson", 20 | "email": "peter@birchroad.net", 21 | "web": "http://github.com/birchroad/node-jspack" 22 | }, 23 | { 24 | "name": "Ryan Olds", 25 | "email": "ryanrolds@gmail.com", 26 | "web": "https://github.com/ryanrolds" 27 | } 28 | ], 29 | "devDependencies": { 30 | "mocha": "1.x", 31 | "should": "3.x" 32 | }, 33 | "scripts": { 34 | "test": "./node_modules/.bin/mocha test/*.test.js --reporter spec" 35 | } 36 | } -------------------------------------------------------------------------------- /test/cstring.test.js: -------------------------------------------------------------------------------- 1 | 2 | require('should'); 3 | var buffer = require('buffer'); 4 | 5 | var bufferpack = require('..'); 6 | 7 | describe('C String', function() { 8 | var values = [1, 2, 3, 'test', 5, 6, 7]; 9 | var format = '