bytebuffer-node.js 140 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454
  1. /*
  2. Copyright 2013-2014 Daniel Wirtz <dcode@dcode.io>
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. /**
  14. * @license bytebuffer.js (c) 2015 Daniel Wirtz <dcode@dcode.io>
  15. * Backing buffer / Accessor: node Buffer
  16. * Released under the Apache License, Version 2.0
  17. * see: https://github.com/dcodeIO/bytebuffer.js for details
  18. */
  19. module.exports = (function() {
  20. "use strict";
  21. var buffer = require("buffer"),
  22. Buffer = buffer["Buffer"],
  23. Long = require("long"),
  24. memcpy = null; try { memcpy = require("memcpy"); } catch (e) {}
  25. /**
  26. * Constructs a new ByteBuffer.
  27. * @class The swiss army knife for binary data in JavaScript.
  28. * @exports ByteBuffer
  29. * @constructor
  30. * @param {number=} capacity Initial capacity. Defaults to {@link ByteBuffer.DEFAULT_CAPACITY}.
  31. * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
  32. * {@link ByteBuffer.DEFAULT_ENDIAN}.
  33. * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to
  34. * {@link ByteBuffer.DEFAULT_NOASSERT}.
  35. * @expose
  36. */
  37. var ByteBuffer = function(capacity, littleEndian, noAssert) {
  38. if (typeof capacity === 'undefined')
  39. capacity = ByteBuffer.DEFAULT_CAPACITY;
  40. if (typeof littleEndian === 'undefined')
  41. littleEndian = ByteBuffer.DEFAULT_ENDIAN;
  42. if (typeof noAssert === 'undefined')
  43. noAssert = ByteBuffer.DEFAULT_NOASSERT;
  44. if (!noAssert) {
  45. capacity = capacity | 0;
  46. if (capacity < 0)
  47. throw RangeError("Illegal capacity");
  48. littleEndian = !!littleEndian;
  49. noAssert = !!noAssert;
  50. }
  51. /**
  52. * Backing node Buffer.
  53. * @type {!Buffer}
  54. * @expose
  55. */
  56. this.buffer = capacity === 0 ? EMPTY_BUFFER : new Buffer(capacity);
  57. /**
  58. * Absolute read/write offset.
  59. * @type {number}
  60. * @expose
  61. * @see ByteBuffer#flip
  62. * @see ByteBuffer#clear
  63. */
  64. this.offset = 0;
  65. /**
  66. * Marked offset.
  67. * @type {number}
  68. * @expose
  69. * @see ByteBuffer#mark
  70. * @see ByteBuffer#reset
  71. */
  72. this.markedOffset = -1;
  73. /**
  74. * Absolute limit of the contained data. Set to the backing buffer's capacity upon allocation.
  75. * @type {number}
  76. * @expose
  77. * @see ByteBuffer#flip
  78. * @see ByteBuffer#clear
  79. */
  80. this.limit = capacity;
  81. /**
  82. * Whether to use little endian byte order, defaults to `false` for big endian.
  83. * @type {boolean}
  84. * @expose
  85. */
  86. this.littleEndian = littleEndian;
  87. /**
  88. * Whether to skip assertions of offsets and values, defaults to `false`.
  89. * @type {boolean}
  90. * @expose
  91. */
  92. this.noAssert = noAssert;
  93. };
  94. /**
  95. * ByteBuffer version.
  96. * @type {string}
  97. * @const
  98. * @expose
  99. */
  100. ByteBuffer.VERSION = "5.0.1";
  101. /**
  102. * Little endian constant that can be used instead of its boolean value. Evaluates to `true`.
  103. * @type {boolean}
  104. * @const
  105. * @expose
  106. */
  107. ByteBuffer.LITTLE_ENDIAN = true;
  108. /**
  109. * Big endian constant that can be used instead of its boolean value. Evaluates to `false`.
  110. * @type {boolean}
  111. * @const
  112. * @expose
  113. */
  114. ByteBuffer.BIG_ENDIAN = false;
  115. /**
  116. * Default initial capacity of `16`.
  117. * @type {number}
  118. * @expose
  119. */
  120. ByteBuffer.DEFAULT_CAPACITY = 16;
  121. /**
  122. * Default endianess of `false` for big endian.
  123. * @type {boolean}
  124. * @expose
  125. */
  126. ByteBuffer.DEFAULT_ENDIAN = ByteBuffer.BIG_ENDIAN;
  127. /**
  128. * Default no assertions flag of `false`.
  129. * @type {boolean}
  130. * @expose
  131. */
  132. ByteBuffer.DEFAULT_NOASSERT = false;
  133. /**
  134. * A `Long` class for representing a 64-bit two's-complement integer value.
  135. * @type {!Long}
  136. * @const
  137. * @see https://npmjs.org/package/long
  138. * @expose
  139. */
  140. ByteBuffer.Long = Long;
  141. /**
  142. * @alias ByteBuffer.prototype
  143. * @inner
  144. */
  145. var ByteBufferPrototype = ByteBuffer.prototype;
  146. /**
  147. * An indicator used to reliably determine if an object is a ByteBuffer or not.
  148. * @type {boolean}
  149. * @const
  150. * @expose
  151. * @private
  152. */
  153. ByteBufferPrototype.__isByteBuffer__;
  154. Object.defineProperty(ByteBufferPrototype, "__isByteBuffer__", {
  155. value: true,
  156. enumerable: false,
  157. configurable: false
  158. });
  159. // helpers
  160. /**
  161. * @type {!Buffer}
  162. * @inner
  163. */
  164. var EMPTY_BUFFER = new Buffer(0);
  165. /**
  166. * String.fromCharCode reference for compile-time renaming.
  167. * @type {function(...number):string}
  168. * @inner
  169. */
  170. var stringFromCharCode = String.fromCharCode;
  171. /**
  172. * Creates a source function for a string.
  173. * @param {string} s String to read from
  174. * @returns {function():number|null} Source function returning the next char code respectively `null` if there are
  175. * no more characters left.
  176. * @throws {TypeError} If the argument is invalid
  177. * @inner
  178. */
  179. function stringSource(s) {
  180. var i=0; return function() {
  181. return i < s.length ? s.charCodeAt(i++) : null;
  182. };
  183. }
  184. /**
  185. * Creates a destination function for a string.
  186. * @returns {function(number=):undefined|string} Destination function successively called with the next char code.
  187. * Returns the final string when called without arguments.
  188. * @inner
  189. */
  190. function stringDestination() {
  191. var cs = [], ps = []; return function() {
  192. if (arguments.length === 0)
  193. return ps.join('')+stringFromCharCode.apply(String, cs);
  194. if (cs.length + arguments.length > 1024)
  195. ps.push(stringFromCharCode.apply(String, cs)),
  196. cs.length = 0;
  197. Array.prototype.push.apply(cs, arguments);
  198. };
  199. }
  200. /**
  201. * Gets the accessor type.
  202. * @returns {Function} `Buffer` under node.js, `Uint8Array` respectively `DataView` in the browser (classes)
  203. * @expose
  204. */
  205. ByteBuffer.accessor = function() {
  206. return Buffer;
  207. };
  208. /**
  209. * Allocates a new ByteBuffer backed by a buffer of the specified capacity.
  210. * @param {number=} capacity Initial capacity. Defaults to {@link ByteBuffer.DEFAULT_CAPACITY}.
  211. * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
  212. * {@link ByteBuffer.DEFAULT_ENDIAN}.
  213. * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to
  214. * {@link ByteBuffer.DEFAULT_NOASSERT}.
  215. * @returns {!ByteBuffer}
  216. * @expose
  217. */
  218. ByteBuffer.allocate = function(capacity, littleEndian, noAssert) {
  219. return new ByteBuffer(capacity, littleEndian, noAssert);
  220. };
  221. /**
  222. * Concatenates multiple ByteBuffers into one.
  223. * @param {!Array.<!ByteBuffer|!Buffer|!ArrayBuffer|!Uint8Array|string>} buffers Buffers to concatenate
  224. * @param {(string|boolean)=} encoding String encoding if `buffers` contains a string ("base64", "hex", "binary",
  225. * defaults to "utf8")
  226. * @param {boolean=} littleEndian Whether to use little or big endian byte order for the resulting ByteBuffer. Defaults
  227. * to {@link ByteBuffer.DEFAULT_ENDIAN}.
  228. * @param {boolean=} noAssert Whether to skip assertions of offsets and values for the resulting ByteBuffer. Defaults to
  229. * {@link ByteBuffer.DEFAULT_NOASSERT}.
  230. * @returns {!ByteBuffer} Concatenated ByteBuffer
  231. * @expose
  232. */
  233. ByteBuffer.concat = function(buffers, encoding, littleEndian, noAssert) {
  234. if (typeof encoding === 'boolean' || typeof encoding !== 'string') {
  235. noAssert = littleEndian;
  236. littleEndian = encoding;
  237. encoding = undefined;
  238. }
  239. var capacity = 0;
  240. for (var i=0, k=buffers.length, length; i<k; ++i) {
  241. if (!ByteBuffer.isByteBuffer(buffers[i]))
  242. buffers[i] = ByteBuffer.wrap(buffers[i], encoding);
  243. length = buffers[i].limit - buffers[i].offset;
  244. if (length > 0) capacity += length;
  245. }
  246. if (capacity === 0)
  247. return new ByteBuffer(0, littleEndian, noAssert);
  248. var bb = new ByteBuffer(capacity, littleEndian, noAssert),
  249. bi;
  250. i=0; while (i<k) {
  251. bi = buffers[i++];
  252. length = bi.limit - bi.offset;
  253. if (length <= 0) continue;
  254. bi.buffer.copy(bb.buffer, bb.offset, bi.offset, bi.limit);
  255. bb.offset += length;
  256. }
  257. bb.limit = bb.offset;
  258. bb.offset = 0;
  259. return bb;
  260. };
  261. /**
  262. * Tests if the specified type is a ByteBuffer.
  263. * @param {*} bb ByteBuffer to test
  264. * @returns {boolean} `true` if it is a ByteBuffer, otherwise `false`
  265. * @expose
  266. */
  267. ByteBuffer.isByteBuffer = function(bb) {
  268. return (bb && bb["__isByteBuffer__"]) === true;
  269. };
  270. /**
  271. * Gets the backing buffer type.
  272. * @returns {Function} `Buffer` under node.js, `ArrayBuffer` in the browser (classes)
  273. * @expose
  274. */
  275. ByteBuffer.type = function() {
  276. return Buffer;
  277. };
  278. /**
  279. * Wraps a buffer or a string. Sets the allocated ByteBuffer's {@link ByteBuffer#offset} to `0` and its
  280. * {@link ByteBuffer#limit} to the length of the wrapped data.
  281. * @param {!ByteBuffer|!Buffer|!ArrayBuffer|!Uint8Array|string|!Array.<number>} buffer Anything that can be wrapped
  282. * @param {(string|boolean)=} encoding String encoding if `buffer` is a string ("base64", "hex", "binary", defaults to
  283. * "utf8")
  284. * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
  285. * {@link ByteBuffer.DEFAULT_ENDIAN}.
  286. * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to
  287. * {@link ByteBuffer.DEFAULT_NOASSERT}.
  288. * @returns {!ByteBuffer} A ByteBuffer wrapping `buffer`
  289. * @expose
  290. */
  291. ByteBuffer.wrap = function(buffer, encoding, littleEndian, noAssert) {
  292. if (typeof encoding !== 'string') {
  293. noAssert = littleEndian;
  294. littleEndian = encoding;
  295. encoding = undefined;
  296. }
  297. if (typeof buffer === 'string') {
  298. if (typeof encoding === 'undefined')
  299. encoding = "utf8";
  300. switch (encoding) {
  301. case "base64":
  302. return ByteBuffer.fromBase64(buffer, littleEndian);
  303. case "hex":
  304. return ByteBuffer.fromHex(buffer, littleEndian);
  305. case "binary":
  306. return ByteBuffer.fromBinary(buffer, littleEndian);
  307. case "utf8":
  308. return ByteBuffer.fromUTF8(buffer, littleEndian);
  309. case "debug":
  310. return ByteBuffer.fromDebug(buffer, littleEndian);
  311. default:
  312. throw Error("Unsupported encoding: "+encoding);
  313. }
  314. }
  315. if (buffer === null || typeof buffer !== 'object')
  316. throw TypeError("Illegal buffer");
  317. var bb;
  318. if (ByteBuffer.isByteBuffer(buffer)) {
  319. bb = ByteBufferPrototype.clone.call(buffer);
  320. bb.markedOffset = -1;
  321. return bb;
  322. }
  323. var i = 0,
  324. k = 0,
  325. b;
  326. if (buffer instanceof Uint8Array) { // Extract bytes from Uint8Array
  327. b = new Buffer(buffer.length);
  328. if (memcpy) { // Fast
  329. memcpy(b, 0, buffer.buffer, buffer.byteOffset, buffer.byteOffset + buffer.length);
  330. } else { // Slow
  331. for (i=0, k=buffer.length; i<k; ++i)
  332. b[i] = buffer[i];
  333. }
  334. buffer = b;
  335. } else if (buffer instanceof ArrayBuffer) { // Convert ArrayBuffer to Buffer
  336. b = new Buffer(buffer.byteLength);
  337. if (memcpy) { // Fast
  338. memcpy(b, 0, buffer, 0, buffer.byteLength);
  339. } else { // Slow
  340. buffer = new Uint8Array(buffer);
  341. for (i=0, k=buffer.length; i<k; ++i) {
  342. b[i] = buffer[i];
  343. }
  344. }
  345. buffer = b;
  346. } else if (!(buffer instanceof Buffer)) { // Create from octets if it is an error, otherwise fail
  347. if (Object.prototype.toString.call(buffer) !== "[object Array]")
  348. throw TypeError("Illegal buffer");
  349. buffer = new Buffer(buffer);
  350. }
  351. bb = new ByteBuffer(0, littleEndian, noAssert);
  352. if (buffer.length > 0) { // Avoid references to more than one EMPTY_BUFFER
  353. bb.buffer = buffer;
  354. bb.limit = buffer.length;
  355. }
  356. return bb;
  357. };
  358. /**
  359. * Writes the array as a bitset.
  360. * @param {Array<boolean>} value Array of booleans to write
  361. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `length` if omitted.
  362. * @returns {!ByteBuffer}
  363. * @expose
  364. */
  365. ByteBufferPrototype.writeBitSet = function(value, offset) {
  366. var relative = typeof offset === 'undefined';
  367. if (relative) offset = this.offset;
  368. if (!this.noAssert) {
  369. if (!(value instanceof Array))
  370. throw TypeError("Illegal BitSet: Not an array");
  371. if (typeof offset !== 'number' || offset % 1 !== 0)
  372. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  373. offset >>>= 0;
  374. if (offset < 0 || offset + 0 > this.buffer.length)
  375. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  376. }
  377. var start = offset,
  378. bits = value.length,
  379. bytes = (bits >> 3),
  380. bit = 0,
  381. k;
  382. offset += this.writeVarint32(bits,offset);
  383. while(bytes--) {
  384. k = (!!value[bit++] & 1) |
  385. ((!!value[bit++] & 1) << 1) |
  386. ((!!value[bit++] & 1) << 2) |
  387. ((!!value[bit++] & 1) << 3) |
  388. ((!!value[bit++] & 1) << 4) |
  389. ((!!value[bit++] & 1) << 5) |
  390. ((!!value[bit++] & 1) << 6) |
  391. ((!!value[bit++] & 1) << 7);
  392. this.writeByte(k,offset++);
  393. }
  394. if(bit < bits) {
  395. var m = 0; k = 0;
  396. while(bit < bits) k = k | ((!!value[bit++] & 1) << (m++));
  397. this.writeByte(k,offset++);
  398. }
  399. if (relative) {
  400. this.offset = offset;
  401. return this;
  402. }
  403. return offset - start;
  404. }
  405. /**
  406. * Reads a BitSet as an array of booleans.
  407. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `length` if omitted.
  408. * @returns {Array<boolean>
  409. * @expose
  410. */
  411. ByteBufferPrototype.readBitSet = function(offset) {
  412. var relative = typeof offset === 'undefined';
  413. if (relative) offset = this.offset;
  414. var ret = this.readVarint32(offset),
  415. bits = ret.value,
  416. bytes = (bits >> 3),
  417. bit = 0,
  418. value = [],
  419. k;
  420. offset += ret.length;
  421. while(bytes--) {
  422. k = this.readByte(offset++);
  423. value[bit++] = !!(k & 0x01);
  424. value[bit++] = !!(k & 0x02);
  425. value[bit++] = !!(k & 0x04);
  426. value[bit++] = !!(k & 0x08);
  427. value[bit++] = !!(k & 0x10);
  428. value[bit++] = !!(k & 0x20);
  429. value[bit++] = !!(k & 0x40);
  430. value[bit++] = !!(k & 0x80);
  431. }
  432. if(bit < bits) {
  433. var m = 0;
  434. k = this.readByte(offset++);
  435. while(bit < bits) value[bit++] = !!((k >> (m++)) & 1);
  436. }
  437. if (relative) {
  438. this.offset = offset;
  439. }
  440. return value;
  441. }
  442. /**
  443. * Reads the specified number of bytes.
  444. * @param {number} length Number of bytes to read
  445. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `length` if omitted.
  446. * @returns {!ByteBuffer}
  447. * @expose
  448. */
  449. ByteBufferPrototype.readBytes = function(length, offset) {
  450. var relative = typeof offset === 'undefined';
  451. if (relative) offset = this.offset;
  452. if (!this.noAssert) {
  453. if (typeof offset !== 'number' || offset % 1 !== 0)
  454. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  455. offset >>>= 0;
  456. if (offset < 0 || offset + length > this.buffer.length)
  457. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+length+") <= "+this.buffer.length);
  458. }
  459. var slice = this.slice(offset, offset + length);
  460. if (relative) this.offset += length;
  461. return slice;
  462. };
  463. /**
  464. * Writes a payload of bytes. This is an alias of {@link ByteBuffer#append}.
  465. * @function
  466. * @param {!ByteBuffer|!Buffer|!ArrayBuffer|!Uint8Array|string} source Data to write. If `source` is a ByteBuffer, its
  467. * offsets will be modified according to the performed read operation.
  468. * @param {(string|number)=} encoding Encoding if `data` is a string ("base64", "hex", "binary", defaults to "utf8")
  469. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  470. * written if omitted.
  471. * @returns {!ByteBuffer} this
  472. * @expose
  473. */
  474. ByteBufferPrototype.writeBytes = ByteBufferPrototype.append;
  475. // types/ints/int8
  476. /**
  477. * Writes an 8bit signed integer.
  478. * @param {number} value Value to write
  479. * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
  480. * @returns {!ByteBuffer} this
  481. * @expose
  482. */
  483. ByteBufferPrototype.writeInt8 = function(value, offset) {
  484. var relative = typeof offset === 'undefined';
  485. if (relative) offset = this.offset;
  486. if (!this.noAssert) {
  487. if (typeof value !== 'number' || value % 1 !== 0)
  488. throw TypeError("Illegal value: "+value+" (not an integer)");
  489. value |= 0;
  490. if (typeof offset !== 'number' || offset % 1 !== 0)
  491. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  492. offset >>>= 0;
  493. if (offset < 0 || offset + 0 > this.buffer.length)
  494. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  495. }
  496. offset += 1;
  497. var capacity0 = this.buffer.length;
  498. if (offset > capacity0)
  499. this.resize((capacity0 *= 2) > offset ? capacity0 : offset);
  500. offset -= 1;
  501. this.buffer[offset] = value;
  502. if (relative) this.offset += 1;
  503. return this;
  504. };
  505. /**
  506. * Writes an 8bit signed integer. This is an alias of {@link ByteBuffer#writeInt8}.
  507. * @function
  508. * @param {number} value Value to write
  509. * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
  510. * @returns {!ByteBuffer} this
  511. * @expose
  512. */
  513. ByteBufferPrototype.writeByte = ByteBufferPrototype.writeInt8;
  514. /**
  515. * Reads an 8bit signed integer.
  516. * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
  517. * @returns {number} Value read
  518. * @expose
  519. */
  520. ByteBufferPrototype.readInt8 = function(offset) {
  521. var relative = typeof offset === 'undefined';
  522. if (relative) offset = this.offset;
  523. if (!this.noAssert) {
  524. if (typeof offset !== 'number' || offset % 1 !== 0)
  525. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  526. offset >>>= 0;
  527. if (offset < 0 || offset + 1 > this.buffer.length)
  528. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.length);
  529. }
  530. var value = this.buffer[offset];
  531. if ((value & 0x80) === 0x80) value = -(0xFF - value + 1); // Cast to signed
  532. if (relative) this.offset += 1;
  533. return value;
  534. };
  535. /**
  536. * Reads an 8bit signed integer. This is an alias of {@link ByteBuffer#readInt8}.
  537. * @function
  538. * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
  539. * @returns {number} Value read
  540. * @expose
  541. */
  542. ByteBufferPrototype.readByte = ByteBufferPrototype.readInt8;
  543. /**
  544. * Writes an 8bit unsigned integer.
  545. * @param {number} value Value to write
  546. * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
  547. * @returns {!ByteBuffer} this
  548. * @expose
  549. */
  550. ByteBufferPrototype.writeUint8 = function(value, offset) {
  551. var relative = typeof offset === 'undefined';
  552. if (relative) offset = this.offset;
  553. if (!this.noAssert) {
  554. if (typeof value !== 'number' || value % 1 !== 0)
  555. throw TypeError("Illegal value: "+value+" (not an integer)");
  556. value >>>= 0;
  557. if (typeof offset !== 'number' || offset % 1 !== 0)
  558. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  559. offset >>>= 0;
  560. if (offset < 0 || offset + 0 > this.buffer.length)
  561. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  562. }
  563. offset += 1;
  564. var capacity1 = this.buffer.length;
  565. if (offset > capacity1)
  566. this.resize((capacity1 *= 2) > offset ? capacity1 : offset);
  567. offset -= 1;
  568. this.buffer[offset] = value;
  569. if (relative) this.offset += 1;
  570. return this;
  571. };
  572. /**
  573. * Writes an 8bit unsigned integer. This is an alias of {@link ByteBuffer#writeUint8}.
  574. * @function
  575. * @param {number} value Value to write
  576. * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
  577. * @returns {!ByteBuffer} this
  578. * @expose
  579. */
  580. ByteBufferPrototype.writeUInt8 = ByteBufferPrototype.writeUint8;
  581. /**
  582. * Reads an 8bit unsigned integer.
  583. * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
  584. * @returns {number} Value read
  585. * @expose
  586. */
  587. ByteBufferPrototype.readUint8 = function(offset) {
  588. var relative = typeof offset === 'undefined';
  589. if (relative) offset = this.offset;
  590. if (!this.noAssert) {
  591. if (typeof offset !== 'number' || offset % 1 !== 0)
  592. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  593. offset >>>= 0;
  594. if (offset < 0 || offset + 1 > this.buffer.length)
  595. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.length);
  596. }
  597. var value = this.buffer[offset];
  598. if (relative) this.offset += 1;
  599. return value;
  600. };
  601. /**
  602. * Reads an 8bit unsigned integer. This is an alias of {@link ByteBuffer#readUint8}.
  603. * @function
  604. * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
  605. * @returns {number} Value read
  606. * @expose
  607. */
  608. ByteBufferPrototype.readUInt8 = ByteBufferPrototype.readUint8;
  609. // types/ints/int16
  610. /**
  611. * Writes a 16bit signed integer.
  612. * @param {number} value Value to write
  613. * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
  614. * @throws {TypeError} If `offset` or `value` is not a valid number
  615. * @throws {RangeError} If `offset` is out of bounds
  616. * @expose
  617. */
  618. ByteBufferPrototype.writeInt16 = function(value, offset) {
  619. var relative = typeof offset === 'undefined';
  620. if (relative) offset = this.offset;
  621. if (!this.noAssert) {
  622. if (typeof value !== 'number' || value % 1 !== 0)
  623. throw TypeError("Illegal value: "+value+" (not an integer)");
  624. value |= 0;
  625. if (typeof offset !== 'number' || offset % 1 !== 0)
  626. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  627. offset >>>= 0;
  628. if (offset < 0 || offset + 0 > this.buffer.length)
  629. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  630. }
  631. offset += 2;
  632. var capacity2 = this.buffer.length;
  633. if (offset > capacity2)
  634. this.resize((capacity2 *= 2) > offset ? capacity2 : offset);
  635. offset -= 2;
  636. if (this.littleEndian) {
  637. this.buffer[offset+1] = (value & 0xFF00) >>> 8;
  638. this.buffer[offset ] = value & 0x00FF;
  639. } else {
  640. this.buffer[offset] = (value & 0xFF00) >>> 8;
  641. this.buffer[offset+1] = value & 0x00FF;
  642. }
  643. if (relative) this.offset += 2;
  644. return this;
  645. };
  646. /**
  647. * Writes a 16bit signed integer. This is an alias of {@link ByteBuffer#writeInt16}.
  648. * @function
  649. * @param {number} value Value to write
  650. * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
  651. * @throws {TypeError} If `offset` or `value` is not a valid number
  652. * @throws {RangeError} If `offset` is out of bounds
  653. * @expose
  654. */
  655. ByteBufferPrototype.writeShort = ByteBufferPrototype.writeInt16;
  656. /**
  657. * Reads a 16bit signed integer.
  658. * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
  659. * @returns {number} Value read
  660. * @throws {TypeError} If `offset` is not a valid number
  661. * @throws {RangeError} If `offset` is out of bounds
  662. * @expose
  663. */
  664. ByteBufferPrototype.readInt16 = function(offset) {
  665. var relative = typeof offset === 'undefined';
  666. if (relative) offset = this.offset;
  667. if (!this.noAssert) {
  668. if (typeof offset !== 'number' || offset % 1 !== 0)
  669. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  670. offset >>>= 0;
  671. if (offset < 0 || offset + 2 > this.buffer.length)
  672. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+2+") <= "+this.buffer.length);
  673. }
  674. var value = 0;
  675. if (this.littleEndian) {
  676. value = this.buffer[offset ];
  677. value |= this.buffer[offset+1] << 8;
  678. } else {
  679. value = this.buffer[offset ] << 8;
  680. value |= this.buffer[offset+1];
  681. }
  682. if ((value & 0x8000) === 0x8000) value = -(0xFFFF - value + 1); // Cast to signed
  683. if (relative) this.offset += 2;
  684. return value;
  685. };
  686. /**
  687. * Reads a 16bit signed integer. This is an alias of {@link ByteBuffer#readInt16}.
  688. * @function
  689. * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
  690. * @returns {number} Value read
  691. * @throws {TypeError} If `offset` is not a valid number
  692. * @throws {RangeError} If `offset` is out of bounds
  693. * @expose
  694. */
  695. ByteBufferPrototype.readShort = ByteBufferPrototype.readInt16;
  696. /**
  697. * Writes a 16bit unsigned integer.
  698. * @param {number} value Value to write
  699. * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
  700. * @throws {TypeError} If `offset` or `value` is not a valid number
  701. * @throws {RangeError} If `offset` is out of bounds
  702. * @expose
  703. */
  704. ByteBufferPrototype.writeUint16 = function(value, offset) {
  705. var relative = typeof offset === 'undefined';
  706. if (relative) offset = this.offset;
  707. if (!this.noAssert) {
  708. if (typeof value !== 'number' || value % 1 !== 0)
  709. throw TypeError("Illegal value: "+value+" (not an integer)");
  710. value >>>= 0;
  711. if (typeof offset !== 'number' || offset % 1 !== 0)
  712. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  713. offset >>>= 0;
  714. if (offset < 0 || offset + 0 > this.buffer.length)
  715. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  716. }
  717. offset += 2;
  718. var capacity3 = this.buffer.length;
  719. if (offset > capacity3)
  720. this.resize((capacity3 *= 2) > offset ? capacity3 : offset);
  721. offset -= 2;
  722. if (this.littleEndian) {
  723. this.buffer[offset+1] = (value & 0xFF00) >>> 8;
  724. this.buffer[offset ] = value & 0x00FF;
  725. } else {
  726. this.buffer[offset] = (value & 0xFF00) >>> 8;
  727. this.buffer[offset+1] = value & 0x00FF;
  728. }
  729. if (relative) this.offset += 2;
  730. return this;
  731. };
  732. /**
  733. * Writes a 16bit unsigned integer. This is an alias of {@link ByteBuffer#writeUint16}.
  734. * @function
  735. * @param {number} value Value to write
  736. * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
  737. * @throws {TypeError} If `offset` or `value` is not a valid number
  738. * @throws {RangeError} If `offset` is out of bounds
  739. * @expose
  740. */
  741. ByteBufferPrototype.writeUInt16 = ByteBufferPrototype.writeUint16;
  742. /**
  743. * Reads a 16bit unsigned integer.
  744. * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
  745. * @returns {number} Value read
  746. * @throws {TypeError} If `offset` is not a valid number
  747. * @throws {RangeError} If `offset` is out of bounds
  748. * @expose
  749. */
  750. ByteBufferPrototype.readUint16 = function(offset) {
  751. var relative = typeof offset === 'undefined';
  752. if (relative) offset = this.offset;
  753. if (!this.noAssert) {
  754. if (typeof offset !== 'number' || offset % 1 !== 0)
  755. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  756. offset >>>= 0;
  757. if (offset < 0 || offset + 2 > this.buffer.length)
  758. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+2+") <= "+this.buffer.length);
  759. }
  760. var value = 0;
  761. if (this.littleEndian) {
  762. value = this.buffer[offset ];
  763. value |= this.buffer[offset+1] << 8;
  764. } else {
  765. value = this.buffer[offset ] << 8;
  766. value |= this.buffer[offset+1];
  767. }
  768. if (relative) this.offset += 2;
  769. return value;
  770. };
  771. /**
  772. * Reads a 16bit unsigned integer. This is an alias of {@link ByteBuffer#readUint16}.
  773. * @function
  774. * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
  775. * @returns {number} Value read
  776. * @throws {TypeError} If `offset` is not a valid number
  777. * @throws {RangeError} If `offset` is out of bounds
  778. * @expose
  779. */
  780. ByteBufferPrototype.readUInt16 = ByteBufferPrototype.readUint16;
  781. // types/ints/int32
  782. /**
  783. * Writes a 32bit signed integer.
  784. * @param {number} value Value to write
  785. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
  786. * @expose
  787. */
  788. ByteBufferPrototype.writeInt32 = function(value, offset) {
  789. var relative = typeof offset === 'undefined';
  790. if (relative) offset = this.offset;
  791. if (!this.noAssert) {
  792. if (typeof value !== 'number' || value % 1 !== 0)
  793. throw TypeError("Illegal value: "+value+" (not an integer)");
  794. value |= 0;
  795. if (typeof offset !== 'number' || offset % 1 !== 0)
  796. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  797. offset >>>= 0;
  798. if (offset < 0 || offset + 0 > this.buffer.length)
  799. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  800. }
  801. offset += 4;
  802. var capacity4 = this.buffer.length;
  803. if (offset > capacity4)
  804. this.resize((capacity4 *= 2) > offset ? capacity4 : offset);
  805. offset -= 4;
  806. if (this.littleEndian) {
  807. this.buffer[offset+3] = (value >>> 24) & 0xFF;
  808. this.buffer[offset+2] = (value >>> 16) & 0xFF;
  809. this.buffer[offset+1] = (value >>> 8) & 0xFF;
  810. this.buffer[offset ] = value & 0xFF;
  811. } else {
  812. this.buffer[offset ] = (value >>> 24) & 0xFF;
  813. this.buffer[offset+1] = (value >>> 16) & 0xFF;
  814. this.buffer[offset+2] = (value >>> 8) & 0xFF;
  815. this.buffer[offset+3] = value & 0xFF;
  816. }
  817. if (relative) this.offset += 4;
  818. return this;
  819. };
  820. /**
  821. * Writes a 32bit signed integer. This is an alias of {@link ByteBuffer#writeInt32}.
  822. * @param {number} value Value to write
  823. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
  824. * @expose
  825. */
  826. ByteBufferPrototype.writeInt = ByteBufferPrototype.writeInt32;
  827. /**
  828. * Reads a 32bit signed integer.
  829. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
  830. * @returns {number} Value read
  831. * @expose
  832. */
  833. ByteBufferPrototype.readInt32 = function(offset) {
  834. var relative = typeof offset === 'undefined';
  835. if (relative) offset = this.offset;
  836. if (!this.noAssert) {
  837. if (typeof offset !== 'number' || offset % 1 !== 0)
  838. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  839. offset >>>= 0;
  840. if (offset < 0 || offset + 4 > this.buffer.length)
  841. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.length);
  842. }
  843. var value = 0;
  844. if (this.littleEndian) {
  845. value = this.buffer[offset+2] << 16;
  846. value |= this.buffer[offset+1] << 8;
  847. value |= this.buffer[offset ];
  848. value += this.buffer[offset+3] << 24 >>> 0;
  849. } else {
  850. value = this.buffer[offset+1] << 16;
  851. value |= this.buffer[offset+2] << 8;
  852. value |= this.buffer[offset+3];
  853. value += this.buffer[offset ] << 24 >>> 0;
  854. }
  855. value |= 0; // Cast to signed
  856. if (relative) this.offset += 4;
  857. return value;
  858. };
  859. /**
  860. * Reads a 32bit signed integer. This is an alias of {@link ByteBuffer#readInt32}.
  861. * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `4` if omitted.
  862. * @returns {number} Value read
  863. * @expose
  864. */
  865. ByteBufferPrototype.readInt = ByteBufferPrototype.readInt32;
  866. /**
  867. * Writes a 32bit unsigned integer.
  868. * @param {number} value Value to write
  869. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
  870. * @expose
  871. */
  872. ByteBufferPrototype.writeUint32 = function(value, offset) {
  873. var relative = typeof offset === 'undefined';
  874. if (relative) offset = this.offset;
  875. if (!this.noAssert) {
  876. if (typeof value !== 'number' || value % 1 !== 0)
  877. throw TypeError("Illegal value: "+value+" (not an integer)");
  878. value >>>= 0;
  879. if (typeof offset !== 'number' || offset % 1 !== 0)
  880. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  881. offset >>>= 0;
  882. if (offset < 0 || offset + 0 > this.buffer.length)
  883. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  884. }
  885. offset += 4;
  886. var capacity5 = this.buffer.length;
  887. if (offset > capacity5)
  888. this.resize((capacity5 *= 2) > offset ? capacity5 : offset);
  889. offset -= 4;
  890. if (this.littleEndian) {
  891. this.buffer[offset+3] = (value >>> 24) & 0xFF;
  892. this.buffer[offset+2] = (value >>> 16) & 0xFF;
  893. this.buffer[offset+1] = (value >>> 8) & 0xFF;
  894. this.buffer[offset ] = value & 0xFF;
  895. } else {
  896. this.buffer[offset ] = (value >>> 24) & 0xFF;
  897. this.buffer[offset+1] = (value >>> 16) & 0xFF;
  898. this.buffer[offset+2] = (value >>> 8) & 0xFF;
  899. this.buffer[offset+3] = value & 0xFF;
  900. }
  901. if (relative) this.offset += 4;
  902. return this;
  903. };
  904. /**
  905. * Writes a 32bit unsigned integer. This is an alias of {@link ByteBuffer#writeUint32}.
  906. * @function
  907. * @param {number} value Value to write
  908. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
  909. * @expose
  910. */
  911. ByteBufferPrototype.writeUInt32 = ByteBufferPrototype.writeUint32;
  912. /**
  913. * Reads a 32bit unsigned integer.
  914. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
  915. * @returns {number} Value read
  916. * @expose
  917. */
  918. ByteBufferPrototype.readUint32 = function(offset) {
  919. var relative = typeof offset === 'undefined';
  920. if (relative) offset = this.offset;
  921. if (!this.noAssert) {
  922. if (typeof offset !== 'number' || offset % 1 !== 0)
  923. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  924. offset >>>= 0;
  925. if (offset < 0 || offset + 4 > this.buffer.length)
  926. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.length);
  927. }
  928. var value = 0;
  929. if (this.littleEndian) {
  930. value = this.buffer[offset+2] << 16;
  931. value |= this.buffer[offset+1] << 8;
  932. value |= this.buffer[offset ];
  933. value += this.buffer[offset+3] << 24 >>> 0;
  934. } else {
  935. value = this.buffer[offset+1] << 16;
  936. value |= this.buffer[offset+2] << 8;
  937. value |= this.buffer[offset+3];
  938. value += this.buffer[offset ] << 24 >>> 0;
  939. }
  940. if (relative) this.offset += 4;
  941. return value;
  942. };
  943. /**
  944. * Reads a 32bit unsigned integer. This is an alias of {@link ByteBuffer#readUint32}.
  945. * @function
  946. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
  947. * @returns {number} Value read
  948. * @expose
  949. */
  950. ByteBufferPrototype.readUInt32 = ByteBufferPrototype.readUint32;
  951. // types/ints/int64
  952. if (Long) {
  953. /**
  954. * Writes a 64bit signed integer.
  955. * @param {number|!Long} value Value to write
  956. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
  957. * @returns {!ByteBuffer} this
  958. * @expose
  959. */
  960. ByteBufferPrototype.writeInt64 = function(value, offset) {
  961. var relative = typeof offset === 'undefined';
  962. if (relative) offset = this.offset;
  963. if (!this.noAssert) {
  964. if (typeof value === 'number')
  965. value = Long.fromNumber(value);
  966. else if (typeof value === 'string')
  967. value = Long.fromString(value);
  968. else if (!(value && value instanceof Long))
  969. throw TypeError("Illegal value: "+value+" (not an integer or Long)");
  970. if (typeof offset !== 'number' || offset % 1 !== 0)
  971. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  972. offset >>>= 0;
  973. if (offset < 0 || offset + 0 > this.buffer.length)
  974. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  975. }
  976. if (typeof value === 'number')
  977. value = Long.fromNumber(value);
  978. else if (typeof value === 'string')
  979. value = Long.fromString(value);
  980. offset += 8;
  981. var capacity6 = this.buffer.length;
  982. if (offset > capacity6)
  983. this.resize((capacity6 *= 2) > offset ? capacity6 : offset);
  984. offset -= 8;
  985. var lo = value.low,
  986. hi = value.high;
  987. if (this.littleEndian) {
  988. this.buffer[offset+3] = (lo >>> 24) & 0xFF;
  989. this.buffer[offset+2] = (lo >>> 16) & 0xFF;
  990. this.buffer[offset+1] = (lo >>> 8) & 0xFF;
  991. this.buffer[offset ] = lo & 0xFF;
  992. offset += 4;
  993. this.buffer[offset+3] = (hi >>> 24) & 0xFF;
  994. this.buffer[offset+2] = (hi >>> 16) & 0xFF;
  995. this.buffer[offset+1] = (hi >>> 8) & 0xFF;
  996. this.buffer[offset ] = hi & 0xFF;
  997. } else {
  998. this.buffer[offset ] = (hi >>> 24) & 0xFF;
  999. this.buffer[offset+1] = (hi >>> 16) & 0xFF;
  1000. this.buffer[offset+2] = (hi >>> 8) & 0xFF;
  1001. this.buffer[offset+3] = hi & 0xFF;
  1002. offset += 4;
  1003. this.buffer[offset ] = (lo >>> 24) & 0xFF;
  1004. this.buffer[offset+1] = (lo >>> 16) & 0xFF;
  1005. this.buffer[offset+2] = (lo >>> 8) & 0xFF;
  1006. this.buffer[offset+3] = lo & 0xFF;
  1007. }
  1008. if (relative) this.offset += 8;
  1009. return this;
  1010. };
  1011. /**
  1012. * Writes a 64bit signed integer. This is an alias of {@link ByteBuffer#writeInt64}.
  1013. * @param {number|!Long} value Value to write
  1014. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
  1015. * @returns {!ByteBuffer} this
  1016. * @expose
  1017. */
  1018. ByteBufferPrototype.writeLong = ByteBufferPrototype.writeInt64;
  1019. /**
  1020. * Reads a 64bit signed integer.
  1021. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
  1022. * @returns {!Long}
  1023. * @expose
  1024. */
  1025. ByteBufferPrototype.readInt64 = function(offset) {
  1026. var relative = typeof offset === 'undefined';
  1027. if (relative) offset = this.offset;
  1028. if (!this.noAssert) {
  1029. if (typeof offset !== 'number' || offset % 1 !== 0)
  1030. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1031. offset >>>= 0;
  1032. if (offset < 0 || offset + 8 > this.buffer.length)
  1033. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.length);
  1034. }
  1035. var lo = 0,
  1036. hi = 0;
  1037. if (this.littleEndian) {
  1038. lo = this.buffer[offset+2] << 16;
  1039. lo |= this.buffer[offset+1] << 8;
  1040. lo |= this.buffer[offset ];
  1041. lo += this.buffer[offset+3] << 24 >>> 0;
  1042. offset += 4;
  1043. hi = this.buffer[offset+2] << 16;
  1044. hi |= this.buffer[offset+1] << 8;
  1045. hi |= this.buffer[offset ];
  1046. hi += this.buffer[offset+3] << 24 >>> 0;
  1047. } else {
  1048. hi = this.buffer[offset+1] << 16;
  1049. hi |= this.buffer[offset+2] << 8;
  1050. hi |= this.buffer[offset+3];
  1051. hi += this.buffer[offset ] << 24 >>> 0;
  1052. offset += 4;
  1053. lo = this.buffer[offset+1] << 16;
  1054. lo |= this.buffer[offset+2] << 8;
  1055. lo |= this.buffer[offset+3];
  1056. lo += this.buffer[offset ] << 24 >>> 0;
  1057. }
  1058. var value = new Long(lo, hi, false);
  1059. if (relative) this.offset += 8;
  1060. return value;
  1061. };
  1062. /**
  1063. * Reads a 64bit signed integer. This is an alias of {@link ByteBuffer#readInt64}.
  1064. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
  1065. * @returns {!Long}
  1066. * @expose
  1067. */
  1068. ByteBufferPrototype.readLong = ByteBufferPrototype.readInt64;
  1069. /**
  1070. * Writes a 64bit unsigned integer.
  1071. * @param {number|!Long} value Value to write
  1072. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
  1073. * @returns {!ByteBuffer} this
  1074. * @expose
  1075. */
  1076. ByteBufferPrototype.writeUint64 = function(value, offset) {
  1077. var relative = typeof offset === 'undefined';
  1078. if (relative) offset = this.offset;
  1079. if (!this.noAssert) {
  1080. if (typeof value === 'number')
  1081. value = Long.fromNumber(value);
  1082. else if (typeof value === 'string')
  1083. value = Long.fromString(value);
  1084. else if (!(value && value instanceof Long))
  1085. throw TypeError("Illegal value: "+value+" (not an integer or Long)");
  1086. if (typeof offset !== 'number' || offset % 1 !== 0)
  1087. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1088. offset >>>= 0;
  1089. if (offset < 0 || offset + 0 > this.buffer.length)
  1090. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  1091. }
  1092. if (typeof value === 'number')
  1093. value = Long.fromNumber(value);
  1094. else if (typeof value === 'string')
  1095. value = Long.fromString(value);
  1096. offset += 8;
  1097. var capacity7 = this.buffer.length;
  1098. if (offset > capacity7)
  1099. this.resize((capacity7 *= 2) > offset ? capacity7 : offset);
  1100. offset -= 8;
  1101. var lo = value.low,
  1102. hi = value.high;
  1103. if (this.littleEndian) {
  1104. this.buffer[offset+3] = (lo >>> 24) & 0xFF;
  1105. this.buffer[offset+2] = (lo >>> 16) & 0xFF;
  1106. this.buffer[offset+1] = (lo >>> 8) & 0xFF;
  1107. this.buffer[offset ] = lo & 0xFF;
  1108. offset += 4;
  1109. this.buffer[offset+3] = (hi >>> 24) & 0xFF;
  1110. this.buffer[offset+2] = (hi >>> 16) & 0xFF;
  1111. this.buffer[offset+1] = (hi >>> 8) & 0xFF;
  1112. this.buffer[offset ] = hi & 0xFF;
  1113. } else {
  1114. this.buffer[offset ] = (hi >>> 24) & 0xFF;
  1115. this.buffer[offset+1] = (hi >>> 16) & 0xFF;
  1116. this.buffer[offset+2] = (hi >>> 8) & 0xFF;
  1117. this.buffer[offset+3] = hi & 0xFF;
  1118. offset += 4;
  1119. this.buffer[offset ] = (lo >>> 24) & 0xFF;
  1120. this.buffer[offset+1] = (lo >>> 16) & 0xFF;
  1121. this.buffer[offset+2] = (lo >>> 8) & 0xFF;
  1122. this.buffer[offset+3] = lo & 0xFF;
  1123. }
  1124. if (relative) this.offset += 8;
  1125. return this;
  1126. };
  1127. /**
  1128. * Writes a 64bit unsigned integer. This is an alias of {@link ByteBuffer#writeUint64}.
  1129. * @function
  1130. * @param {number|!Long} value Value to write
  1131. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
  1132. * @returns {!ByteBuffer} this
  1133. * @expose
  1134. */
  1135. ByteBufferPrototype.writeUInt64 = ByteBufferPrototype.writeUint64;
  1136. /**
  1137. * Reads a 64bit unsigned integer.
  1138. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
  1139. * @returns {!Long}
  1140. * @expose
  1141. */
  1142. ByteBufferPrototype.readUint64 = function(offset) {
  1143. var relative = typeof offset === 'undefined';
  1144. if (relative) offset = this.offset;
  1145. if (!this.noAssert) {
  1146. if (typeof offset !== 'number' || offset % 1 !== 0)
  1147. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1148. offset >>>= 0;
  1149. if (offset < 0 || offset + 8 > this.buffer.length)
  1150. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.length);
  1151. }
  1152. var lo = 0,
  1153. hi = 0;
  1154. if (this.littleEndian) {
  1155. lo = this.buffer[offset+2] << 16;
  1156. lo |= this.buffer[offset+1] << 8;
  1157. lo |= this.buffer[offset ];
  1158. lo += this.buffer[offset+3] << 24 >>> 0;
  1159. offset += 4;
  1160. hi = this.buffer[offset+2] << 16;
  1161. hi |= this.buffer[offset+1] << 8;
  1162. hi |= this.buffer[offset ];
  1163. hi += this.buffer[offset+3] << 24 >>> 0;
  1164. } else {
  1165. hi = this.buffer[offset+1] << 16;
  1166. hi |= this.buffer[offset+2] << 8;
  1167. hi |= this.buffer[offset+3];
  1168. hi += this.buffer[offset ] << 24 >>> 0;
  1169. offset += 4;
  1170. lo = this.buffer[offset+1] << 16;
  1171. lo |= this.buffer[offset+2] << 8;
  1172. lo |= this.buffer[offset+3];
  1173. lo += this.buffer[offset ] << 24 >>> 0;
  1174. }
  1175. var value = new Long(lo, hi, true);
  1176. if (relative) this.offset += 8;
  1177. return value;
  1178. };
  1179. /**
  1180. * Reads a 64bit unsigned integer. This is an alias of {@link ByteBuffer#readUint64}.
  1181. * @function
  1182. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
  1183. * @returns {!Long}
  1184. * @expose
  1185. */
  1186. ByteBufferPrototype.readUInt64 = ByteBufferPrototype.readUint64;
  1187. } // Long
  1188. // types/floats/float32
  1189. /**
  1190. * Writes a 32bit float.
  1191. * @param {number} value Value to write
  1192. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
  1193. * @returns {!ByteBuffer} this
  1194. * @expose
  1195. */
  1196. ByteBufferPrototype.writeFloat32 = function(value, offset) {
  1197. var relative = typeof offset === 'undefined';
  1198. if (relative) offset = this.offset;
  1199. if (!this.noAssert) {
  1200. if (typeof value !== 'number')
  1201. throw TypeError("Illegal value: "+value+" (not a number)");
  1202. if (typeof offset !== 'number' || offset % 1 !== 0)
  1203. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1204. offset >>>= 0;
  1205. if (offset < 0 || offset + 0 > this.buffer.length)
  1206. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  1207. }
  1208. offset += 4;
  1209. var capacity8 = this.buffer.length;
  1210. if (offset > capacity8)
  1211. this.resize((capacity8 *= 2) > offset ? capacity8 : offset);
  1212. offset -= 4;
  1213. this.littleEndian
  1214. ? this.buffer.writeFloatLE(value, offset, true)
  1215. : this.buffer.writeFloatBE(value, offset, true);
  1216. if (relative) this.offset += 4;
  1217. return this;
  1218. };
  1219. /**
  1220. * Writes a 32bit float. This is an alias of {@link ByteBuffer#writeFloat32}.
  1221. * @function
  1222. * @param {number} value Value to write
  1223. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
  1224. * @returns {!ByteBuffer} this
  1225. * @expose
  1226. */
  1227. ByteBufferPrototype.writeFloat = ByteBufferPrototype.writeFloat32;
  1228. /**
  1229. * Reads a 32bit float.
  1230. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
  1231. * @returns {number}
  1232. * @expose
  1233. */
  1234. ByteBufferPrototype.readFloat32 = function(offset) {
  1235. var relative = typeof offset === 'undefined';
  1236. if (relative) offset = this.offset;
  1237. if (!this.noAssert) {
  1238. if (typeof offset !== 'number' || offset % 1 !== 0)
  1239. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1240. offset >>>= 0;
  1241. if (offset < 0 || offset + 4 > this.buffer.length)
  1242. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.length);
  1243. }
  1244. var value = this.littleEndian
  1245. ? this.buffer.readFloatLE(offset, true)
  1246. : this.buffer.readFloatBE(offset, true);
  1247. if (relative) this.offset += 4;
  1248. return value;
  1249. };
  1250. /**
  1251. * Reads a 32bit float. This is an alias of {@link ByteBuffer#readFloat32}.
  1252. * @function
  1253. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
  1254. * @returns {number}
  1255. * @expose
  1256. */
  1257. ByteBufferPrototype.readFloat = ByteBufferPrototype.readFloat32;
  1258. // types/floats/float64
  1259. /**
  1260. * Writes a 64bit float.
  1261. * @param {number} value Value to write
  1262. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
  1263. * @returns {!ByteBuffer} this
  1264. * @expose
  1265. */
  1266. ByteBufferPrototype.writeFloat64 = function(value, offset) {
  1267. var relative = typeof offset === 'undefined';
  1268. if (relative) offset = this.offset;
  1269. if (!this.noAssert) {
  1270. if (typeof value !== 'number')
  1271. throw TypeError("Illegal value: "+value+" (not a number)");
  1272. if (typeof offset !== 'number' || offset % 1 !== 0)
  1273. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1274. offset >>>= 0;
  1275. if (offset < 0 || offset + 0 > this.buffer.length)
  1276. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  1277. }
  1278. offset += 8;
  1279. var capacity9 = this.buffer.length;
  1280. if (offset > capacity9)
  1281. this.resize((capacity9 *= 2) > offset ? capacity9 : offset);
  1282. offset -= 8;
  1283. this.littleEndian
  1284. ? this.buffer.writeDoubleLE(value, offset, true)
  1285. : this.buffer.writeDoubleBE(value, offset, true);
  1286. if (relative) this.offset += 8;
  1287. return this;
  1288. };
  1289. /**
  1290. * Writes a 64bit float. This is an alias of {@link ByteBuffer#writeFloat64}.
  1291. * @function
  1292. * @param {number} value Value to write
  1293. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
  1294. * @returns {!ByteBuffer} this
  1295. * @expose
  1296. */
  1297. ByteBufferPrototype.writeDouble = ByteBufferPrototype.writeFloat64;
  1298. /**
  1299. * Reads a 64bit float.
  1300. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
  1301. * @returns {number}
  1302. * @expose
  1303. */
  1304. ByteBufferPrototype.readFloat64 = function(offset) {
  1305. var relative = typeof offset === 'undefined';
  1306. if (relative) offset = this.offset;
  1307. if (!this.noAssert) {
  1308. if (typeof offset !== 'number' || offset % 1 !== 0)
  1309. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1310. offset >>>= 0;
  1311. if (offset < 0 || offset + 8 > this.buffer.length)
  1312. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.length);
  1313. }
  1314. var value = this.littleEndian
  1315. ? this.buffer.readDoubleLE(offset, true)
  1316. : this.buffer.readDoubleBE(offset, true);
  1317. if (relative) this.offset += 8;
  1318. return value;
  1319. };
  1320. /**
  1321. * Reads a 64bit float. This is an alias of {@link ByteBuffer#readFloat64}.
  1322. * @function
  1323. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
  1324. * @returns {number}
  1325. * @expose
  1326. */
  1327. ByteBufferPrototype.readDouble = ByteBufferPrototype.readFloat64;
  1328. // types/varints/varint32
  1329. /**
  1330. * Maximum number of bytes required to store a 32bit base 128 variable-length integer.
  1331. * @type {number}
  1332. * @const
  1333. * @expose
  1334. */
  1335. ByteBuffer.MAX_VARINT32_BYTES = 5;
  1336. /**
  1337. * Calculates the actual number of bytes required to store a 32bit base 128 variable-length integer.
  1338. * @param {number} value Value to encode
  1339. * @returns {number} Number of bytes required. Capped to {@link ByteBuffer.MAX_VARINT32_BYTES}
  1340. * @expose
  1341. */
  1342. ByteBuffer.calculateVarint32 = function(value) {
  1343. // ref: src/google/protobuf/io/coded_stream.cc
  1344. value = value >>> 0;
  1345. if (value < 1 << 7 ) return 1;
  1346. else if (value < 1 << 14) return 2;
  1347. else if (value < 1 << 21) return 3;
  1348. else if (value < 1 << 28) return 4;
  1349. else return 5;
  1350. };
  1351. /**
  1352. * Zigzag encodes a signed 32bit integer so that it can be effectively used with varint encoding.
  1353. * @param {number} n Signed 32bit integer
  1354. * @returns {number} Unsigned zigzag encoded 32bit integer
  1355. * @expose
  1356. */
  1357. ByteBuffer.zigZagEncode32 = function(n) {
  1358. return (((n |= 0) << 1) ^ (n >> 31)) >>> 0; // ref: src/google/protobuf/wire_format_lite.h
  1359. };
  1360. /**
  1361. * Decodes a zigzag encoded signed 32bit integer.
  1362. * @param {number} n Unsigned zigzag encoded 32bit integer
  1363. * @returns {number} Signed 32bit integer
  1364. * @expose
  1365. */
  1366. ByteBuffer.zigZagDecode32 = function(n) {
  1367. return ((n >>> 1) ^ -(n & 1)) | 0; // // ref: src/google/protobuf/wire_format_lite.h
  1368. };
  1369. /**
  1370. * Writes a 32bit base 128 variable-length integer.
  1371. * @param {number} value Value to write
  1372. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  1373. * written if omitted.
  1374. * @returns {!ByteBuffer|number} this if `offset` is omitted, else the actual number of bytes written
  1375. * @expose
  1376. */
  1377. ByteBufferPrototype.writeVarint32 = function(value, offset) {
  1378. var relative = typeof offset === 'undefined';
  1379. if (relative) offset = this.offset;
  1380. if (!this.noAssert) {
  1381. if (typeof value !== 'number' || value % 1 !== 0)
  1382. throw TypeError("Illegal value: "+value+" (not an integer)");
  1383. value |= 0;
  1384. if (typeof offset !== 'number' || offset % 1 !== 0)
  1385. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1386. offset >>>= 0;
  1387. if (offset < 0 || offset + 0 > this.buffer.length)
  1388. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  1389. }
  1390. var size = ByteBuffer.calculateVarint32(value),
  1391. b;
  1392. offset += size;
  1393. var capacity10 = this.buffer.length;
  1394. if (offset > capacity10)
  1395. this.resize((capacity10 *= 2) > offset ? capacity10 : offset);
  1396. offset -= size;
  1397. value >>>= 0;
  1398. while (value >= 0x80) {
  1399. b = (value & 0x7f) | 0x80;
  1400. this.buffer[offset++] = b;
  1401. value >>>= 7;
  1402. }
  1403. this.buffer[offset++] = value;
  1404. if (relative) {
  1405. this.offset = offset;
  1406. return this;
  1407. }
  1408. return size;
  1409. };
  1410. /**
  1411. * Writes a zig-zag encoded (signed) 32bit base 128 variable-length integer.
  1412. * @param {number} value Value to write
  1413. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  1414. * written if omitted.
  1415. * @returns {!ByteBuffer|number} this if `offset` is omitted, else the actual number of bytes written
  1416. * @expose
  1417. */
  1418. ByteBufferPrototype.writeVarint32ZigZag = function(value, offset) {
  1419. return this.writeVarint32(ByteBuffer.zigZagEncode32(value), offset);
  1420. };
  1421. /**
  1422. * Reads a 32bit base 128 variable-length integer.
  1423. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  1424. * written if omitted.
  1425. * @returns {number|!{value: number, length: number}} The value read if offset is omitted, else the value read
  1426. * and the actual number of bytes read.
  1427. * @throws {Error} If it's not a valid varint. Has a property `truncated = true` if there is not enough data available
  1428. * to fully decode the varint.
  1429. * @expose
  1430. */
  1431. ByteBufferPrototype.readVarint32 = function(offset) {
  1432. var relative = typeof offset === 'undefined';
  1433. if (relative) offset = this.offset;
  1434. if (!this.noAssert) {
  1435. if (typeof offset !== 'number' || offset % 1 !== 0)
  1436. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1437. offset >>>= 0;
  1438. if (offset < 0 || offset + 1 > this.buffer.length)
  1439. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.length);
  1440. }
  1441. var c = 0,
  1442. value = 0 >>> 0,
  1443. b;
  1444. do {
  1445. if (!this.noAssert && offset > this.limit) {
  1446. var err = Error("Truncated");
  1447. err['truncated'] = true;
  1448. throw err;
  1449. }
  1450. b = this.buffer[offset++];
  1451. if (c < 5)
  1452. value |= (b & 0x7f) << (7*c);
  1453. ++c;
  1454. } while ((b & 0x80) !== 0);
  1455. value |= 0;
  1456. if (relative) {
  1457. this.offset = offset;
  1458. return value;
  1459. }
  1460. return {
  1461. "value": value,
  1462. "length": c
  1463. };
  1464. };
  1465. /**
  1466. * Reads a zig-zag encoded (signed) 32bit base 128 variable-length integer.
  1467. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  1468. * written if omitted.
  1469. * @returns {number|!{value: number, length: number}} The value read if offset is omitted, else the value read
  1470. * and the actual number of bytes read.
  1471. * @throws {Error} If it's not a valid varint
  1472. * @expose
  1473. */
  1474. ByteBufferPrototype.readVarint32ZigZag = function(offset) {
  1475. var val = this.readVarint32(offset);
  1476. if (typeof val === 'object')
  1477. val["value"] = ByteBuffer.zigZagDecode32(val["value"]);
  1478. else
  1479. val = ByteBuffer.zigZagDecode32(val);
  1480. return val;
  1481. };
  1482. // types/varints/varint64
  1483. if (Long) {
  1484. /**
  1485. * Maximum number of bytes required to store a 64bit base 128 variable-length integer.
  1486. * @type {number}
  1487. * @const
  1488. * @expose
  1489. */
  1490. ByteBuffer.MAX_VARINT64_BYTES = 10;
  1491. /**
  1492. * Calculates the actual number of bytes required to store a 64bit base 128 variable-length integer.
  1493. * @param {number|!Long} value Value to encode
  1494. * @returns {number} Number of bytes required. Capped to {@link ByteBuffer.MAX_VARINT64_BYTES}
  1495. * @expose
  1496. */
  1497. ByteBuffer.calculateVarint64 = function(value) {
  1498. if (typeof value === 'number')
  1499. value = Long.fromNumber(value);
  1500. else if (typeof value === 'string')
  1501. value = Long.fromString(value);
  1502. // ref: src/google/protobuf/io/coded_stream.cc
  1503. var part0 = value.toInt() >>> 0,
  1504. part1 = value.shiftRightUnsigned(28).toInt() >>> 0,
  1505. part2 = value.shiftRightUnsigned(56).toInt() >>> 0;
  1506. if (part2 == 0) {
  1507. if (part1 == 0) {
  1508. if (part0 < 1 << 14)
  1509. return part0 < 1 << 7 ? 1 : 2;
  1510. else
  1511. return part0 < 1 << 21 ? 3 : 4;
  1512. } else {
  1513. if (part1 < 1 << 14)
  1514. return part1 < 1 << 7 ? 5 : 6;
  1515. else
  1516. return part1 < 1 << 21 ? 7 : 8;
  1517. }
  1518. } else
  1519. return part2 < 1 << 7 ? 9 : 10;
  1520. };
  1521. /**
  1522. * Zigzag encodes a signed 64bit integer so that it can be effectively used with varint encoding.
  1523. * @param {number|!Long} value Signed long
  1524. * @returns {!Long} Unsigned zigzag encoded long
  1525. * @expose
  1526. */
  1527. ByteBuffer.zigZagEncode64 = function(value) {
  1528. if (typeof value === 'number')
  1529. value = Long.fromNumber(value, false);
  1530. else if (typeof value === 'string')
  1531. value = Long.fromString(value, false);
  1532. else if (value.unsigned !== false) value = value.toSigned();
  1533. // ref: src/google/protobuf/wire_format_lite.h
  1534. return value.shiftLeft(1).xor(value.shiftRight(63)).toUnsigned();
  1535. };
  1536. /**
  1537. * Decodes a zigzag encoded signed 64bit integer.
  1538. * @param {!Long|number} value Unsigned zigzag encoded long or JavaScript number
  1539. * @returns {!Long} Signed long
  1540. * @expose
  1541. */
  1542. ByteBuffer.zigZagDecode64 = function(value) {
  1543. if (typeof value === 'number')
  1544. value = Long.fromNumber(value, false);
  1545. else if (typeof value === 'string')
  1546. value = Long.fromString(value, false);
  1547. else if (value.unsigned !== false) value = value.toSigned();
  1548. // ref: src/google/protobuf/wire_format_lite.h
  1549. return value.shiftRightUnsigned(1).xor(value.and(Long.ONE).toSigned().negate()).toSigned();
  1550. };
  1551. /**
  1552. * Writes a 64bit base 128 variable-length integer.
  1553. * @param {number|Long} value Value to write
  1554. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  1555. * written if omitted.
  1556. * @returns {!ByteBuffer|number} `this` if offset is omitted, else the actual number of bytes written.
  1557. * @expose
  1558. */
  1559. ByteBufferPrototype.writeVarint64 = function(value, offset) {
  1560. var relative = typeof offset === 'undefined';
  1561. if (relative) offset = this.offset;
  1562. if (!this.noAssert) {
  1563. if (typeof value === 'number')
  1564. value = Long.fromNumber(value);
  1565. else if (typeof value === 'string')
  1566. value = Long.fromString(value);
  1567. else if (!(value && value instanceof Long))
  1568. throw TypeError("Illegal value: "+value+" (not an integer or Long)");
  1569. if (typeof offset !== 'number' || offset % 1 !== 0)
  1570. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1571. offset >>>= 0;
  1572. if (offset < 0 || offset + 0 > this.buffer.length)
  1573. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  1574. }
  1575. if (typeof value === 'number')
  1576. value = Long.fromNumber(value, false);
  1577. else if (typeof value === 'string')
  1578. value = Long.fromString(value, false);
  1579. else if (value.unsigned !== false) value = value.toSigned();
  1580. var size = ByteBuffer.calculateVarint64(value),
  1581. part0 = value.toInt() >>> 0,
  1582. part1 = value.shiftRightUnsigned(28).toInt() >>> 0,
  1583. part2 = value.shiftRightUnsigned(56).toInt() >>> 0;
  1584. offset += size;
  1585. var capacity11 = this.buffer.length;
  1586. if (offset > capacity11)
  1587. this.resize((capacity11 *= 2) > offset ? capacity11 : offset);
  1588. offset -= size;
  1589. switch (size) {
  1590. case 10: this.buffer[offset+9] = (part2 >>> 7) & 0x01;
  1591. case 9 : this.buffer[offset+8] = size !== 9 ? (part2 ) | 0x80 : (part2 ) & 0x7F;
  1592. case 8 : this.buffer[offset+7] = size !== 8 ? (part1 >>> 21) | 0x80 : (part1 >>> 21) & 0x7F;
  1593. case 7 : this.buffer[offset+6] = size !== 7 ? (part1 >>> 14) | 0x80 : (part1 >>> 14) & 0x7F;
  1594. case 6 : this.buffer[offset+5] = size !== 6 ? (part1 >>> 7) | 0x80 : (part1 >>> 7) & 0x7F;
  1595. case 5 : this.buffer[offset+4] = size !== 5 ? (part1 ) | 0x80 : (part1 ) & 0x7F;
  1596. case 4 : this.buffer[offset+3] = size !== 4 ? (part0 >>> 21) | 0x80 : (part0 >>> 21) & 0x7F;
  1597. case 3 : this.buffer[offset+2] = size !== 3 ? (part0 >>> 14) | 0x80 : (part0 >>> 14) & 0x7F;
  1598. case 2 : this.buffer[offset+1] = size !== 2 ? (part0 >>> 7) | 0x80 : (part0 >>> 7) & 0x7F;
  1599. case 1 : this.buffer[offset ] = size !== 1 ? (part0 ) | 0x80 : (part0 ) & 0x7F;
  1600. }
  1601. if (relative) {
  1602. this.offset += size;
  1603. return this;
  1604. } else {
  1605. return size;
  1606. }
  1607. };
  1608. /**
  1609. * Writes a zig-zag encoded 64bit base 128 variable-length integer.
  1610. * @param {number|Long} value Value to write
  1611. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  1612. * written if omitted.
  1613. * @returns {!ByteBuffer|number} `this` if offset is omitted, else the actual number of bytes written.
  1614. * @expose
  1615. */
  1616. ByteBufferPrototype.writeVarint64ZigZag = function(value, offset) {
  1617. return this.writeVarint64(ByteBuffer.zigZagEncode64(value), offset);
  1618. };
  1619. /**
  1620. * Reads a 64bit base 128 variable-length integer. Requires Long.js.
  1621. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  1622. * read if omitted.
  1623. * @returns {!Long|!{value: Long, length: number}} The value read if offset is omitted, else the value read and
  1624. * the actual number of bytes read.
  1625. * @throws {Error} If it's not a valid varint
  1626. * @expose
  1627. */
  1628. ByteBufferPrototype.readVarint64 = function(offset) {
  1629. var relative = typeof offset === 'undefined';
  1630. if (relative) offset = this.offset;
  1631. if (!this.noAssert) {
  1632. if (typeof offset !== 'number' || offset % 1 !== 0)
  1633. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1634. offset >>>= 0;
  1635. if (offset < 0 || offset + 1 > this.buffer.length)
  1636. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.length);
  1637. }
  1638. // ref: src/google/protobuf/io/coded_stream.cc
  1639. var start = offset,
  1640. part0 = 0,
  1641. part1 = 0,
  1642. part2 = 0,
  1643. b = 0;
  1644. b = this.buffer[offset++]; part0 = (b & 0x7F) ; if ( b & 0x80 ) {
  1645. b = this.buffer[offset++]; part0 |= (b & 0x7F) << 7; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
  1646. b = this.buffer[offset++]; part0 |= (b & 0x7F) << 14; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
  1647. b = this.buffer[offset++]; part0 |= (b & 0x7F) << 21; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
  1648. b = this.buffer[offset++]; part1 = (b & 0x7F) ; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
  1649. b = this.buffer[offset++]; part1 |= (b & 0x7F) << 7; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
  1650. b = this.buffer[offset++]; part1 |= (b & 0x7F) << 14; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
  1651. b = this.buffer[offset++]; part1 |= (b & 0x7F) << 21; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
  1652. b = this.buffer[offset++]; part2 = (b & 0x7F) ; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
  1653. b = this.buffer[offset++]; part2 |= (b & 0x7F) << 7; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
  1654. throw Error("Buffer overrun"); }}}}}}}}}}
  1655. var value = Long.fromBits(part0 | (part1 << 28), (part1 >>> 4) | (part2) << 24, false);
  1656. if (relative) {
  1657. this.offset = offset;
  1658. return value;
  1659. } else {
  1660. return {
  1661. 'value': value,
  1662. 'length': offset-start
  1663. };
  1664. }
  1665. };
  1666. /**
  1667. * Reads a zig-zag encoded 64bit base 128 variable-length integer. Requires Long.js.
  1668. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  1669. * read if omitted.
  1670. * @returns {!Long|!{value: Long, length: number}} The value read if offset is omitted, else the value read and
  1671. * the actual number of bytes read.
  1672. * @throws {Error} If it's not a valid varint
  1673. * @expose
  1674. */
  1675. ByteBufferPrototype.readVarint64ZigZag = function(offset) {
  1676. var val = this.readVarint64(offset);
  1677. if (val && val['value'] instanceof Long)
  1678. val["value"] = ByteBuffer.zigZagDecode64(val["value"]);
  1679. else
  1680. val = ByteBuffer.zigZagDecode64(val);
  1681. return val;
  1682. };
  1683. } // Long
  1684. // types/strings/cstring
  1685. /**
  1686. * Writes a NULL-terminated UTF8 encoded string. For this to work the specified string must not contain any NULL
  1687. * characters itself.
  1688. * @param {string} str String to write
  1689. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  1690. * contained in `str` + 1 if omitted.
  1691. * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written
  1692. * @expose
  1693. */
  1694. ByteBufferPrototype.writeCString = function(str, offset) {
  1695. var relative = typeof offset === 'undefined';
  1696. if (relative) offset = this.offset;
  1697. var i,
  1698. k = str.length;
  1699. if (!this.noAssert) {
  1700. if (typeof str !== 'string')
  1701. throw TypeError("Illegal str: Not a string");
  1702. for (i=0; i<k; ++i) {
  1703. if (str.charCodeAt(i) === 0)
  1704. throw RangeError("Illegal str: Contains NULL-characters");
  1705. }
  1706. if (typeof offset !== 'number' || offset % 1 !== 0)
  1707. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1708. offset >>>= 0;
  1709. if (offset < 0 || offset + 0 > this.buffer.length)
  1710. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  1711. }
  1712. // UTF8 strings do not contain zero bytes in between except for the zero character, so:
  1713. k = Buffer.byteLength(str, "utf8");
  1714. offset += k+1;
  1715. var capacity12 = this.buffer.length;
  1716. if (offset > capacity12)
  1717. this.resize((capacity12 *= 2) > offset ? capacity12 : offset);
  1718. offset -= k+1;
  1719. offset += this.buffer.write(str, offset, k, "utf8");
  1720. this.buffer[offset++] = 0;
  1721. if (relative) {
  1722. this.offset = offset;
  1723. return this;
  1724. }
  1725. return k;
  1726. };
  1727. /**
  1728. * Reads a NULL-terminated UTF8 encoded string. For this to work the string read must not contain any NULL characters
  1729. * itself.
  1730. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  1731. * read if omitted.
  1732. * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string
  1733. * read and the actual number of bytes read.
  1734. * @expose
  1735. */
  1736. ByteBufferPrototype.readCString = function(offset) {
  1737. var relative = typeof offset === 'undefined';
  1738. if (relative) offset = this.offset;
  1739. if (!this.noAssert) {
  1740. if (typeof offset !== 'number' || offset % 1 !== 0)
  1741. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1742. offset >>>= 0;
  1743. if (offset < 0 || offset + 1 > this.buffer.length)
  1744. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.length);
  1745. }
  1746. var start = offset,
  1747. temp;
  1748. // UTF8 strings do not contain zero bytes in between except for the zero character itself, so:
  1749. do {
  1750. if (offset >= this.buffer.length)
  1751. throw RangeError("Index out of range: "+offset+" <= "+this.buffer.length);
  1752. temp = this.buffer[offset++];
  1753. } while (temp !== 0);
  1754. var str = this.buffer.toString("utf8", start, offset-1);
  1755. if (relative) {
  1756. this.offset = offset;
  1757. return str;
  1758. } else {
  1759. return {
  1760. "string": str,
  1761. "length": offset - start
  1762. };
  1763. }
  1764. };
  1765. // types/strings/istring
  1766. /**
  1767. * Writes a length as uint32 prefixed UTF8 encoded string.
  1768. * @param {string} str String to write
  1769. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  1770. * written if omitted.
  1771. * @returns {!ByteBuffer|number} `this` if `offset` is omitted, else the actual number of bytes written
  1772. * @expose
  1773. * @see ByteBuffer#writeVarint32
  1774. */
  1775. ByteBufferPrototype.writeIString = function(str, offset) {
  1776. var relative = typeof offset === 'undefined';
  1777. if (relative) offset = this.offset;
  1778. if (!this.noAssert) {
  1779. if (typeof str !== 'string')
  1780. throw TypeError("Illegal str: Not a string");
  1781. if (typeof offset !== 'number' || offset % 1 !== 0)
  1782. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1783. offset >>>= 0;
  1784. if (offset < 0 || offset + 0 > this.buffer.length)
  1785. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  1786. }
  1787. var start = offset,
  1788. k;
  1789. k = Buffer.byteLength(str, "utf8");
  1790. offset += 4+k;
  1791. var capacity13 = this.buffer.length;
  1792. if (offset > capacity13)
  1793. this.resize((capacity13 *= 2) > offset ? capacity13 : offset);
  1794. offset -= 4+k;
  1795. if (this.littleEndian) {
  1796. this.buffer[offset+3] = (k >>> 24) & 0xFF;
  1797. this.buffer[offset+2] = (k >>> 16) & 0xFF;
  1798. this.buffer[offset+1] = (k >>> 8) & 0xFF;
  1799. this.buffer[offset ] = k & 0xFF;
  1800. } else {
  1801. this.buffer[offset ] = (k >>> 24) & 0xFF;
  1802. this.buffer[offset+1] = (k >>> 16) & 0xFF;
  1803. this.buffer[offset+2] = (k >>> 8) & 0xFF;
  1804. this.buffer[offset+3] = k & 0xFF;
  1805. }
  1806. offset += 4;
  1807. offset += this.buffer.write(str, offset, k, "utf8");
  1808. if (relative) {
  1809. this.offset = offset;
  1810. return this;
  1811. }
  1812. return offset - start;
  1813. };
  1814. /**
  1815. * Reads a length as uint32 prefixed UTF8 encoded string.
  1816. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  1817. * read if omitted.
  1818. * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string
  1819. * read and the actual number of bytes read.
  1820. * @expose
  1821. * @see ByteBuffer#readVarint32
  1822. */
  1823. ByteBufferPrototype.readIString = function(offset) {
  1824. var relative = typeof offset === 'undefined';
  1825. if (relative) offset = this.offset;
  1826. if (!this.noAssert) {
  1827. if (typeof offset !== 'number' || offset % 1 !== 0)
  1828. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1829. offset >>>= 0;
  1830. if (offset < 0 || offset + 4 > this.buffer.length)
  1831. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.length);
  1832. }
  1833. var start = offset;
  1834. var len = this.readUint32(offset);
  1835. var str = this.readUTF8String(len, ByteBuffer.METRICS_BYTES, offset += 4);
  1836. offset += str['length'];
  1837. if (relative) {
  1838. this.offset = offset;
  1839. return str['string'];
  1840. } else {
  1841. return {
  1842. 'string': str['string'],
  1843. 'length': offset - start
  1844. };
  1845. }
  1846. };
  1847. // types/strings/utf8string
  1848. /**
  1849. * Metrics representing number of UTF8 characters. Evaluates to `c`.
  1850. * @type {string}
  1851. * @const
  1852. * @expose
  1853. */
  1854. ByteBuffer.METRICS_CHARS = 'c';
  1855. /**
  1856. * Metrics representing number of bytes. Evaluates to `b`.
  1857. * @type {string}
  1858. * @const
  1859. * @expose
  1860. */
  1861. ByteBuffer.METRICS_BYTES = 'b';
  1862. /**
  1863. * Writes an UTF8 encoded string.
  1864. * @param {string} str String to write
  1865. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} if omitted.
  1866. * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written.
  1867. * @expose
  1868. */
  1869. ByteBufferPrototype.writeUTF8String = function(str, offset) {
  1870. var relative = typeof offset === 'undefined';
  1871. if (relative) offset = this.offset;
  1872. if (!this.noAssert) {
  1873. if (typeof offset !== 'number' || offset % 1 !== 0)
  1874. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1875. offset >>>= 0;
  1876. if (offset < 0 || offset + 0 > this.buffer.length)
  1877. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  1878. }
  1879. var k;
  1880. k = Buffer.byteLength(str, "utf8");
  1881. offset += k;
  1882. var capacity14 = this.buffer.length;
  1883. if (offset > capacity14)
  1884. this.resize((capacity14 *= 2) > offset ? capacity14 : offset);
  1885. offset -= k;
  1886. offset += this.buffer.write(str, offset, k, "utf8");
  1887. if (relative) {
  1888. this.offset = offset;
  1889. return this;
  1890. }
  1891. return k;
  1892. };
  1893. /**
  1894. * Writes an UTF8 encoded string. This is an alias of {@link ByteBuffer#writeUTF8String}.
  1895. * @function
  1896. * @param {string} str String to write
  1897. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} if omitted.
  1898. * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written.
  1899. * @expose
  1900. */
  1901. ByteBufferPrototype.writeString = ByteBufferPrototype.writeUTF8String;
  1902. /**
  1903. * Calculates the number of UTF8 characters of a string. JavaScript itself uses UTF-16, so that a string's
  1904. * `length` property does not reflect its actual UTF8 size if it contains code points larger than 0xFFFF.
  1905. * @param {string} str String to calculate
  1906. * @returns {number} Number of UTF8 characters
  1907. * @expose
  1908. */
  1909. ByteBuffer.calculateUTF8Chars = function(str) {
  1910. return utfx.calculateUTF16asUTF8(stringSource(str))[0];
  1911. };
  1912. /**
  1913. * Calculates the number of UTF8 bytes of a string.
  1914. * @param {string} str String to calculate
  1915. * @returns {number} Number of UTF8 bytes
  1916. * @expose
  1917. */
  1918. ByteBuffer.calculateUTF8Bytes = function(str) {
  1919. if (typeof str !== 'string')
  1920. throw TypeError("Illegal argument: "+(typeof str));
  1921. return Buffer.byteLength(str, "utf8");
  1922. };
  1923. /**
  1924. * Calculates the number of UTF8 bytes of a string. This is an alias of {@link ByteBuffer.calculateUTF8Bytes}.
  1925. * @function
  1926. * @param {string} str String to calculate
  1927. * @returns {number} Number of UTF8 bytes
  1928. * @expose
  1929. */
  1930. ByteBuffer.calculateString = ByteBuffer.calculateUTF8Bytes;
  1931. /**
  1932. * Reads an UTF8 encoded string.
  1933. * @param {number} length Number of characters or bytes to read.
  1934. * @param {string=} metrics Metrics specifying what `length` is meant to count. Defaults to
  1935. * {@link ByteBuffer.METRICS_CHARS}.
  1936. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  1937. * read if omitted.
  1938. * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string
  1939. * read and the actual number of bytes read.
  1940. * @expose
  1941. */
  1942. ByteBufferPrototype.readUTF8String = function(length, metrics, offset) {
  1943. if (typeof metrics === 'number') {
  1944. offset = metrics;
  1945. metrics = undefined;
  1946. }
  1947. var relative = typeof offset === 'undefined';
  1948. if (relative) offset = this.offset;
  1949. if (typeof metrics === 'undefined') metrics = ByteBuffer.METRICS_CHARS;
  1950. if (!this.noAssert) {
  1951. if (typeof length !== 'number' || length % 1 !== 0)
  1952. throw TypeError("Illegal length: "+length+" (not an integer)");
  1953. length |= 0;
  1954. if (typeof offset !== 'number' || offset % 1 !== 0)
  1955. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1956. offset >>>= 0;
  1957. if (offset < 0 || offset + 0 > this.buffer.length)
  1958. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  1959. }
  1960. var i = 0,
  1961. start = offset,
  1962. temp,
  1963. sd;
  1964. if (metrics === ByteBuffer.METRICS_CHARS) { // The same for node and the browser
  1965. sd = stringDestination();
  1966. utfx.decodeUTF8(function() {
  1967. return i < length && offset < this.limit ? this.buffer[offset++] : null;
  1968. }.bind(this), function(cp) {
  1969. ++i; utfx.UTF8toUTF16(cp, sd);
  1970. });
  1971. if (i !== length)
  1972. throw RangeError("Illegal range: Truncated data, "+i+" == "+length);
  1973. if (relative) {
  1974. this.offset = offset;
  1975. return sd();
  1976. } else {
  1977. return {
  1978. "string": sd(),
  1979. "length": offset - start
  1980. };
  1981. }
  1982. } else if (metrics === ByteBuffer.METRICS_BYTES) {
  1983. if (!this.noAssert) {
  1984. if (typeof offset !== 'number' || offset % 1 !== 0)
  1985. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  1986. offset >>>= 0;
  1987. if (offset < 0 || offset + length > this.buffer.length)
  1988. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+length+") <= "+this.buffer.length);
  1989. }
  1990. temp = this.buffer.toString("utf8", offset, offset+length);
  1991. if (relative) {
  1992. this.offset += length;
  1993. return temp;
  1994. } else {
  1995. return {
  1996. 'string': temp,
  1997. 'length': length
  1998. };
  1999. }
  2000. } else
  2001. throw TypeError("Unsupported metrics: "+metrics);
  2002. };
  2003. /**
  2004. * Reads an UTF8 encoded string. This is an alias of {@link ByteBuffer#readUTF8String}.
  2005. * @function
  2006. * @param {number} length Number of characters or bytes to read
  2007. * @param {number=} metrics Metrics specifying what `n` is meant to count. Defaults to
  2008. * {@link ByteBuffer.METRICS_CHARS}.
  2009. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  2010. * read if omitted.
  2011. * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string
  2012. * read and the actual number of bytes read.
  2013. * @expose
  2014. */
  2015. ByteBufferPrototype.readString = ByteBufferPrototype.readUTF8String;
  2016. // types/strings/vstring
  2017. /**
  2018. * Writes a length as varint32 prefixed UTF8 encoded string.
  2019. * @param {string} str String to write
  2020. * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  2021. * written if omitted.
  2022. * @returns {!ByteBuffer|number} `this` if `offset` is omitted, else the actual number of bytes written
  2023. * @expose
  2024. * @see ByteBuffer#writeVarint32
  2025. */
  2026. ByteBufferPrototype.writeVString = function(str, offset) {
  2027. var relative = typeof offset === 'undefined';
  2028. if (relative) offset = this.offset;
  2029. if (!this.noAssert) {
  2030. if (typeof str !== 'string')
  2031. throw TypeError("Illegal str: Not a string");
  2032. if (typeof offset !== 'number' || offset % 1 !== 0)
  2033. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  2034. offset >>>= 0;
  2035. if (offset < 0 || offset + 0 > this.buffer.length)
  2036. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  2037. }
  2038. var start = offset,
  2039. k, l;
  2040. k = Buffer.byteLength(str, "utf8");
  2041. l = ByteBuffer.calculateVarint32(k);
  2042. offset += l+k;
  2043. var capacity15 = this.buffer.length;
  2044. if (offset > capacity15)
  2045. this.resize((capacity15 *= 2) > offset ? capacity15 : offset);
  2046. offset -= l+k;
  2047. offset += this.writeVarint32(k, offset);
  2048. offset += this.buffer.write(str, offset, k, "utf8");
  2049. if (relative) {
  2050. this.offset = offset;
  2051. return this;
  2052. }
  2053. return offset - start;
  2054. };
  2055. /**
  2056. * Reads a length as varint32 prefixed UTF8 encoded string.
  2057. * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  2058. * read if omitted.
  2059. * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string
  2060. * read and the actual number of bytes read.
  2061. * @expose
  2062. * @see ByteBuffer#readVarint32
  2063. */
  2064. ByteBufferPrototype.readVString = function(offset) {
  2065. var relative = typeof offset === 'undefined';
  2066. if (relative) offset = this.offset;
  2067. if (!this.noAssert) {
  2068. if (typeof offset !== 'number' || offset % 1 !== 0)
  2069. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  2070. offset >>>= 0;
  2071. if (offset < 0 || offset + 1 > this.buffer.length)
  2072. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.length);
  2073. }
  2074. var start = offset;
  2075. var len = this.readVarint32(offset);
  2076. var str = this.readUTF8String(len['value'], ByteBuffer.METRICS_BYTES, offset += len['length']);
  2077. offset += str['length'];
  2078. if (relative) {
  2079. this.offset = offset;
  2080. return str['string'];
  2081. } else {
  2082. return {
  2083. 'string': str['string'],
  2084. 'length': offset - start
  2085. };
  2086. }
  2087. };
  2088. /**
  2089. * Appends some data to this ByteBuffer. This will overwrite any contents behind the specified offset up to the appended
  2090. * data's length.
  2091. * @param {!ByteBuffer|!Buffer|!ArrayBuffer|!Uint8Array|string} source Data to append. If `source` is a ByteBuffer, its
  2092. * offsets will be modified according to the performed read operation.
  2093. * @param {(string|number)=} encoding Encoding if `data` is a string ("base64", "hex", "binary", defaults to "utf8")
  2094. * @param {number=} offset Offset to append at. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  2095. * written if omitted.
  2096. * @returns {!ByteBuffer} this
  2097. * @expose
  2098. * @example A relative `<01 02>03.append(<04 05>)` will result in `<01 02 04 05>, 04 05|`
  2099. * @example An absolute `<01 02>03.append(04 05>, 1)` will result in `<01 04>05, 04 05|`
  2100. */
  2101. ByteBufferPrototype.append = function(source, encoding, offset) {
  2102. if (typeof encoding === 'number' || typeof encoding !== 'string') {
  2103. offset = encoding;
  2104. encoding = undefined;
  2105. }
  2106. var relative = typeof offset === 'undefined';
  2107. if (relative) offset = this.offset;
  2108. if (!this.noAssert) {
  2109. if (typeof offset !== 'number' || offset % 1 !== 0)
  2110. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  2111. offset >>>= 0;
  2112. if (offset < 0 || offset + 0 > this.buffer.length)
  2113. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  2114. }
  2115. if (!(source instanceof ByteBuffer))
  2116. source = ByteBuffer.wrap(source, encoding);
  2117. var length = source.limit - source.offset;
  2118. if (length <= 0) return this; // Nothing to append
  2119. offset += length;
  2120. var capacity16 = this.buffer.length;
  2121. if (offset > capacity16)
  2122. this.resize((capacity16 *= 2) > offset ? capacity16 : offset);
  2123. offset -= length;
  2124. source.buffer.copy(this.buffer, offset, source.offset, source.limit);
  2125. source.offset += length;
  2126. if (relative) this.offset += length;
  2127. return this;
  2128. };
  2129. /**
  2130. * Appends this ByteBuffer's contents to another ByteBuffer. This will overwrite any contents at and after the
  2131. specified offset up to the length of this ByteBuffer's data.
  2132. * @param {!ByteBuffer} target Target ByteBuffer
  2133. * @param {number=} offset Offset to append to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  2134. * read if omitted.
  2135. * @returns {!ByteBuffer} this
  2136. * @expose
  2137. * @see ByteBuffer#append
  2138. */
  2139. ByteBufferPrototype.appendTo = function(target, offset) {
  2140. target.append(this, offset);
  2141. return this;
  2142. };
  2143. /**
  2144. * Enables or disables assertions of argument types and offsets. Assertions are enabled by default but you can opt to
  2145. * disable them if your code already makes sure that everything is valid.
  2146. * @param {boolean} assert `true` to enable assertions, otherwise `false`
  2147. * @returns {!ByteBuffer} this
  2148. * @expose
  2149. */
  2150. ByteBufferPrototype.assert = function(assert) {
  2151. this.noAssert = !assert;
  2152. return this;
  2153. };
  2154. /**
  2155. * Gets the capacity of this ByteBuffer's backing buffer.
  2156. * @returns {number} Capacity of the backing buffer
  2157. * @expose
  2158. */
  2159. ByteBufferPrototype.capacity = function() {
  2160. return this.buffer.length;
  2161. };
  2162. /**
  2163. * Clears this ByteBuffer's offsets by setting {@link ByteBuffer#offset} to `0` and {@link ByteBuffer#limit} to the
  2164. * backing buffer's capacity. Discards {@link ByteBuffer#markedOffset}.
  2165. * @returns {!ByteBuffer} this
  2166. * @expose
  2167. */
  2168. ByteBufferPrototype.clear = function() {
  2169. this.offset = 0;
  2170. this.limit = this.buffer.length;
  2171. this.markedOffset = -1;
  2172. return this;
  2173. };
  2174. /**
  2175. * Creates a cloned instance of this ByteBuffer, preset with this ByteBuffer's values for {@link ByteBuffer#offset},
  2176. * {@link ByteBuffer#markedOffset} and {@link ByteBuffer#limit}.
  2177. * @param {boolean=} copy Whether to copy the backing buffer or to return another view on the same, defaults to `false`
  2178. * @returns {!ByteBuffer} Cloned instance
  2179. * @expose
  2180. */
  2181. ByteBufferPrototype.clone = function(copy) {
  2182. var bb = new ByteBuffer(0, this.littleEndian, this.noAssert);
  2183. if (copy) {
  2184. var buffer = new Buffer(this.buffer.length);
  2185. this.buffer.copy(buffer);
  2186. bb.buffer = buffer;
  2187. } else {
  2188. bb.buffer = this.buffer;
  2189. }
  2190. bb.offset = this.offset;
  2191. bb.markedOffset = this.markedOffset;
  2192. bb.limit = this.limit;
  2193. return bb;
  2194. };
  2195. /**
  2196. * Compacts this ByteBuffer to be backed by a {@link ByteBuffer#buffer} of its contents' length. Contents are the bytes
  2197. * between {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. Will set `offset = 0` and `limit = capacity` and
  2198. * adapt {@link ByteBuffer#markedOffset} to the same relative position if set.
  2199. * @param {number=} begin Offset to start at, defaults to {@link ByteBuffer#offset}
  2200. * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit}
  2201. * @returns {!ByteBuffer} this
  2202. * @expose
  2203. */
  2204. ByteBufferPrototype.compact = function(begin, end) {
  2205. if (typeof begin === 'undefined') begin = this.offset;
  2206. if (typeof end === 'undefined') end = this.limit;
  2207. if (!this.noAssert) {
  2208. if (typeof begin !== 'number' || begin % 1 !== 0)
  2209. throw TypeError("Illegal begin: Not an integer");
  2210. begin >>>= 0;
  2211. if (typeof end !== 'number' || end % 1 !== 0)
  2212. throw TypeError("Illegal end: Not an integer");
  2213. end >>>= 0;
  2214. if (begin < 0 || begin > end || end > this.buffer.length)
  2215. throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.length);
  2216. }
  2217. if (begin === 0 && end === this.buffer.length)
  2218. return this; // Already compacted
  2219. var len = end - begin;
  2220. if (len === 0) {
  2221. this.buffer = EMPTY_BUFFER;
  2222. if (this.markedOffset >= 0) this.markedOffset -= begin;
  2223. this.offset = 0;
  2224. this.limit = 0;
  2225. return this;
  2226. }
  2227. var buffer = new Buffer(len);
  2228. this.buffer.copy(buffer, 0, begin, end);
  2229. this.buffer = buffer;
  2230. if (this.markedOffset >= 0) this.markedOffset -= begin;
  2231. this.offset = 0;
  2232. this.limit = len;
  2233. return this;
  2234. };
  2235. /**
  2236. * Creates a copy of this ByteBuffer's contents. Contents are the bytes between {@link ByteBuffer#offset} and
  2237. * {@link ByteBuffer#limit}.
  2238. * @param {number=} begin Begin offset, defaults to {@link ByteBuffer#offset}.
  2239. * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}.
  2240. * @returns {!ByteBuffer} Copy
  2241. * @expose
  2242. */
  2243. ByteBufferPrototype.copy = function(begin, end) {
  2244. if (typeof begin === 'undefined') begin = this.offset;
  2245. if (typeof end === 'undefined') end = this.limit;
  2246. if (!this.noAssert) {
  2247. if (typeof begin !== 'number' || begin % 1 !== 0)
  2248. throw TypeError("Illegal begin: Not an integer");
  2249. begin >>>= 0;
  2250. if (typeof end !== 'number' || end % 1 !== 0)
  2251. throw TypeError("Illegal end: Not an integer");
  2252. end >>>= 0;
  2253. if (begin < 0 || begin > end || end > this.buffer.length)
  2254. throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.length);
  2255. }
  2256. if (begin === end)
  2257. return new ByteBuffer(0, this.littleEndian, this.noAssert);
  2258. var capacity = end - begin,
  2259. bb = new ByteBuffer(capacity, this.littleEndian, this.noAssert);
  2260. bb.offset = 0;
  2261. bb.limit = capacity;
  2262. if (bb.markedOffset >= 0) bb.markedOffset -= begin;
  2263. this.copyTo(bb, 0, begin, end);
  2264. return bb;
  2265. };
  2266. /**
  2267. * Copies this ByteBuffer's contents to another ByteBuffer. Contents are the bytes between {@link ByteBuffer#offset} and
  2268. * {@link ByteBuffer#limit}.
  2269. * @param {!ByteBuffer} target Target ByteBuffer
  2270. * @param {number=} targetOffset Offset to copy to. Will use and increase the target's {@link ByteBuffer#offset}
  2271. * by the number of bytes copied if omitted.
  2272. * @param {number=} sourceOffset Offset to start copying from. Will use and increase {@link ByteBuffer#offset} by the
  2273. * number of bytes copied if omitted.
  2274. * @param {number=} sourceLimit Offset to end copying from, defaults to {@link ByteBuffer#limit}
  2275. * @returns {!ByteBuffer} this
  2276. * @expose
  2277. */
  2278. ByteBufferPrototype.copyTo = function(target, targetOffset, sourceOffset, sourceLimit) {
  2279. var relative,
  2280. targetRelative;
  2281. if (!this.noAssert) {
  2282. if (!ByteBuffer.isByteBuffer(target))
  2283. throw TypeError("Illegal target: Not a ByteBuffer");
  2284. }
  2285. targetOffset = (targetRelative = typeof targetOffset === 'undefined') ? target.offset : targetOffset | 0;
  2286. sourceOffset = (relative = typeof sourceOffset === 'undefined') ? this.offset : sourceOffset | 0;
  2287. sourceLimit = typeof sourceLimit === 'undefined' ? this.limit : sourceLimit | 0;
  2288. if (targetOffset < 0 || targetOffset > target.buffer.length)
  2289. throw RangeError("Illegal target range: 0 <= "+targetOffset+" <= "+target.buffer.length);
  2290. if (sourceOffset < 0 || sourceLimit > this.buffer.length)
  2291. throw RangeError("Illegal source range: 0 <= "+sourceOffset+" <= "+this.buffer.length);
  2292. var len = sourceLimit - sourceOffset;
  2293. if (len === 0)
  2294. return target; // Nothing to copy
  2295. target.ensureCapacity(targetOffset + len);
  2296. this.buffer.copy(target.buffer, targetOffset, sourceOffset, sourceLimit);
  2297. if (relative) this.offset += len;
  2298. if (targetRelative) target.offset += len;
  2299. return this;
  2300. };
  2301. /**
  2302. * Makes sure that this ByteBuffer is backed by a {@link ByteBuffer#buffer} of at least the specified capacity. If the
  2303. * current capacity is exceeded, it will be doubled. If double the current capacity is less than the required capacity,
  2304. * the required capacity will be used instead.
  2305. * @param {number} capacity Required capacity
  2306. * @returns {!ByteBuffer} this
  2307. * @expose
  2308. */
  2309. ByteBufferPrototype.ensureCapacity = function(capacity) {
  2310. var current = this.buffer.length;
  2311. if (current < capacity)
  2312. return this.resize((current *= 2) > capacity ? current : capacity);
  2313. return this;
  2314. };
  2315. /**
  2316. * Overwrites this ByteBuffer's contents with the specified value. Contents are the bytes between
  2317. * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}.
  2318. * @param {number|string} value Byte value to fill with. If given as a string, the first character is used.
  2319. * @param {number=} begin Begin offset. Will use and increase {@link ByteBuffer#offset} by the number of bytes
  2320. * written if omitted. defaults to {@link ByteBuffer#offset}.
  2321. * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}.
  2322. * @returns {!ByteBuffer} this
  2323. * @expose
  2324. * @example `someByteBuffer.clear().fill(0)` fills the entire backing buffer with zeroes
  2325. */
  2326. ByteBufferPrototype.fill = function(value, begin, end) {
  2327. var relative = typeof begin === 'undefined';
  2328. if (relative) begin = this.offset;
  2329. if (typeof value === 'string' && value.length > 0)
  2330. value = value.charCodeAt(0);
  2331. if (typeof begin === 'undefined') begin = this.offset;
  2332. if (typeof end === 'undefined') end = this.limit;
  2333. if (!this.noAssert) {
  2334. if (typeof value !== 'number' || value % 1 !== 0)
  2335. throw TypeError("Illegal value: "+value+" (not an integer)");
  2336. value |= 0;
  2337. if (typeof begin !== 'number' || begin % 1 !== 0)
  2338. throw TypeError("Illegal begin: Not an integer");
  2339. begin >>>= 0;
  2340. if (typeof end !== 'number' || end % 1 !== 0)
  2341. throw TypeError("Illegal end: Not an integer");
  2342. end >>>= 0;
  2343. if (begin < 0 || begin > end || end > this.buffer.length)
  2344. throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.length);
  2345. }
  2346. if (begin >= end)
  2347. return this; // Nothing to fill
  2348. this.buffer.fill(value, begin, end);
  2349. begin = end;
  2350. if (relative) this.offset = begin;
  2351. return this;
  2352. };
  2353. /**
  2354. * Makes this ByteBuffer ready for a new sequence of write or relative read operations. Sets `limit = offset` and
  2355. * `offset = 0`. Make sure always to flip a ByteBuffer when all relative read or write operations are complete.
  2356. * @returns {!ByteBuffer} this
  2357. * @expose
  2358. */
  2359. ByteBufferPrototype.flip = function() {
  2360. this.limit = this.offset;
  2361. this.offset = 0;
  2362. return this;
  2363. };
  2364. /**
  2365. * Marks an offset on this ByteBuffer to be used later.
  2366. * @param {number=} offset Offset to mark. Defaults to {@link ByteBuffer#offset}.
  2367. * @returns {!ByteBuffer} this
  2368. * @throws {TypeError} If `offset` is not a valid number
  2369. * @throws {RangeError} If `offset` is out of bounds
  2370. * @see ByteBuffer#reset
  2371. * @expose
  2372. */
  2373. ByteBufferPrototype.mark = function(offset) {
  2374. offset = typeof offset === 'undefined' ? this.offset : offset;
  2375. if (!this.noAssert) {
  2376. if (typeof offset !== 'number' || offset % 1 !== 0)
  2377. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  2378. offset >>>= 0;
  2379. if (offset < 0 || offset + 0 > this.buffer.length)
  2380. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  2381. }
  2382. this.markedOffset = offset;
  2383. return this;
  2384. };
  2385. /**
  2386. * Sets the byte order.
  2387. * @param {boolean} littleEndian `true` for little endian byte order, `false` for big endian
  2388. * @returns {!ByteBuffer} this
  2389. * @expose
  2390. */
  2391. ByteBufferPrototype.order = function(littleEndian) {
  2392. if (!this.noAssert) {
  2393. if (typeof littleEndian !== 'boolean')
  2394. throw TypeError("Illegal littleEndian: Not a boolean");
  2395. }
  2396. this.littleEndian = !!littleEndian;
  2397. return this;
  2398. };
  2399. /**
  2400. * Switches (to) little endian byte order.
  2401. * @param {boolean=} littleEndian Defaults to `true`, otherwise uses big endian
  2402. * @returns {!ByteBuffer} this
  2403. * @expose
  2404. */
  2405. ByteBufferPrototype.LE = function(littleEndian) {
  2406. this.littleEndian = typeof littleEndian !== 'undefined' ? !!littleEndian : true;
  2407. return this;
  2408. };
  2409. /**
  2410. * Switches (to) big endian byte order.
  2411. * @param {boolean=} bigEndian Defaults to `true`, otherwise uses little endian
  2412. * @returns {!ByteBuffer} this
  2413. * @expose
  2414. */
  2415. ByteBufferPrototype.BE = function(bigEndian) {
  2416. this.littleEndian = typeof bigEndian !== 'undefined' ? !bigEndian : false;
  2417. return this;
  2418. };
  2419. /**
  2420. * Prepends some data to this ByteBuffer. This will overwrite any contents before the specified offset up to the
  2421. * prepended data's length. If there is not enough space available before the specified `offset`, the backing buffer
  2422. * will be resized and its contents moved accordingly.
  2423. * @param {!ByteBuffer|string||!Buffer} source Data to prepend. If `source` is a ByteBuffer, its offset will be modified
  2424. * according to the performed read operation.
  2425. * @param {(string|number)=} encoding Encoding if `data` is a string ("base64", "hex", "binary", defaults to "utf8")
  2426. * @param {number=} offset Offset to prepend at. Will use and decrease {@link ByteBuffer#offset} by the number of bytes
  2427. * prepended if omitted.
  2428. * @returns {!ByteBuffer} this
  2429. * @expose
  2430. * @example A relative `00<01 02 03>.prepend(<04 05>)` results in `<04 05 01 02 03>, 04 05|`
  2431. * @example An absolute `00<01 02 03>.prepend(<04 05>, 2)` results in `04<05 02 03>, 04 05|`
  2432. */
  2433. ByteBufferPrototype.prepend = function(source, encoding, offset) {
  2434. if (typeof encoding === 'number' || typeof encoding !== 'string') {
  2435. offset = encoding;
  2436. encoding = undefined;
  2437. }
  2438. var relative = typeof offset === 'undefined';
  2439. if (relative) offset = this.offset;
  2440. if (!this.noAssert) {
  2441. if (typeof offset !== 'number' || offset % 1 !== 0)
  2442. throw TypeError("Illegal offset: "+offset+" (not an integer)");
  2443. offset >>>= 0;
  2444. if (offset < 0 || offset + 0 > this.buffer.length)
  2445. throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
  2446. }
  2447. if (!(source instanceof ByteBuffer))
  2448. source = ByteBuffer.wrap(source, encoding);
  2449. var len = source.limit - source.offset;
  2450. if (len <= 0) return this; // Nothing to prepend
  2451. var diff = len - offset;
  2452. if (diff > 0) { // Not enough space before offset, so resize + move
  2453. var buffer = new Buffer(this.buffer.length + diff);
  2454. this.buffer.copy(buffer, len, offset, this.buffer.length);
  2455. this.buffer = buffer;
  2456. this.offset += diff;
  2457. if (this.markedOffset >= 0) this.markedOffset += diff;
  2458. this.limit += diff;
  2459. offset += diff;
  2460. } source.buffer.copy(this.buffer, offset - len, source.offset, source.limit);
  2461. source.offset = source.limit;
  2462. if (relative)
  2463. this.offset -= len;
  2464. return this;
  2465. };
  2466. /**
  2467. * Prepends this ByteBuffer to another ByteBuffer. This will overwrite any contents before the specified offset up to the
  2468. * prepended data's length. If there is not enough space available before the specified `offset`, the backing buffer
  2469. * will be resized and its contents moved accordingly.
  2470. * @param {!ByteBuffer} target Target ByteBuffer
  2471. * @param {number=} offset Offset to prepend at. Will use and decrease {@link ByteBuffer#offset} by the number of bytes
  2472. * prepended if omitted.
  2473. * @returns {!ByteBuffer} this
  2474. * @expose
  2475. * @see ByteBuffer#prepend
  2476. */
  2477. ByteBufferPrototype.prependTo = function(target, offset) {
  2478. target.prepend(this, offset);
  2479. return this;
  2480. };
  2481. /**
  2482. * Prints debug information about this ByteBuffer's contents.
  2483. * @param {function(string)=} out Output function to call, defaults to console.log
  2484. * @expose
  2485. */
  2486. ByteBufferPrototype.printDebug = function(out) {
  2487. if (typeof out !== 'function') out = console.log.bind(console);
  2488. out(
  2489. this.toString()+"\n"+
  2490. "-------------------------------------------------------------------\n"+
  2491. this.toDebug(/* columns */ true)
  2492. );
  2493. };
  2494. /**
  2495. * Gets the number of remaining readable bytes. Contents are the bytes between {@link ByteBuffer#offset} and
  2496. * {@link ByteBuffer#limit}, so this returns `limit - offset`.
  2497. * @returns {number} Remaining readable bytes. May be negative if `offset > limit`.
  2498. * @expose
  2499. */
  2500. ByteBufferPrototype.remaining = function() {
  2501. return this.limit - this.offset;
  2502. };
  2503. /**
  2504. * Resets this ByteBuffer's {@link ByteBuffer#offset}. If an offset has been marked through {@link ByteBuffer#mark}
  2505. * before, `offset` will be set to {@link ByteBuffer#markedOffset}, which will then be discarded. If no offset has been
  2506. * marked, sets `offset = 0`.
  2507. * @returns {!ByteBuffer} this
  2508. * @see ByteBuffer#mark
  2509. * @expose
  2510. */
  2511. ByteBufferPrototype.reset = function() {
  2512. if (this.markedOffset >= 0) {
  2513. this.offset = this.markedOffset;
  2514. this.markedOffset = -1;
  2515. } else {
  2516. this.offset = 0;
  2517. }
  2518. return this;
  2519. };
  2520. /**
  2521. * Resizes this ByteBuffer to be backed by a buffer of at least the given capacity. Will do nothing if already that
  2522. * large or larger.
  2523. * @param {number} capacity Capacity required
  2524. * @returns {!ByteBuffer} this
  2525. * @throws {TypeError} If `capacity` is not a number
  2526. * @throws {RangeError} If `capacity < 0`
  2527. * @expose
  2528. */
  2529. ByteBufferPrototype.resize = function(capacity) {
  2530. if (!this.noAssert) {
  2531. if (typeof capacity !== 'number' || capacity % 1 !== 0)
  2532. throw TypeError("Illegal capacity: "+capacity+" (not an integer)");
  2533. capacity |= 0;
  2534. if (capacity < 0)
  2535. throw RangeError("Illegal capacity: 0 <= "+capacity);
  2536. }
  2537. if (this.buffer.length < capacity) {
  2538. var buffer = new Buffer(capacity);
  2539. this.buffer.copy(buffer);
  2540. this.buffer = buffer;
  2541. }
  2542. return this;
  2543. };
  2544. /**
  2545. * Reverses this ByteBuffer's contents.
  2546. * @param {number=} begin Offset to start at, defaults to {@link ByteBuffer#offset}
  2547. * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit}
  2548. * @returns {!ByteBuffer} this
  2549. * @expose
  2550. */
  2551. ByteBufferPrototype.reverse = function(begin, end) {
  2552. if (typeof begin === 'undefined') begin = this.offset;
  2553. if (typeof end === 'undefined') end = this.limit;
  2554. if (!this.noAssert) {
  2555. if (typeof begin !== 'number' || begin % 1 !== 0)
  2556. throw TypeError("Illegal begin: Not an integer");
  2557. begin >>>= 0;
  2558. if (typeof end !== 'number' || end % 1 !== 0)
  2559. throw TypeError("Illegal end: Not an integer");
  2560. end >>>= 0;
  2561. if (begin < 0 || begin > end || end > this.buffer.length)
  2562. throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.length);
  2563. }
  2564. if (begin === end)
  2565. return this; // Nothing to reverse
  2566. Array.prototype.reverse.call(this.buffer.slice(begin, end));
  2567. return this;
  2568. };
  2569. /**
  2570. * Skips the next `length` bytes. This will just advance
  2571. * @param {number} length Number of bytes to skip. May also be negative to move the offset back.
  2572. * @returns {!ByteBuffer} this
  2573. * @expose
  2574. */
  2575. ByteBufferPrototype.skip = function(length) {
  2576. if (!this.noAssert) {
  2577. if (typeof length !== 'number' || length % 1 !== 0)
  2578. throw TypeError("Illegal length: "+length+" (not an integer)");
  2579. length |= 0;
  2580. }
  2581. var offset = this.offset + length;
  2582. if (!this.noAssert) {
  2583. if (offset < 0 || offset > this.buffer.length)
  2584. throw RangeError("Illegal length: 0 <= "+this.offset+" + "+length+" <= "+this.buffer.length);
  2585. }
  2586. this.offset = offset;
  2587. return this;
  2588. };
  2589. /**
  2590. * Slices this ByteBuffer by creating a cloned instance with `offset = begin` and `limit = end`.
  2591. * @param {number=} begin Begin offset, defaults to {@link ByteBuffer#offset}.
  2592. * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}.
  2593. * @returns {!ByteBuffer} Clone of this ByteBuffer with slicing applied, backed by the same {@link ByteBuffer#buffer}
  2594. * @expose
  2595. */
  2596. ByteBufferPrototype.slice = function(begin, end) {
  2597. if (typeof begin === 'undefined') begin = this.offset;
  2598. if (typeof end === 'undefined') end = this.limit;
  2599. if (!this.noAssert) {
  2600. if (typeof begin !== 'number' || begin % 1 !== 0)
  2601. throw TypeError("Illegal begin: Not an integer");
  2602. begin >>>= 0;
  2603. if (typeof end !== 'number' || end % 1 !== 0)
  2604. throw TypeError("Illegal end: Not an integer");
  2605. end >>>= 0;
  2606. if (begin < 0 || begin > end || end > this.buffer.length)
  2607. throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.length);
  2608. }
  2609. var bb = this.clone();
  2610. bb.offset = begin;
  2611. bb.limit = end;
  2612. return bb;
  2613. };
  2614. /**
  2615. * Returns a copy of the backing buffer that contains this ByteBuffer's contents. Contents are the bytes between
  2616. * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}.
  2617. * @param {boolean=} forceCopy If `true` returns a copy, otherwise returns a view referencing the same memory if
  2618. * possible. Defaults to `false`
  2619. * @returns {!Buffer} Contents as a Buffer
  2620. * @expose
  2621. */
  2622. ByteBufferPrototype.toBuffer = function(forceCopy) {
  2623. var offset = this.offset,
  2624. limit = this.limit;
  2625. if (!this.noAssert) {
  2626. if (typeof offset !== 'number' || offset % 1 !== 0)
  2627. throw TypeError("Illegal offset: Not an integer");
  2628. offset >>>= 0;
  2629. if (typeof limit !== 'number' || limit % 1 !== 0)
  2630. throw TypeError("Illegal limit: Not an integer");
  2631. limit >>>= 0;
  2632. if (offset < 0 || offset > limit || limit > this.buffer.length)
  2633. throw RangeError("Illegal range: 0 <= "+offset+" <= "+limit+" <= "+this.buffer.length);
  2634. }
  2635. if (forceCopy) {
  2636. var buffer = new Buffer(limit - offset);
  2637. this.buffer.copy(buffer, 0, offset, limit);
  2638. return buffer;
  2639. } else {
  2640. if (offset === 0 && limit === this.buffer.length)
  2641. return this.buffer;
  2642. else
  2643. return this.buffer.slice(offset, limit);
  2644. }
  2645. };
  2646. /**
  2647. * Returns a copy of the backing buffer compacted to contain this ByteBuffer's contents. Contents are the bytes between
  2648. * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}.
  2649. * @returns {!ArrayBuffer} Contents as an ArrayBuffer
  2650. */
  2651. ByteBufferPrototype.toArrayBuffer = function() {
  2652. var offset = this.offset,
  2653. limit = this.limit;
  2654. if (!this.noAssert) {
  2655. if (typeof offset !== 'number' || offset % 1 !== 0)
  2656. throw TypeError("Illegal offset: Not an integer");
  2657. offset >>>= 0;
  2658. if (typeof limit !== 'number' || limit % 1 !== 0)
  2659. throw TypeError("Illegal limit: Not an integer");
  2660. limit >>>= 0;
  2661. if (offset < 0 || offset > limit || limit > this.buffer.length)
  2662. throw RangeError("Illegal range: 0 <= "+offset+" <= "+limit+" <= "+this.buffer.length);
  2663. }
  2664. var ab = new ArrayBuffer(limit - offset);
  2665. if (memcpy) { // Fast
  2666. memcpy(ab, 0, this.buffer, offset, limit);
  2667. } else { // Slow
  2668. var dst = new Uint8Array(ab);
  2669. for (var i=offset; i<limit; ++i)
  2670. dst[i-offset] = this.buffer[i];
  2671. }
  2672. return ab;
  2673. };
  2674. /**
  2675. * Converts the ByteBuffer's contents to a string.
  2676. * @param {string=} encoding Output encoding. Returns an informative string representation if omitted but also allows
  2677. * direct conversion to "utf8", "hex", "base64" and "binary" encoding. "debug" returns a hex representation with
  2678. * highlighted offsets.
  2679. * @param {number=} begin Offset to begin at, defaults to {@link ByteBuffer#offset}
  2680. * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit}
  2681. * @returns {string} String representation
  2682. * @throws {Error} If `encoding` is invalid
  2683. * @expose
  2684. */
  2685. ByteBufferPrototype.toString = function(encoding, begin, end) {
  2686. if (typeof encoding === 'undefined')
  2687. return "ByteBufferNB(offset="+this.offset+",markedOffset="+this.markedOffset+",limit="+this.limit+",capacity="+this.capacity()+")";
  2688. if (typeof encoding === 'number')
  2689. encoding = "utf8",
  2690. begin = encoding,
  2691. end = begin;
  2692. switch (encoding) {
  2693. case "utf8":
  2694. return this.toUTF8(begin, end);
  2695. case "base64":
  2696. return this.toBase64(begin, end);
  2697. case "hex":
  2698. return this.toHex(begin, end);
  2699. case "binary":
  2700. return this.toBinary(begin, end);
  2701. case "debug":
  2702. return this.toDebug();
  2703. case "columns":
  2704. return this.toColumns();
  2705. default:
  2706. throw Error("Unsupported encoding: "+encoding);
  2707. }
  2708. };
  2709. // encodings/base64
  2710. /**
  2711. * Encodes this ByteBuffer's contents to a base64 encoded string.
  2712. * @param {number=} begin Offset to begin at, defaults to {@link ByteBuffer#offset}.
  2713. * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit}.
  2714. * @returns {string} Base64 encoded string
  2715. * @throws {RangeError} If `begin` or `end` is out of bounds
  2716. * @expose
  2717. */
  2718. ByteBufferPrototype.toBase64 = function(begin, end) {
  2719. if (typeof begin === 'undefined')
  2720. begin = this.offset;
  2721. if (typeof end === 'undefined')
  2722. end = this.limit;
  2723. begin = begin | 0; end = end | 0;
  2724. if (begin < 0 || end > this.capacity || begin > end)
  2725. throw RangeError("begin, end");
  2726. return this.buffer.toString("base64", begin, end);
  2727. };
  2728. /**
  2729. * Decodes a base64 encoded string to a ByteBuffer.
  2730. * @param {string} str String to decode
  2731. * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
  2732. * {@link ByteBuffer.DEFAULT_ENDIAN}.
  2733. * @returns {!ByteBuffer} ByteBuffer
  2734. * @expose
  2735. */
  2736. ByteBuffer.fromBase64 = function(str, littleEndian) {
  2737. return ByteBuffer.wrap(new Buffer(str, "base64"), littleEndian);
  2738. return bb;
  2739. };
  2740. /**
  2741. * Encodes a binary string to base64 like `window.btoa` does.
  2742. * @param {string} str Binary string
  2743. * @returns {string} Base64 encoded string
  2744. * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.btoa
  2745. * @expose
  2746. */
  2747. ByteBuffer.btoa = function(str) {
  2748. return ByteBuffer.fromBinary(str).toBase64();
  2749. };
  2750. /**
  2751. * Decodes a base64 encoded string to binary like `window.atob` does.
  2752. * @param {string} b64 Base64 encoded string
  2753. * @returns {string} Binary string
  2754. * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.atob
  2755. * @expose
  2756. */
  2757. ByteBuffer.atob = function(b64) {
  2758. return ByteBuffer.fromBase64(b64).toBinary();
  2759. };
  2760. // encodings/binary
  2761. /**
  2762. * Encodes this ByteBuffer to a binary encoded string, that is using only characters 0x00-0xFF as bytes.
  2763. * @param {number=} begin Offset to begin at. Defaults to {@link ByteBuffer#offset}.
  2764. * @param {number=} end Offset to end at. Defaults to {@link ByteBuffer#limit}.
  2765. * @returns {string} Binary encoded string
  2766. * @throws {RangeError} If `offset > limit`
  2767. * @expose
  2768. */
  2769. ByteBufferPrototype.toBinary = function(begin, end) {
  2770. if (typeof begin === 'undefined')
  2771. begin = this.offset;
  2772. if (typeof end === 'undefined')
  2773. end = this.limit;
  2774. begin |= 0; end |= 0;
  2775. if (begin < 0 || end > this.capacity() || begin > end)
  2776. throw RangeError("begin, end");
  2777. return this.buffer.toString("binary", begin, end);
  2778. };
  2779. /**
  2780. * Decodes a binary encoded string, that is using only characters 0x00-0xFF as bytes, to a ByteBuffer.
  2781. * @param {string} str String to decode
  2782. * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
  2783. * {@link ByteBuffer.DEFAULT_ENDIAN}.
  2784. * @returns {!ByteBuffer} ByteBuffer
  2785. * @expose
  2786. */
  2787. ByteBuffer.fromBinary = function(str, littleEndian) {
  2788. return ByteBuffer.wrap(new Buffer(str, "binary"), littleEndian);
  2789. return bb;
  2790. };
  2791. // encodings/debug
  2792. /**
  2793. * Encodes this ByteBuffer to a hex encoded string with marked offsets. Offset symbols are:
  2794. * * `<` : offset,
  2795. * * `'` : markedOffset,
  2796. * * `>` : limit,
  2797. * * `|` : offset and limit,
  2798. * * `[` : offset and markedOffset,
  2799. * * `]` : markedOffset and limit,
  2800. * * `!` : offset, markedOffset and limit
  2801. * @param {boolean=} columns If `true` returns two columns hex + ascii, defaults to `false`
  2802. * @returns {string|!Array.<string>} Debug string or array of lines if `asArray = true`
  2803. * @expose
  2804. * @example `>00'01 02<03` contains four bytes with `limit=0, markedOffset=1, offset=3`
  2805. * @example `00[01 02 03>` contains four bytes with `offset=markedOffset=1, limit=4`
  2806. * @example `00|01 02 03` contains four bytes with `offset=limit=1, markedOffset=-1`
  2807. * @example `|` contains zero bytes with `offset=limit=0, markedOffset=-1`
  2808. */
  2809. ByteBufferPrototype.toDebug = function(columns) {
  2810. var i = -1,
  2811. k = this.buffer.length,
  2812. b,
  2813. hex = "",
  2814. asc = "",
  2815. out = "";
  2816. while (i<k) {
  2817. if (i !== -1) {
  2818. b = this.buffer[i];
  2819. if (b < 0x10) hex += "0"+b.toString(16).toUpperCase();
  2820. else hex += b.toString(16).toUpperCase();
  2821. if (columns)
  2822. asc += b > 32 && b < 127 ? String.fromCharCode(b) : '.';
  2823. }
  2824. ++i;
  2825. if (columns) {
  2826. if (i > 0 && i % 16 === 0 && i !== k) {
  2827. while (hex.length < 3*16+3) hex += " ";
  2828. out += hex+asc+"\n";
  2829. hex = asc = "";
  2830. }
  2831. }
  2832. if (i === this.offset && i === this.limit)
  2833. hex += i === this.markedOffset ? "!" : "|";
  2834. else if (i === this.offset)
  2835. hex += i === this.markedOffset ? "[" : "<";
  2836. else if (i === this.limit)
  2837. hex += i === this.markedOffset ? "]" : ">";
  2838. else
  2839. hex += i === this.markedOffset ? "'" : (columns || (i !== 0 && i !== k) ? " " : "");
  2840. }
  2841. if (columns && hex !== " ") {
  2842. while (hex.length < 3*16+3)
  2843. hex += " ";
  2844. out += hex + asc + "\n";
  2845. }
  2846. return columns ? out : hex;
  2847. };
  2848. /**
  2849. * Decodes a hex encoded string with marked offsets to a ByteBuffer.
  2850. * @param {string} str Debug string to decode (not be generated with `columns = true`)
  2851. * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
  2852. * {@link ByteBuffer.DEFAULT_ENDIAN}.
  2853. * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to
  2854. * {@link ByteBuffer.DEFAULT_NOASSERT}.
  2855. * @returns {!ByteBuffer} ByteBuffer
  2856. * @expose
  2857. * @see ByteBuffer#toDebug
  2858. */
  2859. ByteBuffer.fromDebug = function(str, littleEndian, noAssert) {
  2860. var k = str.length,
  2861. bb = new ByteBuffer(((k+1)/3)|0, littleEndian, noAssert);
  2862. var i = 0, j = 0, ch, b,
  2863. rs = false, // Require symbol next
  2864. ho = false, hm = false, hl = false, // Already has offset (ho), markedOffset (hm), limit (hl)?
  2865. fail = false;
  2866. while (i<k) {
  2867. switch (ch = str.charAt(i++)) {
  2868. case '!':
  2869. if (!noAssert) {
  2870. if (ho || hm || hl) {
  2871. fail = true;
  2872. break;
  2873. }
  2874. ho = hm = hl = true;
  2875. }
  2876. bb.offset = bb.markedOffset = bb.limit = j;
  2877. rs = false;
  2878. break;
  2879. case '|':
  2880. if (!noAssert) {
  2881. if (ho || hl) {
  2882. fail = true;
  2883. break;
  2884. }
  2885. ho = hl = true;
  2886. }
  2887. bb.offset = bb.limit = j;
  2888. rs = false;
  2889. break;
  2890. case '[':
  2891. if (!noAssert) {
  2892. if (ho || hm) {
  2893. fail = true;
  2894. break;
  2895. }
  2896. ho = hm = true;
  2897. }
  2898. bb.offset = bb.markedOffset = j;
  2899. rs = false;
  2900. break;
  2901. case '<':
  2902. if (!noAssert) {
  2903. if (ho) {
  2904. fail = true;
  2905. break;
  2906. }
  2907. ho = true;
  2908. }
  2909. bb.offset = j;
  2910. rs = false;
  2911. break;
  2912. case ']':
  2913. if (!noAssert) {
  2914. if (hl || hm) {
  2915. fail = true;
  2916. break;
  2917. }
  2918. hl = hm = true;
  2919. }
  2920. bb.limit = bb.markedOffset = j;
  2921. rs = false;
  2922. break;
  2923. case '>':
  2924. if (!noAssert) {
  2925. if (hl) {
  2926. fail = true;
  2927. break;
  2928. }
  2929. hl = true;
  2930. }
  2931. bb.limit = j;
  2932. rs = false;
  2933. break;
  2934. case "'":
  2935. if (!noAssert) {
  2936. if (hm) {
  2937. fail = true;
  2938. break;
  2939. }
  2940. hm = true;
  2941. }
  2942. bb.markedOffset = j;
  2943. rs = false;
  2944. break;
  2945. case ' ':
  2946. rs = false;
  2947. break;
  2948. default:
  2949. if (!noAssert) {
  2950. if (rs) {
  2951. fail = true;
  2952. break;
  2953. }
  2954. }
  2955. b = parseInt(ch+str.charAt(i++), 16);
  2956. if (!noAssert) {
  2957. if (isNaN(b) || b < 0 || b > 255)
  2958. throw TypeError("Illegal str: Not a debug encoded string");
  2959. }
  2960. bb.buffer[j++] = b;
  2961. rs = true;
  2962. }
  2963. if (fail)
  2964. throw TypeError("Illegal str: Invalid symbol at "+i);
  2965. }
  2966. if (!noAssert) {
  2967. if (!ho || !hl)
  2968. throw TypeError("Illegal str: Missing offset or limit");
  2969. if (j<bb.buffer.length)
  2970. throw TypeError("Illegal str: Not a debug encoded string (is it hex?) "+j+" < "+k);
  2971. }
  2972. return bb;
  2973. };
  2974. // encodings/hex
  2975. /**
  2976. * Encodes this ByteBuffer's contents to a hex encoded string.
  2977. * @param {number=} begin Offset to begin at. Defaults to {@link ByteBuffer#offset}.
  2978. * @param {number=} end Offset to end at. Defaults to {@link ByteBuffer#limit}.
  2979. * @returns {string} Hex encoded string
  2980. * @expose
  2981. */
  2982. ByteBufferPrototype.toHex = function(begin, end) {
  2983. begin = typeof begin === 'undefined' ? this.offset : begin;
  2984. end = typeof end === 'undefined' ? this.limit : end;
  2985. if (!this.noAssert) {
  2986. if (typeof begin !== 'number' || begin % 1 !== 0)
  2987. throw TypeError("Illegal begin: Not an integer");
  2988. begin >>>= 0;
  2989. if (typeof end !== 'number' || end % 1 !== 0)
  2990. throw TypeError("Illegal end: Not an integer");
  2991. end >>>= 0;
  2992. if (begin < 0 || begin > end || end > this.buffer.length)
  2993. throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.length);
  2994. }
  2995. return this.buffer.toString("hex", begin, end);
  2996. };
  2997. /**
  2998. * Decodes a hex encoded string to a ByteBuffer.
  2999. * @param {string} str String to decode
  3000. * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
  3001. * {@link ByteBuffer.DEFAULT_ENDIAN}.
  3002. * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to
  3003. * {@link ByteBuffer.DEFAULT_NOASSERT}.
  3004. * @returns {!ByteBuffer} ByteBuffer
  3005. * @expose
  3006. */
  3007. ByteBuffer.fromHex = function(str, littleEndian, noAssert) {
  3008. if (!noAssert) {
  3009. if (typeof str !== 'string')
  3010. throw TypeError("Illegal str: Not a string");
  3011. if (str.length % 2 !== 0)
  3012. throw TypeError("Illegal str: Length not a multiple of 2");
  3013. }
  3014. var bb = new ByteBuffer(0, littleEndian, true);
  3015. bb.buffer = new Buffer(str, "hex");
  3016. bb.limit = bb.buffer.length;
  3017. return bb;
  3018. };
  3019. // utfx-embeddable
  3020. /**
  3021. * utfx-embeddable (c) 2014 Daniel Wirtz <dcode@dcode.io>
  3022. * Released under the Apache License, Version 2.0
  3023. * see: https://github.com/dcodeIO/utfx for details
  3024. */
  3025. var utfx = function() {
  3026. "use strict";
  3027. /**
  3028. * utfx namespace.
  3029. * @inner
  3030. * @type {!Object.<string,*>}
  3031. */
  3032. var utfx = {};
  3033. /**
  3034. * Maximum valid code point.
  3035. * @type {number}
  3036. * @const
  3037. */
  3038. utfx.MAX_CODEPOINT = 0x10FFFF;
  3039. /**
  3040. * Encodes UTF8 code points to UTF8 bytes.
  3041. * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point
  3042. * respectively `null` if there are no more code points left or a single numeric code point.
  3043. * @param {!function(number)} dst Bytes destination as a function successively called with the next byte
  3044. */
  3045. utfx.encodeUTF8 = function(src, dst) {
  3046. var cp = null;
  3047. if (typeof src === 'number')
  3048. cp = src,
  3049. src = function() { return null; };
  3050. while (cp !== null || (cp = src()) !== null) {
  3051. if (cp < 0x80)
  3052. dst(cp&0x7F);
  3053. else if (cp < 0x800)
  3054. dst(((cp>>6)&0x1F)|0xC0),
  3055. dst((cp&0x3F)|0x80);
  3056. else if (cp < 0x10000)
  3057. dst(((cp>>12)&0x0F)|0xE0),
  3058. dst(((cp>>6)&0x3F)|0x80),
  3059. dst((cp&0x3F)|0x80);
  3060. else
  3061. dst(((cp>>18)&0x07)|0xF0),
  3062. dst(((cp>>12)&0x3F)|0x80),
  3063. dst(((cp>>6)&0x3F)|0x80),
  3064. dst((cp&0x3F)|0x80);
  3065. cp = null;
  3066. }
  3067. };
  3068. /**
  3069. * Decodes UTF8 bytes to UTF8 code points.
  3070. * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there
  3071. * are no more bytes left.
  3072. * @param {!function(number)} dst Code points destination as a function successively called with each decoded code point.
  3073. * @throws {RangeError} If a starting byte is invalid in UTF8
  3074. * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the
  3075. * remaining bytes.
  3076. */
  3077. utfx.decodeUTF8 = function(src, dst) {
  3078. var a, b, c, d, fail = function(b) {
  3079. b = b.slice(0, b.indexOf(null));
  3080. var err = Error(b.toString());
  3081. err.name = "TruncatedError";
  3082. err['bytes'] = b;
  3083. throw err;
  3084. };
  3085. while ((a = src()) !== null) {
  3086. if ((a&0x80) === 0)
  3087. dst(a);
  3088. else if ((a&0xE0) === 0xC0)
  3089. ((b = src()) === null) && fail([a, b]),
  3090. dst(((a&0x1F)<<6) | (b&0x3F));
  3091. else if ((a&0xF0) === 0xE0)
  3092. ((b=src()) === null || (c=src()) === null) && fail([a, b, c]),
  3093. dst(((a&0x0F)<<12) | ((b&0x3F)<<6) | (c&0x3F));
  3094. else if ((a&0xF8) === 0xF0)
  3095. ((b=src()) === null || (c=src()) === null || (d=src()) === null) && fail([a, b, c ,d]),
  3096. dst(((a&0x07)<<18) | ((b&0x3F)<<12) | ((c&0x3F)<<6) | (d&0x3F));
  3097. else throw RangeError("Illegal starting byte: "+a);
  3098. }
  3099. };
  3100. /**
  3101. * Converts UTF16 characters to UTF8 code points.
  3102. * @param {!function():number|null} src Characters source as a function returning the next char code respectively
  3103. * `null` if there are no more characters left.
  3104. * @param {!function(number)} dst Code points destination as a function successively called with each converted code
  3105. * point.
  3106. */
  3107. utfx.UTF16toUTF8 = function(src, dst) {
  3108. var c1, c2 = null;
  3109. while (true) {
  3110. if ((c1 = c2 !== null ? c2 : src()) === null)
  3111. break;
  3112. if (c1 >= 0xD800 && c1 <= 0xDFFF) {
  3113. if ((c2 = src()) !== null) {
  3114. if (c2 >= 0xDC00 && c2 <= 0xDFFF) {
  3115. dst((c1-0xD800)*0x400+c2-0xDC00+0x10000);
  3116. c2 = null; continue;
  3117. }
  3118. }
  3119. }
  3120. dst(c1);
  3121. }
  3122. if (c2 !== null) dst(c2);
  3123. };
  3124. /**
  3125. * Converts UTF8 code points to UTF16 characters.
  3126. * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point
  3127. * respectively `null` if there are no more code points left or a single numeric code point.
  3128. * @param {!function(number)} dst Characters destination as a function successively called with each converted char code.
  3129. * @throws {RangeError} If a code point is out of range
  3130. */
  3131. utfx.UTF8toUTF16 = function(src, dst) {
  3132. var cp = null;
  3133. if (typeof src === 'number')
  3134. cp = src, src = function() { return null; };
  3135. while (cp !== null || (cp = src()) !== null) {
  3136. if (cp <= 0xFFFF)
  3137. dst(cp);
  3138. else
  3139. cp -= 0x10000,
  3140. dst((cp>>10)+0xD800),
  3141. dst((cp%0x400)+0xDC00);
  3142. cp = null;
  3143. }
  3144. };
  3145. /**
  3146. * Converts and encodes UTF16 characters to UTF8 bytes.
  3147. * @param {!function():number|null} src Characters source as a function returning the next char code respectively `null`
  3148. * if there are no more characters left.
  3149. * @param {!function(number)} dst Bytes destination as a function successively called with the next byte.
  3150. */
  3151. utfx.encodeUTF16toUTF8 = function(src, dst) {
  3152. utfx.UTF16toUTF8(src, function(cp) {
  3153. utfx.encodeUTF8(cp, dst);
  3154. });
  3155. };
  3156. /**
  3157. * Decodes and converts UTF8 bytes to UTF16 characters.
  3158. * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there
  3159. * are no more bytes left.
  3160. * @param {!function(number)} dst Characters destination as a function successively called with each converted char code.
  3161. * @throws {RangeError} If a starting byte is invalid in UTF8
  3162. * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the remaining bytes.
  3163. */
  3164. utfx.decodeUTF8toUTF16 = function(src, dst) {
  3165. utfx.decodeUTF8(src, function(cp) {
  3166. utfx.UTF8toUTF16(cp, dst);
  3167. });
  3168. };
  3169. /**
  3170. * Calculates the byte length of an UTF8 code point.
  3171. * @param {number} cp UTF8 code point
  3172. * @returns {number} Byte length
  3173. */
  3174. utfx.calculateCodePoint = function(cp) {
  3175. return (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4;
  3176. };
  3177. /**
  3178. * Calculates the number of UTF8 bytes required to store UTF8 code points.
  3179. * @param {(!function():number|null)} src Code points source as a function returning the next code point respectively
  3180. * `null` if there are no more code points left.
  3181. * @returns {number} The number of UTF8 bytes required
  3182. */
  3183. utfx.calculateUTF8 = function(src) {
  3184. var cp, l=0;
  3185. while ((cp = src()) !== null)
  3186. l += (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4;
  3187. return l;
  3188. };
  3189. /**
  3190. * Calculates the number of UTF8 code points respectively UTF8 bytes required to store UTF16 char codes.
  3191. * @param {(!function():number|null)} src Characters source as a function returning the next char code respectively
  3192. * `null` if there are no more characters left.
  3193. * @returns {!Array.<number>} The number of UTF8 code points at index 0 and the number of UTF8 bytes required at index 1.
  3194. */
  3195. utfx.calculateUTF16asUTF8 = function(src) {
  3196. var n=0, l=0;
  3197. utfx.UTF16toUTF8(src, function(cp) {
  3198. ++n; l += (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4;
  3199. });
  3200. return [n,l];
  3201. };
  3202. return utfx;
  3203. }();
  3204. // encodings/utf8
  3205. /**
  3206. * Encodes this ByteBuffer's contents between {@link ByteBuffer#offset} and {@link ByteBuffer#limit} to an UTF8 encoded
  3207. * string.
  3208. * @returns {string} Hex encoded string
  3209. * @throws {RangeError} If `offset > limit`
  3210. * @expose
  3211. */
  3212. ByteBufferPrototype.toUTF8 = function(begin, end) {
  3213. if (typeof begin === 'undefined') begin = this.offset;
  3214. if (typeof end === 'undefined') end = this.limit;
  3215. if (!this.noAssert) {
  3216. if (typeof begin !== 'number' || begin % 1 !== 0)
  3217. throw TypeError("Illegal begin: Not an integer");
  3218. begin >>>= 0;
  3219. if (typeof end !== 'number' || end % 1 !== 0)
  3220. throw TypeError("Illegal end: Not an integer");
  3221. end >>>= 0;
  3222. if (begin < 0 || begin > end || end > this.buffer.length)
  3223. throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.length);
  3224. }
  3225. return this.buffer.toString("utf8", begin, end);
  3226. };
  3227. /**
  3228. * Decodes an UTF8 encoded string to a ByteBuffer.
  3229. * @param {string} str String to decode
  3230. * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
  3231. * {@link ByteBuffer.DEFAULT_ENDIAN}.
  3232. * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to
  3233. * {@link ByteBuffer.DEFAULT_NOASSERT}.
  3234. * @returns {!ByteBuffer} ByteBuffer
  3235. * @expose
  3236. */
  3237. ByteBuffer.fromUTF8 = function(str, littleEndian, noAssert) {
  3238. if (!noAssert)
  3239. if (typeof str !== 'string')
  3240. throw TypeError("Illegal str: Not a string");
  3241. var bb = new ByteBuffer(0, littleEndian, noAssert);
  3242. bb.buffer = new Buffer(str, "utf8");
  3243. bb.limit = bb.buffer.length;
  3244. return bb;
  3245. };
  3246. /**
  3247. * node-memcpy. This is an optional binding dependency and may not be present.
  3248. * @function
  3249. * @param {!(Buffer|ArrayBuffer|Uint8Array)} target Destination
  3250. * @param {number|!(Buffer|ArrayBuffer)} targetStart Destination start, defaults to 0.
  3251. * @param {(!(Buffer|ArrayBuffer|Uint8Array)|number)=} source Source
  3252. * @param {number=} sourceStart Source start, defaults to 0.
  3253. * @param {number=} sourceEnd Source end, defaults to capacity.
  3254. * @returns {number} Number of bytes copied
  3255. * @throws {Error} If any index is out of bounds
  3256. * @expose
  3257. */
  3258. ByteBuffer.memcpy = memcpy;
  3259. return ByteBuffer;
  3260. })();