22// Globals
33//========================================================================================
44var vm = require ( "vm" ) ;
5+ const SmartBuffer = require ( "smart-buffer" ) . SmartBuffer ;
6+ global . SmartBuffer = SmartBuffer ;
57
68var Context = require ( "./context" ) . Context ;
79
@@ -70,8 +72,10 @@ var Parser = function(opts) {
7072 this . endian = "be" ;
7173 this . constructorFn = null ;
7274 this . alias = null ;
73- this . bufferSize =
74- opts && typeof opts === "object" && opts . bufferSize ? opts . bufferSize : 256 ;
75+ this . smartBufferSize =
76+ opts && typeof opts === "object" && opts . smartBufferSize
77+ ? opts . smartBufferSize
78+ : 256 ;
7579} ;
7680
7781//----------------------------------------------------------------------------------------
@@ -310,14 +314,16 @@ Parser.prototype.addRawCode = function(ctx) {
310314
311315Parser . prototype . addRawCodeEncode = function ( ctx ) {
312316 ctx . pushCode ( "var vars = obj;" ) ;
313- ctx . pushCode ( "var offset = 0, maxOffset = {0};" , this . bufferSize ) ;
314- ctx . pushCode ( "var buffer = Buffer.alloc(maxOffset);" ) ; //TODO See how to dynamically alloc encode buffer
317+ ctx . pushCode (
318+ "var smartBuffer = SmartBuffer.fromOptions({size: {0}, encoding: 'utf8'});" ,
319+ this . smartBufferSize
320+ ) ;
315321
316322 this . generateEncode ( ctx ) ;
317323
318324 this . resolveReferences ( ctx , "encode" ) ;
319325
320- ctx . pushCode ( "return buffer.slice(0, offset );" ) ;
326+ ctx . pushCode ( "return smartBuffer.toBuffer( );" ) ;
321327} ;
322328
323329Parser . prototype . addAliasedCode = function ( ctx ) {
@@ -344,15 +350,17 @@ Parser.prototype.addAliasedCodeEncode = function(ctx) {
344350 ctx . pushCode ( "function {0}(obj) {" , FUNCTION_ENCODE_PREFIX + this . alias ) ;
345351
346352 ctx . pushCode ( "var vars = obj;" ) ;
347- ctx . pushCode ( "var offset = 0, maxOffset = {0};" , this . bufferSize ) ;
348- ctx . pushCode ( "var buffer = Buffer.alloc(maxOffset);" ) ; //TODO See how to dynamically alloc encode buffer
353+ ctx . pushCode (
354+ "var smartBuffer = SmartBuffer.fromOptions({size: {0}, encoding: 'utf8'});" ,
355+ this . smartBufferSize
356+ ) ;
349357
350358 this . generateEncode ( ctx ) ;
351359
352360 ctx . markResolved ( this . alias ) ;
353361 this . resolveReferences ( ctx , "encode" ) ;
354362
355- ctx . pushCode ( "return buffer.slice(0, offset );" ) ;
363+ ctx . pushCode ( "return smartBuffer.toBuffer( );" ) ;
356364 ctx . pushCode ( "}" ) ;
357365
358366 return ctx ;
@@ -377,7 +385,7 @@ Parser.prototype.compile = function() {
377385} ;
378386
379387Parser . prototype . compileEncode = function ( ) {
380- var src = "(function(obj, buffer ) { " + this . getCodeEncode ( ) + " })" ;
388+ var src = "(function(obj) { " + this . getCodeEncode ( ) + " })" ;
381389 this . compiledEncode = vm . runInThisContext ( src ) ;
382390} ;
383391
@@ -439,12 +447,12 @@ Parser.prototype.parse = function(buffer) {
439447} ;
440448
441449// Follow the parser chain till the root and start encoding from there
442- Parser . prototype . encode = function ( obj , buffer ) {
450+ Parser . prototype . encode = function ( obj ) {
443451 if ( ! this . compiledEncode ) {
444452 this . compileEncode ( ) ;
445453 }
446454
447- return this . compiledEncode ( obj , buffer ) ;
455+ return this . compiledEncode ( obj ) ;
448456} ;
449457
450458//----------------------------------------------------------------------------------------
@@ -557,8 +565,7 @@ Object.keys(PRIMITIVE_TYPES).forEach(function(type) {
557565 } ;
558566 Parser . prototype [ "generate_encode" + type ] = function ( ctx ) {
559567 ctx . pushCode (
560- "if (offset + {0} <= maxOffset) offset = buffer.write{1}({2}, offset);" ,
561- PRIMITIVE_TYPES [ type ] ,
568+ "smartBuffer.write{0}({1});" ,
562569 type ,
563570 ctx . generateVariable ( this . varName )
564571 ) ;
@@ -664,11 +671,20 @@ Parser.prototype.generate_encodeBit = function(ctx) {
664671 ctx . pushCode ( "{0} = {0} >>> 0;" , tmpVal ) ;
665672 bitOffset += parser . options . length ;
666673 } ) ;
667- ctx . pushCode (
668- "if (offset + {1} <= maxOffset) offset = buffer.writeUIntBE({0}, offset, {1});" ,
669- tmpVal ,
670- sum / 8
671- ) ;
674+ if ( sum == 8 ) {
675+ ctx . pushCode ( "smartBuffer.writeUInt8({0});" , tmpVal ) ;
676+ } else if ( sum == 16 ) {
677+ ctx . pushCode ( "smartBuffer.writeUInt16BE({0});" , tmpVal ) ;
678+ } else if ( sum == 24 ) {
679+ var val1 = ctx . generateTmpVariable ( ) ;
680+ var val2 = ctx . generateTmpVariable ( ) ;
681+ ctx . pushCode ( "var {0} = ({1} >>> 8);" , val1 , tmpVal ) ;
682+ ctx . pushCode ( "var {0} = ({1} & 0x0ff);" , val2 , tmpVal ) ;
683+ ctx . pushCode ( "smartBuffer.writeUInt16BE({0});" , val1 ) ;
684+ ctx . pushCode ( "smartBuffer.writeUInt8({0});" , val2 ) ;
685+ } else if ( sum == 32 ) {
686+ ctx . pushCode ( "smartBuffer.writeUInt32BE({0});" , tmpVal ) ;
687+ }
672688
673689 ctx . bitFields = [ ] ;
674690 }
@@ -681,7 +697,8 @@ Parser.prototype.generateSkip = function(ctx) {
681697
682698Parser . prototype . generate_encodeSkip = function ( ctx ) {
683699 var length = ctx . generateOption ( this . options . length ) ;
684- ctx . pushCode ( "offset += {0};" , length ) ;
700+ ctx . pushCode ( "smartBuffer._ensureWriteable({0});" , length ) ;
701+ ctx . pushCode ( "smartBuffer.writeOffset += {0};" , length ) ;
685702} ;
686703
687704Parser . prototype . generateString = function ( ctx ) {
@@ -740,21 +757,36 @@ Parser.prototype.generate_encodeString = function(ctx) {
740757
741758 // Get the length of string to encode
742759 if ( this . options . length ) {
760+ var optLength = ctx . generateOption ( this . options . length ) ;
761+ // Encode the string to a temporary buffer
762+ var tmpBuf = ctx . generateTmpVariable ( ) ;
743763 ctx . pushCode (
744- "offset += buffer.write({0}, offset, {1}, '{2}');" ,
764+ "var {0} = Buffer.from({1}, '{2}');" ,
765+ tmpBuf ,
745766 name ,
746- ctx . generateOption ( this . options . length ) ,
747767 this . options . encoding
748768 ) ;
769+ // Truncate the buffer to specified (Bytes) length
770+ ctx . pushCode ( "{0} = {0}.slice(0, {1});" , tmpBuf , optLength ) ;
771+ // Compute padding length
772+ var padLen = ctx . generateTmpVariable ( ) ;
773+ ctx . pushCode ( "{0} = {1} - {2}.length;" , padLen , optLength , tmpBuf ) ;
774+ // Copy the temporary string buffer to current smartBuffer
775+ ctx . pushCode ( "smartBuffer.writeBuffer({0});" , tmpBuf ) ;
776+ // Add padding spaces
777+ ctx . pushCode (
778+ "if ({0} > 0) {smartBuffer.writeString(' '.repeat({0}));}" ,
779+ padLen
780+ ) ;
749781 } else {
750782 ctx . pushCode (
751- "offset += buffer.write ({0}, offset , '{1}');" ,
783+ "smartBuffer.writeString ({0}, '{1}');" ,
752784 name ,
753785 this . options . encoding
754786 ) ;
755787 }
756788 if ( this . options . zeroTerminated ) {
757- ctx . pushCode ( "offset = buffer .writeUInt8(0x00, offset );" ) ;
789+ ctx . pushCode ( "smartBuffer .writeUInt8(0x00);" ) ;
758790 }
759791} ;
760792
@@ -780,7 +812,7 @@ Parser.prototype.generateBuffer = function(ctx) {
780812
781813Parser . prototype . generate_encodeBuffer = function ( ctx ) {
782814 ctx . pushCode (
783- "offset += {0}.copy(buffer, offset );" ,
815+ "smartBuffer.writeBuffer( {0});" ,
784816 ctx . generateVariable ( this . varName )
785817 ) ;
786818} ;
@@ -864,11 +896,7 @@ Parser.prototype.generate_encodeArray = function(ctx) {
864896 ctx . generateError ( '"Encoding associative array not supported"' ) ;
865897 }
866898
867- if ( lengthInBytes !== undefined ) {
868- ctx . pushCode ( "var {0} = offset + {1};" , maxOffset , lengthInBytes ) ;
869- } else {
870- ctx . pushCode ( "var {0} = Number.MAX_SAFE_INTEGER;" , maxOffset ) ;
871- }
899+ // Compute the desired count of array items to encode (min of array size and length option)
872900 if ( length !== undefined ) {
873901 var tmpLength = ctx . generateTmpVariable ( ) ;
874902 ctx . pushCode ( "var {0} = {1};" , tmpLength , length ) ;
@@ -882,8 +910,15 @@ Parser.prototype.generate_encodeArray = function(ctx) {
882910 ctx . pushCode ( "var {0} = {1}.length;" , maxItems , name ) ;
883911 }
884912
885- ctx . pushCode ( "var {0} = 0;" , itemCounter ) ;
913+ // Save current encoding smartBuffer and allocate a new one
914+ var savSmartBuffer = ctx . generateTmpVariable ( ) ;
915+ ctx . pushCode (
916+ "var {0} = smartBuffer; smartBuffer = SmartBuffer.fromOptions({size: {1}, encoding: 'utf8'});" ,
917+ savSmartBuffer ,
918+ this . smartBufferSize
919+ ) ;
886920
921+ ctx . pushCode ( "var {0} = 0;" , itemCounter ) ;
887922 if ( typeof this . options . readUntil === "function" ) {
888923 ctx . pushCode ( "do {" ) ;
889924 } else {
@@ -895,74 +930,44 @@ Parser.prototype.generate_encodeArray = function(ctx) {
895930
896931 if ( typeof type === "string" ) {
897932 if ( ! aliasRegistry [ type ] ) {
898- ctx . pushCode (
899- "if (offset + {0} > {1} || offset + {0} > maxOffset) break;" ,
900- PRIMITIVE_TYPES [ NAME_MAP [ type ] ] ,
901- maxOffset
902- ) ;
903- ctx . pushCode (
904- "offset = buffer.write{0}({1}, offset);" ,
905- NAME_MAP [ type ] ,
906- item
907- ) ;
933+ ctx . pushCode ( "smartBuffer.write{0}({1});" , NAME_MAP [ type ] , item ) ;
908934 } else {
909- var tempVar = ctx . generateTmpVariable ( ) ;
910935 ctx . pushCode (
911- "var {0} = {1}({2});" ,
912- tempVar ,
936+ "smartBuffer.writeBuffer({0}({1}));" ,
913937 FUNCTION_ENCODE_PREFIX + type ,
914938 item
915939 ) ;
916- ctx . pushCode (
917- "if (offset + {0}.length > {1} || offset + {0}.length > maxOffset) break;" ,
918- tempVar ,
919- maxOffset
920- ) ;
921- ctx . pushCode ( "offset += {0}.copy(buffer, offset);" , tempVar ) ;
922- if ( type !== this . alias ) ctx . addReference ( type ) ;
940+ if ( type !== this . alias ) {
941+ ctx . addReference ( type ) ;
942+ }
923943 }
924944 } else if ( type instanceof Parser ) {
925- var savMaxOffset = ctx . generateTmpVariable ( ) ;
926- var savBuffer = ctx . generateTmpVariable ( ) ;
927- var savOffset = ctx . generateTmpVariable ( ) ;
928- ctx . pushCode (
929- "var {0} = maxOffset; maxOffset = {1};" ,
930- savMaxOffset ,
931- maxOffset
932- ) ;
933- ctx . pushCode (
934- "var {0} = buffer; buffer = Buffer.alloc({1});" ,
935- savBuffer ,
936- this . bufferSize
937- ) ;
938- ctx . pushCode ( "var {0} = offset; offset = 0;" , savOffset ) ;
939945 ctx . pushScope ( item ) ;
940946 type . generateEncode ( ctx ) ;
941947 ctx . popScope ( ) ;
942- ctx . pushCode (
943- "if ({1} + offset <= {0}) {1} += buffer.copy({2}, {3}, 0, offset);" ,
944- maxOffset ,
945- savOffset ,
946- savBuffer ,
947- savOffset
948- ) ;
949- ctx . pushCode (
950- "maxOffset = {0}; buffer = {1}; offset = {2};" ,
951- savMaxOffset ,
952- savBuffer ,
953- savOffset
954- ) ;
955948 }
956949
957950 ctx . pushCode ( "}" ) ; // End of 'do {' or 'for(...) {'
958951
959952 if ( typeof this . options . readUntil === "function" ) {
960953 ctx . pushCode (
961- " while (!({0}).call(this, {1}, buffer.slice(offset )));" ,
954+ " while (!({0}).call(this, {1}, {2}.toBuffer( )));" ,
962955 this . options . readUntil ,
963- item
956+ item ,
957+ savSmartBuffer
964958 ) ;
965959 }
960+
961+ var tmpBuffer = ctx . generateTmpVariable ( ) ;
962+ ctx . pushCode ( "var {0} = smartBuffer.toBuffer()" , tmpBuffer ) ;
963+ if ( lengthInBytes !== undefined ) {
964+ // Truncate the tmpBuffer so that it will respect the lengthInBytes option
965+ ctx . pushCode ( "{0} = {0}.slice(0, {1});" , tmpBuffer , lengthInBytes ) ;
966+ }
967+ // Copy tmp Buffer to saved smartBuffer
968+ ctx . pushCode ( "{0}.writeBuffer({1});" , savSmartBuffer , tmpBuffer ) ;
969+ // Restore current smartBuffer
970+ ctx . pushCode ( "smartBuffer = {0};" , savSmartBuffer ) ;
966971} ;
967972
968973Parser . prototype . generateChoiceCase = function ( ctx , varName , type ) {
@@ -995,7 +1000,7 @@ Parser.prototype.generate_encodeChoiceCase = function(ctx, varName, type) {
9951000 if ( typeof type === "string" ) {
9961001 if ( ! aliasRegistry [ type ] ) {
9971002 ctx . pushCode (
998- "offset = buffer .write{0}({1}, offset );" ,
1003+ "smartBuffer .write{0}({1});" ,
9991004 NAME_MAP [ type ] ,
10001005 ctx . generateVariable ( this . varName )
10011006 ) ;
@@ -1007,7 +1012,7 @@ Parser.prototype.generate_encodeChoiceCase = function(ctx, varName, type) {
10071012 FUNCTION_ENCODE_PREFIX + type ,
10081013 ctx . generateVariable ( this . varName )
10091014 ) ;
1010- ctx . pushCode ( "offset += {0}.copy(buffer, offset );" , tempVar ) ;
1015+ ctx . pushCode ( "smartBuffer.writeBuffer( {0});" , tempVar ) ;
10111016 if ( type !== this . alias ) ctx . addReference ( type ) ;
10121017 }
10131018 } else if ( type instanceof Parser ) {
@@ -1099,7 +1104,7 @@ Parser.prototype.generate_encodeNest = function(ctx) {
10991104 FUNCTION_ENCODE_PREFIX + this . options . type ,
11001105 nestVar
11011106 ) ;
1102- ctx . pushCode ( "offset += {0}.copy(buffer, offset );" , tempVar ) ;
1107+ ctx . pushCode ( "smartBuffer.writeBuffer( {0});" , tempVar ) ;
11031108 if ( this . options . type !== this . alias ) ctx . addReference ( this . options . type ) ;
11041109 }
11051110} ;
0 commit comments