bytebuffer.js 150 KB

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