bytebuffer.js 147 KB

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