bytebuffer-dataview.js 140 KB

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