ProtoBuf.js 195 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336
  1. /*
  2. Copyright 2013 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 ProtoBuf.js (c) 2013 Daniel Wirtz <dcode@dcode.io>
  15. * Released under the Apache License, Version 2.0
  16. * see: https://github.com/dcodeIO/ProtoBuf.js for details
  17. */
  18. (function(global) {
  19. "use strict";
  20. function init(ByteBuffer) {
  21. /**
  22. * The ProtoBuf namespace.
  23. * @exports ProtoBuf
  24. * @namespace
  25. * @expose
  26. */
  27. var ProtoBuf = {};
  28. /**
  29. * ProtoBuf.js version.
  30. * @type {string}
  31. * @const
  32. * @expose
  33. */
  34. ProtoBuf.VERSION = "3.8.0";
  35. /**
  36. * Wire types.
  37. * @type {Object.<string,number>}
  38. * @const
  39. * @expose
  40. */
  41. ProtoBuf.WIRE_TYPES = {};
  42. /**
  43. * Varint wire type.
  44. * @type {number}
  45. * @expose
  46. */
  47. ProtoBuf.WIRE_TYPES.VARINT = 0;
  48. /**
  49. * Fixed 64 bits wire type.
  50. * @type {number}
  51. * @const
  52. * @expose
  53. */
  54. ProtoBuf.WIRE_TYPES.BITS64 = 1;
  55. /**
  56. * Length delimited wire type.
  57. * @type {number}
  58. * @const
  59. * @expose
  60. */
  61. ProtoBuf.WIRE_TYPES.LDELIM = 2;
  62. /**
  63. * Start group wire type.
  64. * @type {number}
  65. * @const
  66. * @expose
  67. */
  68. ProtoBuf.WIRE_TYPES.STARTGROUP = 3;
  69. /**
  70. * End group wire type.
  71. * @type {number}
  72. * @const
  73. * @expose
  74. */
  75. ProtoBuf.WIRE_TYPES.ENDGROUP = 4;
  76. /**
  77. * Fixed 32 bits wire type.
  78. * @type {number}
  79. * @const
  80. * @expose
  81. */
  82. ProtoBuf.WIRE_TYPES.BITS32 = 5;
  83. /**
  84. * Packable wire types.
  85. * @type {!Array.<number>}
  86. * @const
  87. * @expose
  88. */
  89. ProtoBuf.PACKABLE_WIRE_TYPES = [
  90. ProtoBuf.WIRE_TYPES.VARINT,
  91. ProtoBuf.WIRE_TYPES.BITS64,
  92. ProtoBuf.WIRE_TYPES.BITS32
  93. ];
  94. /**
  95. * Types.
  96. * @dict
  97. * @type {Object.<string,{name: string, wireType: number}>}
  98. * @const
  99. * @expose
  100. */
  101. ProtoBuf.TYPES = {
  102. // According to the protobuf spec.
  103. "int32": {
  104. name: "int32",
  105. wireType: ProtoBuf.WIRE_TYPES.VARINT
  106. },
  107. "uint32": {
  108. name: "uint32",
  109. wireType: ProtoBuf.WIRE_TYPES.VARINT
  110. },
  111. "sint32": {
  112. name: "sint32",
  113. wireType: ProtoBuf.WIRE_TYPES.VARINT
  114. },
  115. "int64": {
  116. name: "int64",
  117. wireType: ProtoBuf.WIRE_TYPES.VARINT
  118. },
  119. "uint64": {
  120. name: "uint64",
  121. wireType: ProtoBuf.WIRE_TYPES.VARINT
  122. },
  123. "sint64": {
  124. name: "sint64",
  125. wireType: ProtoBuf.WIRE_TYPES.VARINT
  126. },
  127. "bool": {
  128. name: "bool",
  129. wireType: ProtoBuf.WIRE_TYPES.VARINT
  130. },
  131. "double": {
  132. name: "double",
  133. wireType: ProtoBuf.WIRE_TYPES.BITS64
  134. },
  135. "string": {
  136. name: "string",
  137. wireType: ProtoBuf.WIRE_TYPES.LDELIM
  138. },
  139. "bytes": {
  140. name: "bytes",
  141. wireType: ProtoBuf.WIRE_TYPES.LDELIM
  142. },
  143. "fixed32": {
  144. name: "fixed32",
  145. wireType: ProtoBuf.WIRE_TYPES.BITS32
  146. },
  147. "sfixed32": {
  148. name: "sfixed32",
  149. wireType: ProtoBuf.WIRE_TYPES.BITS32
  150. },
  151. "fixed64": {
  152. name: "fixed64",
  153. wireType: ProtoBuf.WIRE_TYPES.BITS64
  154. },
  155. "sfixed64": {
  156. name: "sfixed64",
  157. wireType: ProtoBuf.WIRE_TYPES.BITS64
  158. },
  159. "float": {
  160. name: "float",
  161. wireType: ProtoBuf.WIRE_TYPES.BITS32
  162. },
  163. "enum": {
  164. name: "enum",
  165. wireType: ProtoBuf.WIRE_TYPES.VARINT
  166. },
  167. "message": {
  168. name: "message",
  169. wireType: ProtoBuf.WIRE_TYPES.LDELIM
  170. },
  171. "group": {
  172. name: "group",
  173. wireType: ProtoBuf.WIRE_TYPES.STARTGROUP
  174. }
  175. };
  176. /**
  177. * Minimum field id.
  178. * @type {number}
  179. * @const
  180. * @expose
  181. */
  182. ProtoBuf.ID_MIN = 1;
  183. /**
  184. * Maximum field id.
  185. * @type {number}
  186. * @const
  187. * @expose
  188. */
  189. ProtoBuf.ID_MAX = 0x1FFFFFFF;
  190. /**
  191. * @type {!function(new: ByteBuffer, ...[*])}
  192. * @expose
  193. */
  194. ProtoBuf.ByteBuffer = ByteBuffer;
  195. /**
  196. * @type {?function(new: Long, ...[*])}
  197. * @expose
  198. */
  199. ProtoBuf.Long = ByteBuffer.Long || null;
  200. /**
  201. * If set to `true`, field names will be converted from underscore notation to camel case. Defaults to `false`.
  202. * Must be set prior to parsing.
  203. * @type {boolean}
  204. * @expose
  205. */
  206. ProtoBuf.convertFieldsToCamelCase = false;
  207. /**
  208. * By default, messages are populated with (setX, set_x) accessors for each field. This can be disabled by
  209. * setting this to `false` prior to building messages.
  210. * @type {boolean}
  211. * @expose
  212. */
  213. ProtoBuf.populateAccessors = true;
  214. /**
  215. * @alias ProtoBuf.Util
  216. * @expose
  217. */
  218. ProtoBuf.Util = (function() {
  219. "use strict";
  220. // Object.create polyfill
  221. // ref: https://developer.mozilla.org/de/docs/JavaScript/Reference/Global_Objects/Object/create
  222. if (!Object.create)
  223. /** @expose */
  224. Object.create = function (o) {
  225. if (arguments.length > 1)
  226. throw Error('Object.create polyfill only accepts the first parameter.');
  227. function F() {}
  228. F.prototype = o;
  229. return new F();
  230. };
  231. /**
  232. * ProtoBuf utilities.
  233. * @exports ProtoBuf.Util
  234. * @namespace
  235. */
  236. var Util = {};
  237. /**
  238. * Flag if running in node (fs is available) or not.
  239. * @type {boolean}
  240. * @const
  241. * @expose
  242. */
  243. Util.IS_NODE = false;
  244. try {
  245. // There is no reliable way to detect node.js as an environment, so our
  246. // best bet is to feature-detect what we actually need.
  247. Util.IS_NODE =
  248. typeof require === 'function' &&
  249. typeof require("fs").readFileSync === 'function' &&
  250. typeof require("path").resolve === 'function';
  251. } catch (e) {}
  252. /**
  253. * Constructs a XMLHttpRequest object.
  254. * @return {XMLHttpRequest}
  255. * @throws {Error} If XMLHttpRequest is not supported
  256. * @expose
  257. */
  258. Util.XHR = function() {
  259. // No dependencies please, ref: http://www.quirksmode.org/js/xmlhttp.html
  260. var XMLHttpFactories = [
  261. function () {return new XMLHttpRequest()},
  262. function () {return new ActiveXObject("Msxml2.XMLHTTP")},
  263. function () {return new ActiveXObject("Msxml3.XMLHTTP")},
  264. function () {return new ActiveXObject("Microsoft.XMLHTTP")}
  265. ];
  266. /** @type {?XMLHttpRequest} */
  267. var xhr = null;
  268. for (var i=0;i<XMLHttpFactories.length;i++) {
  269. try { xhr = XMLHttpFactories[i](); }
  270. catch (e) { continue; }
  271. break;
  272. }
  273. if (!xhr)
  274. throw Error("XMLHttpRequest is not supported");
  275. return xhr;
  276. };
  277. /**
  278. * Fetches a resource.
  279. * @param {string} path Resource path
  280. * @param {function(?string)=} callback Callback receiving the resource's contents. If omitted the resource will
  281. * be fetched synchronously. If the request failed, contents will be null.
  282. * @return {?string|undefined} Resource contents if callback is omitted (null if the request failed), else undefined.
  283. * @expose
  284. */
  285. Util.fetch = function(path, callback) {
  286. if (callback && typeof callback != 'function')
  287. callback = null;
  288. if (Util.IS_NODE) {
  289. if (callback) {
  290. require("fs").readFile(path, function(err, data) {
  291. if (err)
  292. callback(null);
  293. else
  294. callback(""+data);
  295. });
  296. } else
  297. try {
  298. return require("fs").readFileSync(path);
  299. } catch (e) {
  300. return null;
  301. }
  302. } else {
  303. var xhr = Util.XHR();
  304. xhr.open('GET', path, callback ? true : false);
  305. // xhr.setRequestHeader('User-Agent', 'XMLHTTP/1.0');
  306. xhr.setRequestHeader('Accept', 'text/plain');
  307. if (typeof xhr.overrideMimeType === 'function') xhr.overrideMimeType('text/plain');
  308. if (callback) {
  309. xhr.onreadystatechange = function() {
  310. if (xhr.readyState != 4) return;
  311. if (/* remote */ xhr.status == 200 || /* local */ (xhr.status == 0 && typeof xhr.responseText === 'string'))
  312. callback(xhr.responseText);
  313. else
  314. callback(null);
  315. };
  316. if (xhr.readyState == 4)
  317. return;
  318. xhr.send(null);
  319. } else {
  320. xhr.send(null);
  321. if (/* remote */ xhr.status == 200 || /* local */ (xhr.status == 0 && typeof xhr.responseText === 'string'))
  322. return xhr.responseText;
  323. return null;
  324. }
  325. }
  326. };
  327. /**
  328. * Tests if an object is an array.
  329. * @function
  330. * @param {*} obj Object to test
  331. * @returns {boolean} true if it is an array, else false
  332. * @expose
  333. */
  334. Util.isArray = Array.isArray || function(obj) {
  335. return Object.prototype.toString.call(obj) === "[object Array]";
  336. };
  337. return Util;
  338. })();
  339. /**
  340. * Language expressions.
  341. * @type {!Object.<string,string|!RegExp>}
  342. * @expose
  343. */
  344. ProtoBuf.Lang = {
  345. OPEN: "{",
  346. CLOSE: "}",
  347. OPTOPEN: "[",
  348. OPTCLOSE: "]",
  349. OPTEND: ",",
  350. EQUAL: "=",
  351. END: ";",
  352. STRINGOPEN: '"',
  353. STRINGCLOSE: '"',
  354. STRINGOPEN_SQ: "'",
  355. STRINGCLOSE_SQ: "'",
  356. COPTOPEN: '(',
  357. COPTCLOSE: ')',
  358. DELIM: /[\s\{\}=;\[\],'"\(\)]/g,
  359. // KEYWORD: /^(?:package|option|import|message|enum|extend|service|syntax|extensions|group)$/,
  360. RULE: /^(?:required|optional|repeated)$/,
  361. TYPE: /^(?:double|float|int32|uint32|sint32|int64|uint64|sint64|fixed32|sfixed32|fixed64|sfixed64|bool|string|bytes)$/,
  362. NAME: /^[a-zA-Z_][a-zA-Z_0-9]*$/,
  363. TYPEDEF: /^[a-zA-Z][a-zA-Z_0-9]*$/,
  364. TYPEREF: /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)+$/,
  365. FQTYPEREF: /^(?:\.[a-zA-Z][a-zA-Z_0-9]*)+$/,
  366. NUMBER: /^-?(?:[1-9][0-9]*|0|0x[0-9a-fA-F]+|0[0-7]+|([0-9]*\.[0-9]+([Ee][+-]?[0-9]+)?))$/,
  367. NUMBER_DEC: /^(?:[1-9][0-9]*|0)$/,
  368. NUMBER_HEX: /^0x[0-9a-fA-F]+$/,
  369. NUMBER_OCT: /^0[0-7]+$/,
  370. NUMBER_FLT: /^[0-9]*\.[0-9]+([Ee][+-]?[0-9]+)?$/,
  371. ID: /^(?:[1-9][0-9]*|0|0x[0-9a-fA-F]+|0[0-7]+)$/,
  372. NEGID: /^\-?(?:[1-9][0-9]*|0|0x[0-9a-fA-F]+|0[0-7]+)$/,
  373. WHITESPACE: /\s/,
  374. STRING: /['"]([^'"\\]*(\\.[^"\\]*)*)['"]/g,
  375. BOOL: /^(?:true|false)$/i
  376. };
  377. /**
  378. * @alias ProtoBuf.DotProto
  379. * @expose
  380. */
  381. ProtoBuf.DotProto = (function(ProtoBuf, Lang) {
  382. "use strict";
  383. /**
  384. * Utilities to parse .proto files.
  385. * @exports ProtoBuf.DotProto
  386. * @namespace
  387. */
  388. var DotProto = {};
  389. /**
  390. * Constructs a new Tokenizer.
  391. * @exports ProtoBuf.DotProto.Tokenizer
  392. * @class prototype tokenizer
  393. * @param {string} proto Proto to tokenize
  394. * @constructor
  395. */
  396. var Tokenizer = function(proto) {
  397. /**
  398. * Source to parse.
  399. * @type {string}
  400. * @expose
  401. */
  402. this.source = ""+proto; // In case it's a buffer
  403. /**
  404. * Current index.
  405. * @type {number}
  406. * @expose
  407. */
  408. this.index = 0;
  409. /**
  410. * Current line.
  411. * @type {number}
  412. * @expose
  413. */
  414. this.line = 1;
  415. /**
  416. * Stacked values.
  417. * @type {Array}
  418. * @expose
  419. */
  420. this.stack = [];
  421. /**
  422. * Whether currently reading a string or not.
  423. * @type {boolean}
  424. * @expose
  425. */
  426. this.readingString = false;
  427. /**
  428. * Whatever character ends the string. Either a single or double quote character.
  429. * @type {string}
  430. * @expose
  431. */
  432. this.stringEndsWith = Lang.STRINGCLOSE;
  433. };
  434. /**
  435. * @alias ProtoBuf.DotProto.Tokenizer.prototype
  436. * @inner
  437. */
  438. var TokenizerPrototype = Tokenizer.prototype;
  439. /**
  440. * Reads a string beginning at the current index.
  441. * @return {string} The string
  442. * @throws {Error} If it's not a valid string
  443. * @private
  444. */
  445. TokenizerPrototype._readString = function() {
  446. Lang.STRING.lastIndex = this.index-1; // Include the open quote
  447. var match;
  448. if ((match = Lang.STRING.exec(this.source)) !== null) {
  449. var s = match[1];
  450. this.index = Lang.STRING.lastIndex;
  451. this.stack.push(this.stringEndsWith);
  452. return s;
  453. }
  454. throw Error("Unterminated string at line "+this.line+", index "+this.index);
  455. };
  456. /**
  457. * Gets the next token and advances by one.
  458. * @return {?string} Token or `null` on EOF
  459. * @throws {Error} If it's not a valid proto file
  460. * @expose
  461. */
  462. TokenizerPrototype.next = function() {
  463. if (this.stack.length > 0)
  464. return this.stack.shift();
  465. if (this.index >= this.source.length)
  466. return null; // No more tokens
  467. if (this.readingString) {
  468. this.readingString = false;
  469. return this._readString();
  470. }
  471. var repeat, last;
  472. do {
  473. repeat = false;
  474. // Strip white spaces
  475. while (Lang.WHITESPACE.test(last = this.source.charAt(this.index))) {
  476. this.index++;
  477. if (last === "\n")
  478. this.line++;
  479. if (this.index === this.source.length)
  480. return null;
  481. }
  482. // Strip comments
  483. if (this.source.charAt(this.index) === '/') {
  484. if (this.source.charAt(++this.index) === '/') { // Single line
  485. while (this.source.charAt(this.index) !== "\n") {
  486. this.index++;
  487. if (this.index == this.source.length)
  488. return null;
  489. }
  490. this.index++;
  491. this.line++;
  492. repeat = true;
  493. } else if (this.source.charAt(this.index) === '*') { /* Block */
  494. last = '';
  495. while (last+(last=this.source.charAt(this.index)) !== '*/') {
  496. this.index++;
  497. if (last === "\n")
  498. this.line++;
  499. if (this.index === this.source.length)
  500. return null;
  501. }
  502. this.index++;
  503. repeat = true;
  504. } else
  505. throw Error("Unterminated comment at line "+this.line+": /"+this.source.charAt(this.index));
  506. }
  507. } while (repeat);
  508. if (this.index === this.source.length) return null;
  509. // Read the next token
  510. var end = this.index;
  511. Lang.DELIM.lastIndex = 0;
  512. var delim = Lang.DELIM.test(this.source.charAt(end));
  513. if (!delim) {
  514. ++end;
  515. while(end < this.source.length && !Lang.DELIM.test(this.source.charAt(end)))
  516. end++;
  517. } else
  518. ++end;
  519. var token = this.source.substring(this.index, this.index = end);
  520. if (token === Lang.STRINGOPEN)
  521. this.readingString = true,
  522. this.stringEndsWith = Lang.STRINGCLOSE;
  523. else if (token === Lang.STRINGOPEN_SQ)
  524. this.readingString = true,
  525. this.stringEndsWith = Lang.STRINGCLOSE_SQ;
  526. return token;
  527. };
  528. /**
  529. * Peeks for the next token.
  530. * @return {?string} Token or `null` on EOF
  531. * @throws {Error} If it's not a valid proto file
  532. * @expose
  533. */
  534. TokenizerPrototype.peek = function() {
  535. if (this.stack.length === 0) {
  536. var token = this.next();
  537. if (token === null)
  538. return null;
  539. this.stack.push(token);
  540. }
  541. return this.stack[0];
  542. };
  543. /**
  544. * Returns a string representation of this object.
  545. * @return {string} String representation as of "Tokenizer(index/length)"
  546. * @expose
  547. */
  548. TokenizerPrototype.toString = function() {
  549. return "Tokenizer("+this.index+"/"+this.source.length+" at line "+this.line+")";
  550. };
  551. /**
  552. * @alias ProtoBuf.DotProto.Tokenizer
  553. * @expose
  554. */
  555. DotProto.Tokenizer = Tokenizer;
  556. /**
  557. * Constructs a new Parser.
  558. * @exports ProtoBuf.DotProto.Parser
  559. * @class prototype parser
  560. * @param {string} proto Protocol source
  561. * @constructor
  562. */
  563. var Parser = function(proto) {
  564. /**
  565. * Tokenizer.
  566. * @type {ProtoBuf.DotProto.Tokenizer}
  567. * @expose
  568. */
  569. this.tn = new Tokenizer(proto);
  570. };
  571. /**
  572. * @alias ProtoBuf.DotProto.Parser.prototype
  573. * @inner
  574. */
  575. var ParserPrototype = Parser.prototype;
  576. /**
  577. * Runs the parser.
  578. * @return {{package: string|null, messages: Array.<object>, enums: Array.<object>, imports: Array.<string>, options: object<string,*>}}
  579. * @throws {Error} If the source cannot be parsed
  580. * @expose
  581. */
  582. ParserPrototype.parse = function() {
  583. var topLevel = {
  584. "name": "[ROOT]", // temporary
  585. "package": null,
  586. "messages": [],
  587. "enums": [],
  588. "imports": [],
  589. "options": {},
  590. "services": []
  591. };
  592. var token, head = true;
  593. while(token = this.tn.next()) {
  594. switch (token) {
  595. case 'package':
  596. if (!head || topLevel["package"] !== null)
  597. throw Error("Unexpected package at line "+this.tn.line);
  598. topLevel["package"] = this._parsePackage(token);
  599. break;
  600. case 'import':
  601. if (!head)
  602. throw Error("Unexpected import at line "+this.tn.line);
  603. topLevel.imports.push(this._parseImport(token));
  604. break;
  605. case 'message':
  606. this._parseMessage(topLevel, null, token);
  607. head = false;
  608. break;
  609. case 'enum':
  610. this._parseEnum(topLevel, token);
  611. head = false;
  612. break;
  613. case 'option':
  614. if (!head)
  615. throw Error("Unexpected option at line "+this.tn.line);
  616. this._parseOption(topLevel, token);
  617. break;
  618. case 'service':
  619. this._parseService(topLevel, token);
  620. break;
  621. case 'extend':
  622. this._parseExtend(topLevel, token);
  623. break;
  624. case 'syntax':
  625. this._parseIgnoredStatement(topLevel, token);
  626. break;
  627. default:
  628. throw Error("Unexpected token at line "+this.tn.line+": "+token);
  629. }
  630. }
  631. delete topLevel["name"];
  632. return topLevel;
  633. };
  634. /**
  635. * Parses a number value.
  636. * @param {string} val Number value to parse
  637. * @return {number} Number
  638. * @throws {Error} If the number value is invalid
  639. * @private
  640. */
  641. ParserPrototype._parseNumber = function(val) {
  642. var sign = 1;
  643. if (val.charAt(0) == '-')
  644. sign = -1,
  645. val = val.substring(1);
  646. if (Lang.NUMBER_DEC.test(val))
  647. return sign*parseInt(val, 10);
  648. else if (Lang.NUMBER_HEX.test(val))
  649. return sign*parseInt(val.substring(2), 16);
  650. else if (Lang.NUMBER_OCT.test(val))
  651. return sign*parseInt(val.substring(1), 8);
  652. else if (Lang.NUMBER_FLT.test(val))
  653. return sign*parseFloat(val);
  654. throw Error("Illegal number at line "+this.tn.line+": "+(sign < 0 ? '-' : '')+val);
  655. };
  656. /**
  657. * Parses a (possibly multiline) string.
  658. * @returns {string}
  659. * @private
  660. */
  661. ParserPrototype._parseString = function() {
  662. var value = "", token;
  663. do {
  664. token = this.tn.next(); // Known to be = this.tn.stringEndsWith
  665. value += this.tn.next();
  666. token = this.tn.next();
  667. if (token !== this.tn.stringEndsWith)
  668. throw Error("Illegal end of string at line "+this.tn.line+": "+token);
  669. token = this.tn.peek();
  670. } while (token === Lang.STRINGOPEN || token === Lang.STRINGOPEN_SQ);
  671. return value;
  672. };
  673. /**
  674. * Parses an ID value.
  675. * @param {string} val ID value to parse
  676. * @param {boolean=} neg Whether the ID may be negative, defaults to `false`
  677. * @returns {number} ID
  678. * @throws {Error} If the ID value is invalid
  679. * @private
  680. */
  681. ParserPrototype._parseId = function(val, neg) {
  682. var id = -1;
  683. var sign = 1;
  684. if (val.charAt(0) == '-')
  685. sign = -1,
  686. val = val.substring(1);
  687. if (Lang.NUMBER_DEC.test(val))
  688. id = parseInt(val);
  689. else if (Lang.NUMBER_HEX.test(val))
  690. id = parseInt(val.substring(2), 16);
  691. else if (Lang.NUMBER_OCT.test(val))
  692. id = parseInt(val.substring(1), 8);
  693. else
  694. throw Error("Illegal id at line "+this.tn.line+": "+(sign < 0 ? '-' : '')+val);
  695. id = (sign*id)|0; // Force to 32bit
  696. if (!neg && id < 0)
  697. throw Error("Illegal id at line "+this.tn.line+": "+(sign < 0 ? '-' : '')+val);
  698. return id;
  699. };
  700. /**
  701. * Parses the package definition.
  702. * @param {string} token Initial token
  703. * @return {string} Package name
  704. * @throws {Error} If the package definition cannot be parsed
  705. * @private
  706. */
  707. ParserPrototype._parsePackage = function(token) {
  708. token = this.tn.next();
  709. if (!Lang.TYPEREF.test(token))
  710. throw Error("Illegal package name at line "+this.tn.line+": "+token);
  711. var pkg = token;
  712. token = this.tn.next();
  713. if (token != Lang.END)
  714. throw Error("Illegal end of package at line "+this.tn.line+": "+token);
  715. return pkg;
  716. };
  717. /**
  718. * Parses an import definition.
  719. * @param {string} token Initial token
  720. * @return {string} Import file name
  721. * @throws {Error} If the import definition cannot be parsed
  722. * @private
  723. */
  724. ParserPrototype._parseImport = function(token) {
  725. token = this.tn.peek();
  726. if (token === "public")
  727. this.tn.next(),
  728. token = this.tn.peek();
  729. if (token !== Lang.STRINGOPEN && token !== Lang.STRINGOPEN_SQ)
  730. throw Error("Illegal start of import at line "+this.tn.line+": "+token);
  731. var imported = this._parseString();
  732. token = this.tn.next();
  733. if (token !== Lang.END)
  734. throw Error("Illegal end of import at line "+this.tn.line+": "+token);
  735. return imported;
  736. };
  737. /**
  738. * Parses a namespace option.
  739. * @param {Object} parent Parent definition
  740. * @param {string} token Initial token
  741. * @throws {Error} If the option cannot be parsed
  742. * @private
  743. */
  744. ParserPrototype._parseOption = function(parent, token) {
  745. token = this.tn.next();
  746. var custom = false;
  747. if (token == Lang.COPTOPEN)
  748. custom = true,
  749. token = this.tn.next();
  750. if (!Lang.TYPEREF.test(token))
  751. // we can allow options of the form google.protobuf.* since they will just get ignored anyways
  752. if (!/google\.protobuf\./.test(token))
  753. throw Error("Illegal option name in message "+parent.name+" at line "+this.tn.line+": "+token);
  754. var name = token;
  755. token = this.tn.next();
  756. if (custom) { // (my_method_option).foo, (my_method_option), some_method_option, (foo.my_option).bar
  757. if (token !== Lang.COPTCLOSE)
  758. throw Error("Illegal end in message "+parent.name+", option "+name+" at line "+this.tn.line+": "+token);
  759. name = '('+name+')';
  760. token = this.tn.next();
  761. if (Lang.FQTYPEREF.test(token))
  762. name += token,
  763. token = this.tn.next();
  764. }
  765. if (token !== Lang.EQUAL)
  766. throw Error("Illegal operator in message "+parent.name+", option "+name+" at line "+this.tn.line+": "+token);
  767. var value;
  768. token = this.tn.peek();
  769. if (token === Lang.STRINGOPEN || token === Lang.STRINGOPEN_SQ)
  770. value = this._parseString();
  771. else {
  772. this.tn.next();
  773. if (Lang.NUMBER.test(token))
  774. value = this._parseNumber(token, true);
  775. else if (Lang.BOOL.test(token))
  776. value = token === 'true';
  777. else if (Lang.TYPEREF.test(token))
  778. value = token;
  779. else
  780. throw Error("Illegal option value in message "+parent.name+", option "+name+" at line "+this.tn.line+": "+token);
  781. }
  782. token = this.tn.next();
  783. if (token !== Lang.END)
  784. throw Error("Illegal end of option in message "+parent.name+", option "+name+" at line "+this.tn.line+": "+token);
  785. parent["options"][name] = value;
  786. };
  787. /**
  788. * Parses an ignored statement of the form ['keyword', ..., ';'].
  789. * @param {Object} parent Parent definition
  790. * @param {string} keyword Initial token
  791. * @throws {Error} If the directive cannot be parsed
  792. * @private
  793. */
  794. ParserPrototype._parseIgnoredStatement = function(parent, keyword) {
  795. var token;
  796. do {
  797. token = this.tn.next();
  798. if (token === null)
  799. throw Error("Unexpected EOF in "+parent.name+", "+keyword+" at line "+this.tn.line);
  800. if (token === Lang.END)
  801. break;
  802. } while (true);
  803. };
  804. /**
  805. * Parses a service definition.
  806. * @param {Object} parent Parent definition
  807. * @param {string} token Initial token
  808. * @throws {Error} If the service cannot be parsed
  809. * @private
  810. */
  811. ParserPrototype._parseService = function(parent, token) {
  812. token = this.tn.next();
  813. if (!Lang.NAME.test(token))
  814. throw Error("Illegal service name at line "+this.tn.line+": "+token);
  815. var name = token;
  816. var svc = {
  817. "name": name,
  818. "rpc": {},
  819. "options": {}
  820. };
  821. token = this.tn.next();
  822. if (token !== Lang.OPEN)
  823. throw Error("Illegal start of service "+name+" at line "+this.tn.line+": "+token);
  824. do {
  825. token = this.tn.next();
  826. if (token === "option")
  827. this._parseOption(svc, token);
  828. else if (token === 'rpc')
  829. this._parseServiceRPC(svc, token);
  830. else if (token !== Lang.CLOSE)
  831. throw Error("Illegal type of service "+name+" at line "+this.tn.line+": "+token);
  832. } while (token !== Lang.CLOSE);
  833. parent["services"].push(svc);
  834. };
  835. /**
  836. * Parses a RPC service definition of the form ['rpc', name, (request), 'returns', (response)].
  837. * @param {Object} svc Parent definition
  838. * @param {string} token Initial token
  839. * @private
  840. */
  841. ParserPrototype._parseServiceRPC = function(svc, token) {
  842. var type = token;
  843. token = this.tn.next();
  844. if (!Lang.NAME.test(token))
  845. throw Error("Illegal method name in service "+svc["name"]+" at line "+this.tn.line+": "+token);
  846. var name = token;
  847. var method = {
  848. "request": null,
  849. "response": null,
  850. "options": {}
  851. };
  852. token = this.tn.next();
  853. if (token !== Lang.COPTOPEN)
  854. throw Error("Illegal start of request type in service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token);
  855. token = this.tn.next();
  856. if (!Lang.TYPEREF.test(token))
  857. throw Error("Illegal request type in service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token);
  858. method["request"] = token;
  859. token = this.tn.next();
  860. if (token != Lang.COPTCLOSE)
  861. throw Error("Illegal end of request type in service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token);
  862. token = this.tn.next();
  863. if (token.toLowerCase() !== "returns")
  864. throw Error("Illegal delimiter in service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token);
  865. token = this.tn.next();
  866. if (token != Lang.COPTOPEN)
  867. throw Error("Illegal start of response type in service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token);
  868. token = this.tn.next();
  869. method["response"] = token;
  870. token = this.tn.next();
  871. if (token !== Lang.COPTCLOSE)
  872. throw Error("Illegal end of response type in service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token);
  873. token = this.tn.next();
  874. if (token === Lang.OPEN) {
  875. do {
  876. token = this.tn.next();
  877. if (token === 'option')
  878. this._parseOption(method, token); // <- will fail for the custom-options example
  879. else if (token !== Lang.CLOSE)
  880. throw Error("Illegal start of option inservice "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token);
  881. } while (token !== Lang.CLOSE);
  882. if (this.tn.peek() === Lang.END)
  883. this.tn.next();
  884. } else if (token !== Lang.END)
  885. throw Error("Illegal delimiter in service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token);
  886. if (typeof svc[type] === 'undefined')
  887. svc[type] = {};
  888. svc[type][name] = method;
  889. };
  890. /**
  891. * Parses a message definition.
  892. * @param {Object} parent Parent definition
  893. * @param {Object} fld Field definition if this is a group, otherwise `null`
  894. * @param {string} token First token
  895. * @return {Object}
  896. * @throws {Error} If the message cannot be parsed
  897. * @private
  898. */
  899. ParserPrototype._parseMessage = function(parent, fld, token) {
  900. /** @dict */
  901. var msg = {}; // Note: At some point we might want to exclude the parser, so we need a dict.
  902. var isGroup = token === "group";
  903. token = this.tn.next();
  904. if (!Lang.NAME.test(token))
  905. throw Error("Illegal "+(isGroup ? "group" : "message")+" name"+(parent ? " in message "+parent["name"] : "")+" at line "+this.tn.line+": "+token);
  906. msg["name"] = token;
  907. if (isGroup) {
  908. token = this.tn.next();
  909. if (token !== Lang.EQUAL)
  910. throw Error("Illegal id assignment after group "+msg.name+" at line "+this.tn.line+": "+token);
  911. token = this.tn.next();
  912. try {
  913. fld["id"] = this._parseId(token);
  914. } catch (e) {
  915. throw Error("Illegal field id value for group "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token);
  916. }
  917. msg["isGroup"] = true;
  918. }
  919. msg["fields"] = []; // Note: Using arrays to support also browser that cannot preserve order of object keys.
  920. msg["enums"] = [];
  921. msg["messages"] = [];
  922. msg["options"] = {};
  923. msg["oneofs"] = {};
  924. token = this.tn.next();
  925. if (token === Lang.OPTOPEN && fld)
  926. this._parseFieldOptions(msg, fld, token),
  927. token = this.tn.next();
  928. if (token !== Lang.OPEN)
  929. throw Error("Illegal start of "+(isGroup ? "group" : "message")+" "+msg.name+" at line "+this.tn.line+": "+token);
  930. // msg["extensions"] = undefined
  931. do {
  932. token = this.tn.next();
  933. if (token === Lang.CLOSE) {
  934. token = this.tn.peek();
  935. if (token === Lang.END)
  936. this.tn.next();
  937. break;
  938. } else if (Lang.RULE.test(token))
  939. this._parseMessageField(msg, token);
  940. else if (token === "oneof")
  941. this._parseMessageOneOf(msg, token);
  942. else if (token === "enum")
  943. this._parseEnum(msg, token);
  944. else if (token === "message")
  945. this._parseMessage(msg, null, token);
  946. else if (token === "option")
  947. this._parseOption(msg, token);
  948. else if (token === "extensions")
  949. msg["extensions"] = this._parseExtensions(msg, token);
  950. else if (token === "extend")
  951. this._parseExtend(msg, token);
  952. else
  953. throw Error("Illegal token in message "+msg.name+" at line "+this.tn.line+": "+token);
  954. } while (true);
  955. parent["messages"].push(msg);
  956. return msg;
  957. };
  958. /**
  959. * Parses a message field.
  960. * @param {Object} msg Message definition
  961. * @param {string} token Initial token
  962. * @returns {!Object} Field descriptor
  963. * @throws {Error} If the message field cannot be parsed
  964. * @private
  965. */
  966. ParserPrototype._parseMessageField = function(msg, token) {
  967. /** @dict */
  968. var fld = {}, grp = null;
  969. fld["rule"] = token;
  970. /** @dict */
  971. fld["options"] = {};
  972. token = this.tn.next();
  973. if (token === "group") {
  974. // "A [legacy] group simply combines a nested message type and a field into a single declaration. In your
  975. // code, you can treat this message just as if it had a Result type field called result (the latter name is
  976. // converted to lower-case so that it does not conflict with the former)."
  977. grp = this._parseMessage(msg, fld, token);
  978. if (!/^[A-Z]/.test(grp["name"]))
  979. throw Error('Group names must start with a capital letter');
  980. fld["type"] = grp["name"];
  981. fld["name"] = grp["name"].toLowerCase();
  982. token = this.tn.peek();
  983. if (token === Lang.END)
  984. this.tn.next();
  985. } else {
  986. if (!Lang.TYPE.test(token) && !Lang.TYPEREF.test(token))
  987. throw Error("Illegal field type in message "+msg.name+" at line "+this.tn.line+": "+token);
  988. fld["type"] = token;
  989. token = this.tn.next();
  990. if (!Lang.NAME.test(token))
  991. throw Error("Illegal field name in message "+msg.name+" at line "+this.tn.line+": "+token);
  992. fld["name"] = token;
  993. token = this.tn.next();
  994. if (token !== Lang.EQUAL)
  995. throw Error("Illegal token in field "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token);
  996. token = this.tn.next();
  997. try {
  998. fld["id"] = this._parseId(token);
  999. } catch (e) {
  1000. throw Error("Illegal field id in message "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token);
  1001. }
  1002. token = this.tn.next();
  1003. if (token === Lang.OPTOPEN)
  1004. this._parseFieldOptions(msg, fld, token),
  1005. token = this.tn.next();
  1006. if (token !== Lang.END)
  1007. throw Error("Illegal delimiter in message "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token);
  1008. }
  1009. msg["fields"].push(fld);
  1010. return fld;
  1011. };
  1012. /**
  1013. * Parses a message oneof.
  1014. * @param {Object} msg Message definition
  1015. * @param {string} token Initial token
  1016. * @throws {Error} If the message oneof cannot be parsed
  1017. * @private
  1018. */
  1019. ParserPrototype._parseMessageOneOf = function(msg, token) {
  1020. token = this.tn.next();
  1021. if (!Lang.NAME.test(token))
  1022. throw Error("Illegal oneof name in message "+msg.name+" at line "+this.tn.line+": "+token);
  1023. var name = token,
  1024. fld;
  1025. var fields = [];
  1026. token = this.tn.next();
  1027. if (token !== Lang.OPEN)
  1028. throw Error("Illegal start of oneof "+name+" at line "+this.tn.line+": "+token);
  1029. while (this.tn.peek() !== Lang.CLOSE) {
  1030. fld = this._parseMessageField(msg, "optional");
  1031. fld["oneof"] = name;
  1032. fields.push(fld["id"]);
  1033. }
  1034. this.tn.next();
  1035. msg["oneofs"][name] = fields;
  1036. };
  1037. /**
  1038. * Parses a set of field option definitions.
  1039. * @param {Object} msg Message definition
  1040. * @param {Object} fld Field definition
  1041. * @param {string} token Initial token
  1042. * @throws {Error} If the message field options cannot be parsed
  1043. * @private
  1044. */
  1045. ParserPrototype._parseFieldOptions = function(msg, fld, token) {
  1046. var first = true;
  1047. do {
  1048. token = this.tn.next();
  1049. if (token === Lang.OPTCLOSE)
  1050. break;
  1051. else if (token === Lang.OPTEND) {
  1052. if (first)
  1053. throw Error("Illegal start of options in message "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token);
  1054. token = this.tn.next();
  1055. }
  1056. this._parseFieldOption(msg, fld, token);
  1057. first = false;
  1058. } while (true);
  1059. };
  1060. /**
  1061. * Parses a single field option.
  1062. * @param {Object} msg Message definition
  1063. * @param {Object} fld Field definition
  1064. * @param {string} token Initial token
  1065. * @throws {Error} If the mesage field option cannot be parsed
  1066. * @private
  1067. */
  1068. ParserPrototype._parseFieldOption = function(msg, fld, token) {
  1069. var custom = false;
  1070. if (token === Lang.COPTOPEN)
  1071. token = this.tn.next(),
  1072. custom = true;
  1073. if (!Lang.TYPEREF.test(token))
  1074. throw Error("Illegal field option in "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token);
  1075. var name = token;
  1076. token = this.tn.next();
  1077. if (custom) {
  1078. if (token !== Lang.COPTCLOSE)
  1079. throw Error("Illegal delimiter in "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token);
  1080. name = '('+name+')';
  1081. token = this.tn.next();
  1082. if (Lang.FQTYPEREF.test(token))
  1083. name += token,
  1084. token = this.tn.next();
  1085. }
  1086. if (token !== Lang.EQUAL)
  1087. throw Error("Illegal token in "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token);
  1088. var value;
  1089. token = this.tn.peek();
  1090. if (token === Lang.STRINGOPEN || token === Lang.STRINGOPEN_SQ) {
  1091. value = this._parseString();
  1092. } else if (Lang.NUMBER.test(token, true))
  1093. value = this._parseNumber(this.tn.next(), true);
  1094. else if (Lang.BOOL.test(token))
  1095. value = this.tn.next().toLowerCase() === 'true';
  1096. else if (Lang.TYPEREF.test(token))
  1097. value = this.tn.next(); // TODO: Resolve?
  1098. else
  1099. throw Error("Illegal value in message "+msg.name+"#"+fld.name+", option "+name+" at line "+this.tn.line+": "+token);
  1100. fld["options"][name] = value;
  1101. };
  1102. /**
  1103. * Parses an enum.
  1104. * @param {Object} msg Message definition
  1105. * @param {string} token Initial token
  1106. * @throws {Error} If the enum cannot be parsed
  1107. * @private
  1108. */
  1109. ParserPrototype._parseEnum = function(msg, token) {
  1110. /** @dict */
  1111. var enm = {};
  1112. token = this.tn.next();
  1113. if (!Lang.NAME.test(token))
  1114. throw Error("Illegal enum name in message "+msg.name+" at line "+this.tn.line+": "+token);
  1115. enm["name"] = token;
  1116. token = this.tn.next();
  1117. if (token !== Lang.OPEN)
  1118. throw Error("Illegal start of enum "+enm.name+" at line "+this.tn.line+": "+token);
  1119. enm["values"] = [];
  1120. enm["options"] = {};
  1121. do {
  1122. token = this.tn.next();
  1123. if (token === Lang.CLOSE) {
  1124. token = this.tn.peek();
  1125. if (token === Lang.END)
  1126. this.tn.next();
  1127. break;
  1128. }
  1129. if (token == 'option')
  1130. this._parseOption(enm, token);
  1131. else {
  1132. if (!Lang.NAME.test(token))
  1133. throw Error("Illegal name in enum "+enm.name+" at line "+this.tn.line+": "+token);
  1134. this._parseEnumValue(enm, token);
  1135. }
  1136. } while (true);
  1137. msg["enums"].push(enm);
  1138. };
  1139. /**
  1140. * Parses an enum value.
  1141. * @param {Object} enm Enum definition
  1142. * @param {string} token Initial token
  1143. * @throws {Error} If the enum value cannot be parsed
  1144. * @private
  1145. */
  1146. ParserPrototype._parseEnumValue = function(enm, token) {
  1147. /** @dict */
  1148. var val = {};
  1149. val["name"] = token;
  1150. token = this.tn.next();
  1151. if (token !== Lang.EQUAL)
  1152. throw Error("Illegal token in enum "+enm.name+" at line "+this.tn.line+": "+token);
  1153. token = this.tn.next();
  1154. try {
  1155. val["id"] = this._parseId(token, true);
  1156. } catch (e) {
  1157. throw Error("Illegal id in enum "+enm.name+" at line "+this.tn.line+": "+token);
  1158. }
  1159. enm["values"].push(val);
  1160. token = this.tn.next();
  1161. if (token === Lang.OPTOPEN) {
  1162. var opt = { 'options' : {} }; // TODO: Actually expose them somehow.
  1163. this._parseFieldOptions(enm, opt, token);
  1164. token = this.tn.next();
  1165. }
  1166. if (token !== Lang.END)
  1167. throw Error("Illegal delimiter in enum "+enm.name+" at line "+this.tn.line+": "+token);
  1168. };
  1169. /**
  1170. * Parses an extensions statement.
  1171. * @param {Object} msg Message object
  1172. * @param {string} token Initial token
  1173. * @throws {Error} If the extensions statement cannot be parsed
  1174. * @private
  1175. */
  1176. ParserPrototype._parseExtensions = function(msg, token) {
  1177. /** @type {Array.<number>} */
  1178. var range = [];
  1179. token = this.tn.next();
  1180. if (token === "min") // FIXME: Does the official implementation support this?
  1181. range.push(ProtoBuf.ID_MIN);
  1182. else if (token === "max")
  1183. range.push(ProtoBuf.ID_MAX);
  1184. else
  1185. range.push(this._parseNumber(token));
  1186. token = this.tn.next();
  1187. if (token !== 'to')
  1188. throw Error("Illegal extensions delimiter in message "+msg.name+" at line "+this.tn.line+": "+token);
  1189. token = this.tn.next();
  1190. if (token === "min")
  1191. range.push(ProtoBuf.ID_MIN);
  1192. else if (token === "max")
  1193. range.push(ProtoBuf.ID_MAX);
  1194. else
  1195. range.push(this._parseNumber(token));
  1196. token = this.tn.next();
  1197. if (token !== Lang.END)
  1198. throw Error("Illegal extensions delimiter in message "+msg.name+" at line "+this.tn.line+": "+token);
  1199. return range;
  1200. };
  1201. /**
  1202. * Parses an extend block.
  1203. * @param {Object} parent Parent object
  1204. * @param {string} token Initial token
  1205. * @throws {Error} If the extend block cannot be parsed
  1206. * @private
  1207. */
  1208. ParserPrototype._parseExtend = function(parent, token) {
  1209. token = this.tn.next();
  1210. if (!Lang.TYPEREF.test(token))
  1211. throw Error("Illegal message name at line "+this.tn.line+": "+token);
  1212. /** @dict */
  1213. var ext = {};
  1214. ext["ref"] = token;
  1215. ext["fields"] = [];
  1216. token = this.tn.next();
  1217. if (token !== Lang.OPEN)
  1218. throw Error("Illegal start of extend "+ext.name+" at line "+this.tn.line+": "+token);
  1219. do {
  1220. token = this.tn.next();
  1221. if (token === Lang.CLOSE) {
  1222. token = this.tn.peek();
  1223. if (token == Lang.END)
  1224. this.tn.next();
  1225. break;
  1226. } else if (Lang.RULE.test(token))
  1227. this._parseMessageField(ext, token);
  1228. else
  1229. throw Error("Illegal token in extend "+ext.name+" at line "+this.tn.line+": "+token);
  1230. } while (true);
  1231. parent["messages"].push(ext);
  1232. return ext;
  1233. };
  1234. /**
  1235. * Returns a string representation of this object.
  1236. * @returns {string} String representation as of "Parser"
  1237. */
  1238. ParserPrototype.toString = function() {
  1239. return "Parser";
  1240. };
  1241. /**
  1242. * @alias ProtoBuf.DotProto.Parser
  1243. * @expose
  1244. */
  1245. DotProto.Parser = Parser;
  1246. return DotProto;
  1247. })(ProtoBuf, ProtoBuf.Lang);
  1248. /**
  1249. * @alias ProtoBuf.Reflect
  1250. * @expose
  1251. */
  1252. ProtoBuf.Reflect = (function(ProtoBuf) {
  1253. "use strict";
  1254. /**
  1255. * Reflection types.
  1256. * @exports ProtoBuf.Reflect
  1257. * @namespace
  1258. */
  1259. var Reflect = {};
  1260. /**
  1261. * Constructs a Reflect base class.
  1262. * @exports ProtoBuf.Reflect.T
  1263. * @constructor
  1264. * @abstract
  1265. * @param {!ProtoBuf.Builder} builder Builder reference
  1266. * @param {?ProtoBuf.Reflect.T} parent Parent object
  1267. * @param {string} name Object name
  1268. */
  1269. var T = function(builder, parent, name) {
  1270. /**
  1271. * Builder reference.
  1272. * @type {!ProtoBuf.Builder}
  1273. * @expose
  1274. */
  1275. this.builder = builder;
  1276. /**
  1277. * Parent object.
  1278. * @type {?ProtoBuf.Reflect.T}
  1279. * @expose
  1280. */
  1281. this.parent = parent;
  1282. /**
  1283. * Object name in namespace.
  1284. * @type {string}
  1285. * @expose
  1286. */
  1287. this.name = name;
  1288. /**
  1289. * Fully qualified class name
  1290. * @type {string}
  1291. * @expose
  1292. */
  1293. this.className;
  1294. };
  1295. /**
  1296. * @alias ProtoBuf.Reflect.T.prototype
  1297. * @inner
  1298. */
  1299. var TPrototype = T.prototype;
  1300. /**
  1301. * Returns the fully qualified name of this object.
  1302. * @returns {string} Fully qualified name as of ".PATH.TO.THIS"
  1303. * @expose
  1304. */
  1305. TPrototype.fqn = function() {
  1306. var name = this.name,
  1307. ptr = this;
  1308. do {
  1309. ptr = ptr.parent;
  1310. if (ptr == null)
  1311. break;
  1312. name = ptr.name+"."+name;
  1313. } while (true);
  1314. return name;
  1315. };
  1316. /**
  1317. * Returns a string representation of this Reflect object (its fully qualified name).
  1318. * @param {boolean=} includeClass Set to true to include the class name. Defaults to false.
  1319. * @return String representation
  1320. * @expose
  1321. */
  1322. TPrototype.toString = function(includeClass) {
  1323. return (includeClass ? this.className + " " : "") + this.fqn();
  1324. };
  1325. /**
  1326. * Builds this type.
  1327. * @throws {Error} If this type cannot be built directly
  1328. * @expose
  1329. */
  1330. TPrototype.build = function() {
  1331. throw Error(this.toString(true)+" cannot be built directly");
  1332. };
  1333. /**
  1334. * @alias ProtoBuf.Reflect.T
  1335. * @expose
  1336. */
  1337. Reflect.T = T;
  1338. /**
  1339. * Constructs a new Namespace.
  1340. * @exports ProtoBuf.Reflect.Namespace
  1341. * @param {!ProtoBuf.Builder} builder Builder reference
  1342. * @param {?ProtoBuf.Reflect.Namespace} parent Namespace parent
  1343. * @param {string} name Namespace name
  1344. * @param {Object.<string,*>=} options Namespace options
  1345. * @constructor
  1346. * @extends ProtoBuf.Reflect.T
  1347. */
  1348. var Namespace = function(builder, parent, name, options) {
  1349. T.call(this, builder, parent, name);
  1350. /**
  1351. * @override
  1352. */
  1353. this.className = "Namespace";
  1354. /**
  1355. * Children inside the namespace.
  1356. * @type {!Array.<ProtoBuf.Reflect.T>}
  1357. */
  1358. this.children = [];
  1359. /**
  1360. * Options.
  1361. * @type {!Object.<string, *>}
  1362. */
  1363. this.options = options || {};
  1364. };
  1365. /**
  1366. * @alias ProtoBuf.Reflect.Namespace.prototype
  1367. * @inner
  1368. */
  1369. var NamespacePrototype = Namespace.prototype = Object.create(T.prototype);
  1370. /**
  1371. * Returns an array of the namespace's children.
  1372. * @param {ProtoBuf.Reflect.T=} type Filter type (returns instances of this type only). Defaults to null (all children).
  1373. * @return {Array.<ProtoBuf.Reflect.T>}
  1374. * @expose
  1375. */
  1376. NamespacePrototype.getChildren = function(type) {
  1377. type = type || null;
  1378. if (type == null)
  1379. return this.children.slice();
  1380. var children = [];
  1381. for (var i=0, k=this.children.length; i<k; ++i)
  1382. if (this.children[i] instanceof type)
  1383. children.push(this.children[i]);
  1384. return children;
  1385. };
  1386. /**
  1387. * Adds a child to the namespace.
  1388. * @param {ProtoBuf.Reflect.T} child Child
  1389. * @throws {Error} If the child cannot be added (duplicate)
  1390. * @expose
  1391. */
  1392. NamespacePrototype.addChild = function(child) {
  1393. var other;
  1394. if (other = this.getChild(child.name)) {
  1395. // Try to revert camelcase transformation on collision
  1396. if (other instanceof Message.Field && other.name !== other.originalName && this.getChild(other.originalName) === null)
  1397. other.name = other.originalName; // Revert previous first (effectively keeps both originals)
  1398. else if (child instanceof Message.Field && child.name !== child.originalName && this.getChild(child.originalName) === null)
  1399. child.name = child.originalName;
  1400. else
  1401. throw Error("Duplicate name in namespace "+this.toString(true)+": "+child.name);
  1402. }
  1403. this.children.push(child);
  1404. };
  1405. /**
  1406. * Gets a child by its name or id.
  1407. * @param {string|number} nameOrId Child name or id
  1408. * @return {?ProtoBuf.Reflect.T} The child or null if not found
  1409. * @expose
  1410. */
  1411. NamespacePrototype.getChild = function(nameOrId) {
  1412. var key = typeof nameOrId === 'number' ? 'id' : 'name';
  1413. for (var i=0, k=this.children.length; i<k; ++i)
  1414. if (this.children[i][key] === nameOrId)
  1415. return this.children[i];
  1416. return null;
  1417. };
  1418. /**
  1419. * Resolves a reflect object inside of this namespace.
  1420. * @param {string} qn Qualified name to resolve
  1421. * @param {boolean=} excludeFields Excludes fields, defaults to `false`
  1422. * @return {?ProtoBuf.Reflect.Namespace} The resolved type or null if not found
  1423. * @expose
  1424. */
  1425. NamespacePrototype.resolve = function(qn, excludeFields) {
  1426. var part = qn.split("."),
  1427. ptr = this,
  1428. i = 0;
  1429. if (part[i] === "") { // Fully qualified name, e.g. ".My.Message'
  1430. while (ptr.parent !== null)
  1431. ptr = ptr.parent;
  1432. i++;
  1433. }
  1434. var child;
  1435. do {
  1436. do {
  1437. child = ptr.getChild(part[i]);
  1438. if (!child || !(child instanceof Reflect.T) || (excludeFields && child instanceof Reflect.Message.Field)) {
  1439. ptr = null;
  1440. break;
  1441. }
  1442. ptr = child; i++;
  1443. } while (i < part.length);
  1444. if (ptr != null)
  1445. break; // Found
  1446. // Else search the parent
  1447. if (this.parent !== null) {
  1448. return this.parent.resolve(qn, excludeFields);
  1449. }
  1450. } while (ptr != null);
  1451. return ptr;
  1452. };
  1453. /**
  1454. * Builds the namespace and returns the runtime counterpart.
  1455. * @return {Object.<string,Function|Object>} Runtime namespace
  1456. * @expose
  1457. */
  1458. NamespacePrototype.build = function() {
  1459. /** @dict */
  1460. var ns = {};
  1461. var children = this.children;
  1462. for (var i=0, k=children.length, child; i<k; ++i) {
  1463. child = children[i];
  1464. if (child instanceof Namespace)
  1465. ns[child.name] = child.build();
  1466. }
  1467. if (Object.defineProperty)
  1468. Object.defineProperty(ns, "$options", { "value": this.buildOpt() });
  1469. return ns;
  1470. };
  1471. /**
  1472. * Builds the namespace's '$options' property.
  1473. * @return {Object.<string,*>}
  1474. */
  1475. NamespacePrototype.buildOpt = function() {
  1476. var opt = {},
  1477. keys = Object.keys(this.options);
  1478. for (var i=0, k=keys.length; i<k; ++i) {
  1479. var key = keys[i],
  1480. val = this.options[keys[i]];
  1481. // TODO: Options are not resolved, yet.
  1482. // if (val instanceof Namespace) {
  1483. // opt[key] = val.build();
  1484. // } else {
  1485. opt[key] = val;
  1486. // }
  1487. }
  1488. return opt;
  1489. };
  1490. /**
  1491. * Gets the value assigned to the option with the specified name.
  1492. * @param {string=} name Returns the option value if specified, otherwise all options are returned.
  1493. * @return {*|Object.<string,*>}null} Option value or NULL if there is no such option
  1494. */
  1495. NamespacePrototype.getOption = function(name) {
  1496. if (typeof name === 'undefined')
  1497. return this.options;
  1498. return typeof this.options[name] !== 'undefined' ? this.options[name] : null;
  1499. };
  1500. /**
  1501. * @alias ProtoBuf.Reflect.Namespace
  1502. * @expose
  1503. */
  1504. Reflect.Namespace = Namespace;
  1505. /**
  1506. * Constructs a new Message.
  1507. * @exports ProtoBuf.Reflect.Message
  1508. * @param {!ProtoBuf.Builder} builder Builder reference
  1509. * @param {!ProtoBuf.Reflect.Namespace} parent Parent message or namespace
  1510. * @param {string} name Message name
  1511. * @param {Object.<string,*>=} options Message options
  1512. * @param {boolean=} isGroup `true` if this is a legacy group
  1513. * @constructor
  1514. * @extends ProtoBuf.Reflect.Namespace
  1515. */
  1516. var Message = function(builder, parent, name, options, isGroup) {
  1517. Namespace.call(this, builder, parent, name, options);
  1518. /**
  1519. * @override
  1520. */
  1521. this.className = "Message";
  1522. /**
  1523. * Extensions range.
  1524. * @type {!Array.<number>}
  1525. * @expose
  1526. */
  1527. this.extensions = [ProtoBuf.ID_MIN, ProtoBuf.ID_MAX];
  1528. /**
  1529. * Runtime message class.
  1530. * @type {?function(new:ProtoBuf.Builder.Message)}
  1531. * @expose
  1532. */
  1533. this.clazz = null;
  1534. /**
  1535. * Whether this is a legacy group or not.
  1536. * @type {boolean}
  1537. * @expose
  1538. */
  1539. this.isGroup = !!isGroup;
  1540. // The following cached collections are used to efficiently iterate over or look up fields when decoding.
  1541. /**
  1542. * Cached fields.
  1543. * @type {?Array.<!ProtoBuf.Reflect.Message.Field>}
  1544. * @private
  1545. */
  1546. this._fields = null;
  1547. /**
  1548. * Cached fields by id.
  1549. * @type {?Object.<number,!ProtoBuf.Reflect.Message.Field>}
  1550. * @private
  1551. */
  1552. this._fieldsById = null;
  1553. /**
  1554. * Cached fields by name.
  1555. * @type {?Object.<string,!ProtoBuf.Reflect.Message.Field>}
  1556. * @private
  1557. */
  1558. this._fieldsByName = null;
  1559. };
  1560. /**
  1561. * @alias ProtoBuf.Reflect.Message.prototype
  1562. * @inner
  1563. */
  1564. var MessagePrototype = Message.prototype = Object.create(Namespace.prototype);
  1565. /**
  1566. * Builds the message and returns the runtime counterpart, which is a fully functional class.
  1567. * @see ProtoBuf.Builder.Message
  1568. * @param {boolean=} rebuild Whether to rebuild or not, defaults to false
  1569. * @return {ProtoBuf.Reflect.Message} Message class
  1570. * @throws {Error} If the message cannot be built
  1571. * @expose
  1572. */
  1573. MessagePrototype.build = function(rebuild) {
  1574. if (this.clazz && !rebuild)
  1575. return this.clazz;
  1576. // Create the runtime Message class in its own scope
  1577. var clazz = (function(ProtoBuf, T) {
  1578. var fields = T.getChildren(ProtoBuf.Reflect.Message.Field),
  1579. oneofs = T.getChildren(ProtoBuf.Reflect.Message.OneOf);
  1580. /**
  1581. * Constructs a new runtime Message.
  1582. * @name ProtoBuf.Builder.Message
  1583. * @class Barebone of all runtime messages.
  1584. * @param {!Object.<string,*>|string} values Preset values
  1585. * @param {...string} var_args
  1586. * @constructor
  1587. * @throws {Error} If the message cannot be created
  1588. */
  1589. var Message = function(values, var_args) {
  1590. ProtoBuf.Builder.Message.call(this);
  1591. // Create virtual oneof properties
  1592. for (var i=0, k=oneofs.length; i<k; ++i)
  1593. this[oneofs[i].name] = null;
  1594. // Create fields and set default values
  1595. for (i=0, k=fields.length; i<k; ++i) {
  1596. var field = fields[i];
  1597. this[field.name] = field.repeated ? [] : null;
  1598. if (field.required && field.defaultValue !== null)
  1599. this[field.name] = field.defaultValue;
  1600. }
  1601. if (arguments.length > 0) {
  1602. // Set field values from a values object
  1603. if (arguments.length === 1 && typeof values === 'object' &&
  1604. /* not another Message */ typeof values.encode !== 'function' &&
  1605. /* not a repeated field */ !ProtoBuf.Util.isArray(values) &&
  1606. /* not a ByteBuffer */ !(values instanceof ByteBuffer) &&
  1607. /* not an ArrayBuffer */ !(values instanceof ArrayBuffer) &&
  1608. /* not a Long */ !(ProtoBuf.Long && values instanceof ProtoBuf.Long)) {
  1609. var keys = Object.keys(values);
  1610. for (i=0, k=keys.length; i<k; ++i)
  1611. this.$set(keys[i], values[keys[i]]); // May throw
  1612. } else // Set field values from arguments, in declaration order
  1613. for (i=0, k=arguments.length; i<k; ++i)
  1614. this.$set(fields[i].name, arguments[i]); // May throw
  1615. }
  1616. };
  1617. /**
  1618. * @alias ProtoBuf.Builder.Message.prototype
  1619. * @inner
  1620. */
  1621. var MessagePrototype = Message.prototype = Object.create(ProtoBuf.Builder.Message.prototype);
  1622. /**
  1623. * Adds a value to a repeated field.
  1624. * @name ProtoBuf.Builder.Message#add
  1625. * @function
  1626. * @param {string} key Field name
  1627. * @param {*} value Value to add
  1628. * @param {boolean=} noAssert Whether to assert the value or not (asserts by default)
  1629. * @throws {Error} If the value cannot be added
  1630. * @expose
  1631. */
  1632. MessagePrototype.add = function(key, value, noAssert) {
  1633. var field = T._fieldsByName[key];
  1634. if (!noAssert) {
  1635. if (!field)
  1636. throw Error(this+"#"+key+" is undefined");
  1637. if (!(field instanceof ProtoBuf.Reflect.Message.Field))
  1638. throw Error(this+"#"+key+" is not a field: "+field.toString(true)); // May throw if it's an enum or embedded message
  1639. if (!field.repeated)
  1640. throw Error(this+"#"+key+" is not a repeated field");
  1641. }
  1642. if (this[field.name] === null)
  1643. this[field.name] = [];
  1644. this[field.name].push(noAssert ? value : field.verifyValue(value, true));
  1645. };
  1646. /**
  1647. * Adds a value to a repeated field. This is an alias for {@link ProtoBuf.Builder.Message#add}.
  1648. * @name ProtoBuf.Builder.Message#$add
  1649. * @function
  1650. * @param {string} key Field name
  1651. * @param {*} value Value to add
  1652. * @param {boolean=} noAssert Whether to assert the value or not (asserts by default)
  1653. * @throws {Error} If the value cannot be added
  1654. * @expose
  1655. */
  1656. MessagePrototype.$add = MessagePrototype.add;
  1657. /**
  1658. * Sets a field's value.
  1659. * @name ProtoBuf.Builder.Message#set
  1660. * @function
  1661. * @param {string} key Key
  1662. * @param {*} value Value to set
  1663. * @param {boolean=} noAssert Whether to not assert for an actual field / proper value type, defaults to `false`
  1664. * @returns {!ProtoBuf.Builder.Message} this
  1665. * @throws {Error} If the value cannot be set
  1666. * @expose
  1667. */
  1668. MessagePrototype.set = function(key, value, noAssert) {
  1669. if (key && typeof key === 'object') {
  1670. for (var i in key)
  1671. if (key.hasOwnProperty(i))
  1672. this.$set(i, key[i], noAssert);
  1673. return this;
  1674. }
  1675. var field = T._fieldsByName[key];
  1676. if (!noAssert) {
  1677. if (!field)
  1678. throw Error(this+"#"+key+" is not a field: undefined");
  1679. if (!(field instanceof ProtoBuf.Reflect.Message.Field))
  1680. throw Error(this+"#"+key+" is not a field: "+field.toString(true));
  1681. this[field.name] = (value = field.verifyValue(value)); // May throw
  1682. } else {
  1683. this[field.name] = value;
  1684. }
  1685. if (field.oneof) {
  1686. if (value !== null) {
  1687. if (this[field.oneof.name] !== null)
  1688. this[this[field.oneof.name]] = null; // Unset the previous (field name is the oneof field's value)
  1689. this[field.oneof.name] = field.name;
  1690. } else if (field.oneof.name === key)
  1691. this[field.oneof.name] = null;
  1692. }
  1693. return this;
  1694. };
  1695. /**
  1696. * Sets a field's value. This is an alias for [@link ProtoBuf.Builder.Message#set}.
  1697. * @name ProtoBuf.Builder.Message#$set
  1698. * @function
  1699. * @param {string} key Key
  1700. * @param {*} value Value to set
  1701. * @param {boolean=} noAssert Whether to not assert the value, defaults to `false`
  1702. * @throws {Error} If the value cannot be set
  1703. * @expose
  1704. */
  1705. MessagePrototype.$set = MessagePrototype.set;
  1706. /**
  1707. * Gets a field's value.
  1708. * @name ProtoBuf.Builder.Message#get
  1709. * @function
  1710. * @param {string} key Key
  1711. * @param {boolean=} noAssert Whether to not assert for an actual field, defaults to `false`
  1712. * @return {*} Value
  1713. * @throws {Error} If there is no such field
  1714. * @expose
  1715. */
  1716. MessagePrototype.get = function(key, noAssert) {
  1717. if (noAssert)
  1718. return this[key];
  1719. var field = T._fieldsByName[key];
  1720. if (!field || !(field instanceof ProtoBuf.Reflect.Message.Field))
  1721. throw Error(this+"#"+key+" is not a field: undefined");
  1722. if (!(field instanceof ProtoBuf.Reflect.Message.Field))
  1723. throw Error(this+"#"+key+" is not a field: "+field.toString(true));
  1724. return this[field.name];
  1725. };
  1726. /**
  1727. * Gets a field's value. This is an alias for {@link ProtoBuf.Builder.Message#$get}.
  1728. * @name ProtoBuf.Builder.Message#$get
  1729. * @function
  1730. * @param {string} key Key
  1731. * @return {*} Value
  1732. * @throws {Error} If there is no such field
  1733. * @expose
  1734. */
  1735. MessagePrototype.$get = MessagePrototype.get;
  1736. // Getters and setters
  1737. for (var i=0; i<fields.length; i++) {
  1738. var field = fields[i];
  1739. // no setters for extension fields as these are named by their fqn
  1740. if (field instanceof ProtoBuf.Reflect.Message.ExtensionField)
  1741. continue;
  1742. if (T.builder.options['populateAccessors'])
  1743. (function(field) {
  1744. // set/get[SomeValue]
  1745. var Name = field.originalName.replace(/(_[a-zA-Z])/g, function(match) {
  1746. return match.toUpperCase().replace('_','');
  1747. });
  1748. Name = Name.substring(0,1).toUpperCase() + Name.substring(1);
  1749. // set/get_[some_value] FIXME: Do we really need these?
  1750. var name = field.originalName.replace(/([A-Z])/g, function(match) {
  1751. return "_"+match;
  1752. });
  1753. /**
  1754. * The current field's unbound setter function.
  1755. * @function
  1756. * @param {*} value
  1757. * @param {boolean=} noAssert
  1758. * @returns {!ProtoBuf.Builder.Message}
  1759. * @inner
  1760. */
  1761. var setter = function(value, noAssert) {
  1762. this[field.name] = noAssert ? value : field.verifyValue(value);
  1763. return this;
  1764. };
  1765. /**
  1766. * The current field's unbound getter function.
  1767. * @function
  1768. * @returns {*}
  1769. * @inner
  1770. */
  1771. var getter = function() {
  1772. return this[field.name];
  1773. };
  1774. /**
  1775. * Sets a value. This method is present for each field, but only if there is no name conflict with
  1776. * another field.
  1777. * @name ProtoBuf.Builder.Message#set[SomeField]
  1778. * @function
  1779. * @param {*} value Value to set
  1780. * @param {boolean=} noAssert Whether to not assert the value, defaults to `false`
  1781. * @returns {!ProtoBuf.Builder.Message} this
  1782. * @abstract
  1783. * @throws {Error} If the value cannot be set
  1784. */
  1785. if (T.getChild("set"+Name) === null)
  1786. MessagePrototype["set"+Name] = setter;
  1787. /**
  1788. * Sets a value. This method is present for each field, but only if there is no name conflict with
  1789. * another field.
  1790. * @name ProtoBuf.Builder.Message#set_[some_field]
  1791. * @function
  1792. * @param {*} value Value to set
  1793. * @param {boolean=} noAssert Whether to not assert the value, defaults to `false`
  1794. * @returns {!ProtoBuf.Builder.Message} this
  1795. * @abstract
  1796. * @throws {Error} If the value cannot be set
  1797. */
  1798. if (T.getChild("set_"+name) === null)
  1799. MessagePrototype["set_"+name] = setter;
  1800. /**
  1801. * Gets a value. This method is present for each field, but only if there is no name conflict with
  1802. * another field.
  1803. * @name ProtoBuf.Builder.Message#get[SomeField]
  1804. * @function
  1805. * @abstract
  1806. * @return {*} The value
  1807. */
  1808. if (T.getChild("get"+Name) === null)
  1809. MessagePrototype["get"+Name] = getter;
  1810. /**
  1811. * Gets a value. This method is present for each field, but only if there is no name conflict with
  1812. * another field.
  1813. * @name ProtoBuf.Builder.Message#get_[some_field]
  1814. * @function
  1815. * @return {*} The value
  1816. * @abstract
  1817. */
  1818. if (T.getChild("get_"+name) === null)
  1819. MessagePrototype["get_"+name] = getter;
  1820. })(field);
  1821. }
  1822. // En-/decoding
  1823. /**
  1824. * Encodes the message.
  1825. * @name ProtoBuf.Builder.Message#$encode
  1826. * @function
  1827. * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted.
  1828. * @param {boolean=} noVerify Whether to not verify field values, defaults to `false`
  1829. * @return {!ByteBuffer} Encoded message as a ByteBuffer
  1830. * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
  1831. * returns the encoded ByteBuffer in the `encoded` property on the error.
  1832. * @expose
  1833. * @see ProtoBuf.Builder.Message#encode64
  1834. * @see ProtoBuf.Builder.Message#encodeHex
  1835. * @see ProtoBuf.Builder.Message#encodeAB
  1836. */
  1837. MessagePrototype.encode = function(buffer, noVerify) {
  1838. if (typeof buffer === 'boolean')
  1839. noVerify = buffer,
  1840. buffer = undefined;
  1841. var isNew = false;
  1842. if (!buffer)
  1843. buffer = new ByteBuffer(),
  1844. isNew = true;
  1845. var le = buffer.littleEndian;
  1846. try {
  1847. T.encode(this, buffer.LE(), noVerify);
  1848. return (isNew ? buffer.flip() : buffer).LE(le);
  1849. } catch (e) {
  1850. buffer.LE(le);
  1851. throw(e);
  1852. }
  1853. };
  1854. /**
  1855. * Calculates the byte length of the message.
  1856. * @name ProtoBuf.Builder.Message#calculate
  1857. * @function
  1858. * @returns {number} Byte length
  1859. * @throws {Error} If the message cannot be calculated or if required fields are missing.
  1860. * @expose
  1861. */
  1862. MessagePrototype.calculate = function() {
  1863. return T.calculate(this);
  1864. };
  1865. /**
  1866. * Encodes the varint32 length-delimited message.
  1867. * @name ProtoBuf.Builder.Message#encodeDelimited
  1868. * @function
  1869. * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted.
  1870. * @return {!ByteBuffer} Encoded message as a ByteBuffer
  1871. * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
  1872. * returns the encoded ByteBuffer in the `encoded` property on the error.
  1873. * @expose
  1874. */
  1875. MessagePrototype.encodeDelimited = function(buffer) {
  1876. var isNew = false;
  1877. if (!buffer)
  1878. buffer = new ByteBuffer(),
  1879. isNew = true;
  1880. var enc = new ByteBuffer().LE();
  1881. T.encode(this, enc).flip();
  1882. buffer.writeVarint32(enc.remaining());
  1883. buffer.append(enc);
  1884. return isNew ? buffer.flip() : buffer;
  1885. };
  1886. /**
  1887. * Directly encodes the message to an ArrayBuffer.
  1888. * @name ProtoBuf.Builder.Message#encodeAB
  1889. * @function
  1890. * @return {ArrayBuffer} Encoded message as ArrayBuffer
  1891. * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
  1892. * returns the encoded ArrayBuffer in the `encoded` property on the error.
  1893. * @expose
  1894. */
  1895. MessagePrototype.encodeAB = function() {
  1896. try {
  1897. return this.encode().toArrayBuffer();
  1898. } catch (e) {
  1899. if (e["encoded"]) e["encoded"] = e["encoded"].toArrayBuffer();
  1900. throw(e);
  1901. }
  1902. };
  1903. /**
  1904. * Returns the message as an ArrayBuffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeAB}.
  1905. * @name ProtoBuf.Builder.Message#toArrayBuffer
  1906. * @function
  1907. * @return {ArrayBuffer} Encoded message as ArrayBuffer
  1908. * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
  1909. * returns the encoded ArrayBuffer in the `encoded` property on the error.
  1910. * @expose
  1911. */
  1912. MessagePrototype.toArrayBuffer = MessagePrototype.encodeAB;
  1913. /**
  1914. * Directly encodes the message to a node Buffer.
  1915. * @name ProtoBuf.Builder.Message#encodeNB
  1916. * @function
  1917. * @return {!Buffer}
  1918. * @throws {Error} If the message cannot be encoded, not running under node.js or if required fields are
  1919. * missing. The later still returns the encoded node Buffer in the `encoded` property on the error.
  1920. * @expose
  1921. */
  1922. MessagePrototype.encodeNB = function() {
  1923. try {
  1924. return this.encode().toBuffer();
  1925. } catch (e) {
  1926. if (e["encoded"]) e["encoded"] = e["encoded"].toBuffer();
  1927. throw(e);
  1928. }
  1929. };
  1930. /**
  1931. * Returns the message as a node Buffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeNB}.
  1932. * @name ProtoBuf.Builder.Message#toBuffer
  1933. * @function
  1934. * @return {!Buffer}
  1935. * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
  1936. * returns the encoded node Buffer in the `encoded` property on the error.
  1937. * @expose
  1938. */
  1939. MessagePrototype.toBuffer = MessagePrototype.encodeNB;
  1940. /**
  1941. * Directly encodes the message to a base64 encoded string.
  1942. * @name ProtoBuf.Builder.Message#encode64
  1943. * @function
  1944. * @return {string} Base64 encoded string
  1945. * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later
  1946. * still returns the encoded base64 string in the `encoded` property on the error.
  1947. * @expose
  1948. */
  1949. MessagePrototype.encode64 = function() {
  1950. try {
  1951. return this.encode().toBase64();
  1952. } catch (e) {
  1953. if (e["encoded"]) e["encoded"] = e["encoded"].toBase64();
  1954. throw(e);
  1955. }
  1956. };
  1957. /**
  1958. * Returns the message as a base64 encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encode64}.
  1959. * @name ProtoBuf.Builder.Message#toBase64
  1960. * @function
  1961. * @return {string} Base64 encoded string
  1962. * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
  1963. * returns the encoded base64 string in the `encoded` property on the error.
  1964. * @expose
  1965. */
  1966. MessagePrototype.toBase64 = MessagePrototype.encode64;
  1967. /**
  1968. * Directly encodes the message to a hex encoded string.
  1969. * @name ProtoBuf.Builder.Message#encodeHex
  1970. * @function
  1971. * @return {string} Hex encoded string
  1972. * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later
  1973. * still returns the encoded hex string in the `encoded` property on the error.
  1974. * @expose
  1975. */
  1976. MessagePrototype.encodeHex = function() {
  1977. try {
  1978. return this.encode().toHex();
  1979. } catch (e) {
  1980. if (e["encoded"]) e["encoded"] = e["encoded"].toHex();
  1981. throw(e);
  1982. }
  1983. };
  1984. /**
  1985. * Returns the message as a hex encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encodeHex}.
  1986. * @name ProtoBuf.Builder.Message#toHex
  1987. * @function
  1988. * @return {string} Hex encoded string
  1989. * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
  1990. * returns the encoded hex string in the `encoded` property on the error.
  1991. * @expose
  1992. */
  1993. MessagePrototype.toHex = MessagePrototype.encodeHex;
  1994. /**
  1995. * Clones a message object to a raw object.
  1996. * @param {*} obj Object to clone
  1997. * @param {boolean} includeBinaryAsBase64 Whether to include binary data as base64 strings or not
  1998. * @returns {*} Cloned object
  1999. * @inner
  2000. */
  2001. function cloneRaw(obj, includeBinaryAsBase64) {
  2002. var clone = {};
  2003. for (var i in obj)
  2004. if (obj.hasOwnProperty(i)) {
  2005. if (obj[i] === null || typeof obj[i] !== 'object')
  2006. clone[i] = obj[i];
  2007. else if (obj[i] instanceof ByteBuffer) {
  2008. if (includeBinaryAsBase64)
  2009. clone[i] = obj[i].toBase64();
  2010. } else // is a non-null object
  2011. clone[i] = cloneRaw(obj[i], includeBinaryAsBase64);
  2012. }
  2013. return clone;
  2014. }
  2015. /**
  2016. * Returns the message's raw payload.
  2017. * @param {boolean=} includeBinaryAsBase64 Whether to include binary data as base64 strings or not, defaults to `false`
  2018. * @returns {Object.<string,*>} Raw payload
  2019. * @expose
  2020. */
  2021. MessagePrototype.toRaw = function(includeBinaryAsBase64) {
  2022. return cloneRaw(this, !!includeBinaryAsBase64);
  2023. };
  2024. /**
  2025. * Decodes a message from the specified buffer or string.
  2026. * @name ProtoBuf.Builder.Message.decode
  2027. * @function
  2028. * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from
  2029. * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64
  2030. * @return {!ProtoBuf.Builder.Message} Decoded message
  2031. * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still
  2032. * returns the decoded message with missing fields in the `decoded` property on the error.
  2033. * @expose
  2034. * @see ProtoBuf.Builder.Message.decode64
  2035. * @see ProtoBuf.Builder.Message.decodeHex
  2036. */
  2037. Message.decode = function(buffer, enc) {
  2038. if (typeof buffer === 'string')
  2039. buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64");
  2040. buffer = buffer instanceof ByteBuffer ? buffer : ByteBuffer.wrap(buffer); // May throw
  2041. var le = buffer.littleEndian;
  2042. try {
  2043. var msg = T.decode(buffer.LE());
  2044. buffer.LE(le);
  2045. return msg;
  2046. } catch (e) {
  2047. buffer.LE(le);
  2048. throw(e);
  2049. }
  2050. };
  2051. /**
  2052. * Decodes a varint32 length-delimited message from the specified buffer or string.
  2053. * @name ProtoBuf.Builder.Message.decodeDelimited
  2054. * @function
  2055. * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from
  2056. * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64
  2057. * @return {ProtoBuf.Builder.Message} Decoded message or `null` if not enough bytes are available yet
  2058. * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still
  2059. * returns the decoded message with missing fields in the `decoded` property on the error.
  2060. * @expose
  2061. */
  2062. Message.decodeDelimited = function(buffer, enc) {
  2063. if (typeof buffer === 'string')
  2064. buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64");
  2065. buffer = buffer instanceof ByteBuffer ? buffer : ByteBuffer.wrap(buffer); // May throw
  2066. if (buffer.remaining() < 1)
  2067. return null;
  2068. var off = buffer.offset,
  2069. len = buffer.readVarint32();
  2070. if (buffer.remaining() < len) {
  2071. buffer.offset = off;
  2072. return null;
  2073. }
  2074. try {
  2075. var msg = T.decode(buffer.slice(buffer.offset, buffer.offset + len).LE());
  2076. buffer.offset += len;
  2077. return msg;
  2078. } catch (err) {
  2079. buffer.offset += len;
  2080. throw err;
  2081. }
  2082. };
  2083. /**
  2084. * Decodes the message from the specified base64 encoded string.
  2085. * @name ProtoBuf.Builder.Message.decode64
  2086. * @function
  2087. * @param {string} str String to decode from
  2088. * @return {!ProtoBuf.Builder.Message} Decoded message
  2089. * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still
  2090. * returns the decoded message with missing fields in the `decoded` property on the error.
  2091. * @expose
  2092. */
  2093. Message.decode64 = function(str) {
  2094. return Message.decode(str, "base64");
  2095. };
  2096. /**
  2097. * Decodes the message from the specified hex encoded string.
  2098. * @name ProtoBuf.Builder.Message.decodeHex
  2099. * @function
  2100. * @param {string} str String to decode from
  2101. * @return {!ProtoBuf.Builder.Message} Decoded message
  2102. * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still
  2103. * returns the decoded message with missing fields in the `decoded` property on the error.
  2104. * @expose
  2105. */
  2106. Message.decodeHex = function(str) {
  2107. return Message.decode(str, "hex");
  2108. };
  2109. // Utility
  2110. /**
  2111. * Returns a string representation of this Message.
  2112. * @name ProtoBuf.Builder.Message#toString
  2113. * @function
  2114. * @return {string} String representation as of ".Fully.Qualified.MessageName"
  2115. * @expose
  2116. */
  2117. MessagePrototype.toString = function() {
  2118. return T.toString();
  2119. };
  2120. // Properties
  2121. /**
  2122. * Options.
  2123. * @name ProtoBuf.Builder.Message.$options
  2124. * @type {Object.<string,*>}
  2125. * @expose
  2126. */
  2127. var $options; // cc
  2128. /**
  2129. * Reflection type.
  2130. * @name ProtoBuf.Builder.Message#$type
  2131. * @type {!ProtoBuf.Reflect.Message}
  2132. * @expose
  2133. */
  2134. var $type; // cc
  2135. if (Object.defineProperty)
  2136. Object.defineProperty(Message, '$options', { "value": T.buildOpt() }),
  2137. Object.defineProperty(MessagePrototype, "$type", {
  2138. get: function() { return T; }
  2139. });
  2140. return Message;
  2141. })(ProtoBuf, this);
  2142. // Static enums and prototyped sub-messages / cached collections
  2143. this._fields = [];
  2144. this._fieldsById = {};
  2145. this._fieldsByName = {};
  2146. for (var i=0, k=this.children.length, child; i<k; i++) {
  2147. child = this.children[i];
  2148. if (child instanceof Enum)
  2149. clazz[child.name] = child.build();
  2150. else if (child instanceof Message)
  2151. clazz[child.name] = child.build();
  2152. else if (child instanceof Message.Field)
  2153. child.build(),
  2154. this._fields.push(child),
  2155. this._fieldsById[child.id] = child,
  2156. this._fieldsByName[child.name] = child;
  2157. else if (!(child instanceof Message.OneOf) && !(child instanceof Extension)) // Not built
  2158. throw Error("Illegal reflect child of "+this.toString(true)+": "+children[i].toString(true));
  2159. }
  2160. return this.clazz = clazz;
  2161. };
  2162. /**
  2163. * Encodes a runtime message's contents to the specified buffer.
  2164. * @param {!ProtoBuf.Builder.Message} message Runtime message to encode
  2165. * @param {ByteBuffer} buffer ByteBuffer to write to
  2166. * @param {boolean=} noVerify Whether to not verify field values, defaults to `false`
  2167. * @return {ByteBuffer} The ByteBuffer for chaining
  2168. * @throws {Error} If required fields are missing or the message cannot be encoded for another reason
  2169. * @expose
  2170. */
  2171. MessagePrototype.encode = function(message, buffer, noVerify) {
  2172. var fieldMissing = null,
  2173. field;
  2174. for (var i=0, k=this._fields.length, val; i<k; ++i) {
  2175. field = this._fields[i];
  2176. val = message[field.name];
  2177. if (field.required && val === null) {
  2178. if (fieldMissing === null)
  2179. fieldMissing = field;
  2180. } else
  2181. field.encode(noVerify ? val : field.verifyValue(val), buffer);
  2182. }
  2183. if (fieldMissing !== null) {
  2184. var err = Error("Missing at least one required field for "+this.toString(true)+": "+fieldMissing);
  2185. err["encoded"] = buffer; // Still expose what we got
  2186. throw(err);
  2187. }
  2188. return buffer;
  2189. };
  2190. /**
  2191. * Calculates a runtime message's byte length.
  2192. * @param {!ProtoBuf.Builder.Message} message Runtime message to encode
  2193. * @returns {number} Byte length
  2194. * @throws {Error} If required fields are missing or the message cannot be calculated for another reason
  2195. * @expose
  2196. */
  2197. MessagePrototype.calculate = function(message) {
  2198. for (var n=0, i=0, k=this._fields.length, field, val; i<k; ++i) {
  2199. field = this._fields[i];
  2200. val = message[field.name];
  2201. if (field.required && val === null)
  2202. throw Error("Missing at least one required field for "+this.toString(true)+": "+field);
  2203. else
  2204. n += field.calculate(val);
  2205. }
  2206. return n;
  2207. };
  2208. /**
  2209. * Skips all data until the end of the specified group has been reached.
  2210. * @param {number} expectedId Expected GROUPEND id
  2211. * @param {!ByteBuffer} buf ByteBuffer
  2212. * @returns {boolean} `true` if a value as been skipped, `false` if the end has been reached
  2213. * @throws {Error} If it wasn't possible to find the end of the group (buffer overrun or end tag mismatch)
  2214. * @inner
  2215. */
  2216. function skipTillGroupEnd(expectedId, buf) {
  2217. var tag = buf.readVarint32(), // Throws on OOB
  2218. wireType = tag & 0x07,
  2219. id = tag >> 3;
  2220. switch (wireType) {
  2221. case ProtoBuf.WIRE_TYPES.VARINT:
  2222. do tag = buf.readUint8();
  2223. while ((tag & 0x80) === 0x80);
  2224. break;
  2225. case ProtoBuf.WIRE_TYPES.BITS64:
  2226. buf.offset += 8;
  2227. break;
  2228. case ProtoBuf.WIRE_TYPES.LDELIM:
  2229. tag = buf.readVarint32(); // reads the varint
  2230. buf.offset += tag; // skips n bytes
  2231. break;
  2232. case ProtoBuf.WIRE_TYPES.STARTGROUP:
  2233. skipTillGroupEnd(id, buf);
  2234. break;
  2235. case ProtoBuf.WIRE_TYPES.ENDGROUP:
  2236. if (id === expectedId)
  2237. return false;
  2238. else
  2239. throw Error("Illegal GROUPEND after unknown group: "+id+" ("+expectedId+" expected)");
  2240. case ProtoBuf.WIRE_TYPES.BITS32:
  2241. buf.offset += 4;
  2242. break;
  2243. default:
  2244. throw Error("Illegal wire type in unknown group "+expectedId+": "+wireType);
  2245. }
  2246. return true;
  2247. }
  2248. /**
  2249. * Decodes an encoded message and returns the decoded message.
  2250. * @param {ByteBuffer} buffer ByteBuffer to decode from
  2251. * @param {number=} length Message length. Defaults to decode all the available data.
  2252. * @param {number=} expectedGroupEndId Expected GROUPEND id if this is a legacy group
  2253. * @return {ProtoBuf.Builder.Message} Decoded message
  2254. * @throws {Error} If the message cannot be decoded
  2255. * @expose
  2256. */
  2257. MessagePrototype.decode = function(buffer, length, expectedGroupEndId) {
  2258. length = typeof length === 'number' ? length : -1;
  2259. var start = buffer.offset,
  2260. msg = new (this.clazz)(),
  2261. tag, wireType, id, field;
  2262. while (buffer.offset < start+length || (length === -1 && buffer.remaining() > 0)) {
  2263. tag = buffer.readVarint32();
  2264. wireType = tag & 0x07;
  2265. id = tag >> 3;
  2266. if (wireType === ProtoBuf.WIRE_TYPES.ENDGROUP) {
  2267. if (id !== expectedGroupEndId)
  2268. throw Error("Illegal group end indicator for "+this.toString(true)+": "+id+" ("+(expectedGroupEndId ? expectedGroupEndId+" expected" : "not a group")+")");
  2269. break;
  2270. }
  2271. if (!(field = this._fieldsById[id])) {
  2272. // "messages created by your new code can be parsed by your old code: old binaries simply ignore the new field when parsing."
  2273. switch (wireType) {
  2274. case ProtoBuf.WIRE_TYPES.VARINT:
  2275. buffer.readVarint32();
  2276. break;
  2277. case ProtoBuf.WIRE_TYPES.BITS32:
  2278. buffer.offset += 4;
  2279. break;
  2280. case ProtoBuf.WIRE_TYPES.BITS64:
  2281. buffer.offset += 8;
  2282. break;
  2283. case ProtoBuf.WIRE_TYPES.LDELIM:
  2284. var len = buffer.readVarint32();
  2285. buffer.offset += len;
  2286. break;
  2287. case ProtoBuf.WIRE_TYPES.STARTGROUP:
  2288. while (skipTillGroupEnd(id, buffer)) {}
  2289. break;
  2290. default:
  2291. throw Error("Illegal wire type for unknown field "+id+" in "+this.toString(true)+"#decode: "+wireType);
  2292. }
  2293. continue;
  2294. }
  2295. if (field.repeated && !field.options["packed"])
  2296. msg[field.name].push(field.decode(wireType, buffer));
  2297. else {
  2298. msg[field.name] = field.decode(wireType, buffer);
  2299. if (field.oneof) {
  2300. if (this[field.oneof.name] !== null)
  2301. this[this[field.oneof.name]] = null;
  2302. msg[field.oneof.name] = field.name;
  2303. }
  2304. }
  2305. }
  2306. // Check if all required fields are present and set default values for optional fields that are not
  2307. for (var i=0, k=this._fields.length; i<k; ++i) {
  2308. field = this._fields[i];
  2309. if (msg[field.name] === null)
  2310. if (field.required) {
  2311. var err = Error("Missing at least one required field for "+this.toString(true)+": "+field.name);
  2312. err["decoded"] = msg; // Still expose what we got
  2313. throw(err);
  2314. } else if (field.defaultValue !== null)
  2315. msg[field.name] = field.defaultValue;
  2316. }
  2317. return msg;
  2318. };
  2319. /**
  2320. * @alias ProtoBuf.Reflect.Message
  2321. * @expose
  2322. */
  2323. Reflect.Message = Message;
  2324. /**
  2325. * Constructs a new Message Field.
  2326. * @exports ProtoBuf.Reflect.Message.Field
  2327. * @param {!ProtoBuf.Builder} builder Builder reference
  2328. * @param {!ProtoBuf.Reflect.Message} message Message reference
  2329. * @param {string} rule Rule, one of requried, optional, repeated
  2330. * @param {string} type Data type, e.g. int32
  2331. * @param {string} name Field name
  2332. * @param {number} id Unique field id
  2333. * @param {Object.<string,*>=} options Options
  2334. * @param {!ProtoBuf.Reflect.Message.OneOf=} oneof Enclosing OneOf
  2335. * @constructor
  2336. * @extends ProtoBuf.Reflect.T
  2337. */
  2338. var Field = function(builder, message, rule, type, name, id, options, oneof) {
  2339. T.call(this, builder, message, name);
  2340. /**
  2341. * @override
  2342. */
  2343. this.className = "Message.Field";
  2344. /**
  2345. * Message field required flag.
  2346. * @type {boolean}
  2347. * @expose
  2348. */
  2349. this.required = rule === "required";
  2350. /**
  2351. * Message field repeated flag.
  2352. * @type {boolean}
  2353. * @expose
  2354. */
  2355. this.repeated = rule === "repeated";
  2356. /**
  2357. * Message field type. Type reference string if unresolved, protobuf type if resolved.
  2358. * @type {string|{name: string, wireType: number}}
  2359. * @expose
  2360. */
  2361. this.type = type;
  2362. /**
  2363. * Resolved type reference inside the global namespace.
  2364. * @type {ProtoBuf.Reflect.T|null}
  2365. * @expose
  2366. */
  2367. this.resolvedType = null;
  2368. /**
  2369. * Unique message field id.
  2370. * @type {number}
  2371. * @expose
  2372. */
  2373. this.id = id;
  2374. /**
  2375. * Message field options.
  2376. * @type {!Object.<string,*>}
  2377. * @dict
  2378. * @expose
  2379. */
  2380. this.options = options || {};
  2381. /**
  2382. * Default value.
  2383. * @type {*}
  2384. * @expose
  2385. */
  2386. this.defaultValue = null;
  2387. /**
  2388. * Enclosing OneOf.
  2389. * @type {?ProtoBuf.Reflect.Message.OneOf}
  2390. * @expose
  2391. */
  2392. this.oneof = oneof || null;
  2393. /**
  2394. * Original field name.
  2395. * @type {string}
  2396. * @expose
  2397. */
  2398. this.originalName = this.name; // Used to revert camelcase transformation on naming collisions
  2399. // Convert field names to camel case notation if the override is set
  2400. if (this.builder.options['convertFieldsToCamelCase'] && !(this instanceof Message.ExtensionField))
  2401. this.name = Field._toCamelCase(this.name);
  2402. };
  2403. /**
  2404. * Converts a field name to camel case.
  2405. * @param {string} name Likely underscore notated name
  2406. * @returns {string} Camel case notated name
  2407. * @private
  2408. */
  2409. Field._toCamelCase = function(name) {
  2410. return name.replace(/_([a-zA-Z])/g, function($0, $1) {
  2411. return $1.toUpperCase();
  2412. });
  2413. };
  2414. /**
  2415. * @alias ProtoBuf.Reflect.Message.Field.prototype
  2416. * @inner
  2417. */
  2418. var FieldPrototype = Field.prototype = Object.create(T.prototype);
  2419. /**
  2420. * Builds the field.
  2421. * @override
  2422. * @expose
  2423. */
  2424. FieldPrototype.build = function() {
  2425. this.defaultValue = typeof this.options['default'] !== 'undefined'
  2426. ? this.verifyValue(this.options['default']) : null;
  2427. };
  2428. /**
  2429. * Makes a Long from a value.
  2430. * @param {{low: number, high: number, unsigned: boolean}|string|number} value Value
  2431. * @param {boolean=} unsigned Whether unsigned or not, defaults to reuse it from Long-like objects or to signed for
  2432. * strings and numbers
  2433. * @returns {!Long}
  2434. * @throws {Error} If the value cannot be converted to a Long
  2435. * @inner
  2436. */
  2437. function mkLong(value, unsigned) {
  2438. if (value && typeof value.low === 'number' && typeof value.high === 'number' && typeof value.unsigned === 'boolean'
  2439. && value.low === value.low && value.high === value.high)
  2440. return new ProtoBuf.Long(value.low, value.high, typeof unsigned === 'undefined' ? value.unsigned : unsigned);
  2441. if (typeof value === 'string')
  2442. return ProtoBuf.Long.fromString(value, unsigned || false, 10);
  2443. if (typeof value === 'number')
  2444. return ProtoBuf.Long.fromNumber(value, unsigned || false);
  2445. throw Error("not convertible to Long");
  2446. }
  2447. /**
  2448. * Checks if the given value can be set for this field.
  2449. * @param {*} value Value to check
  2450. * @param {boolean=} skipRepeated Whether to skip the repeated value check or not. Defaults to false.
  2451. * @return {*} Verified, maybe adjusted, value
  2452. * @throws {Error} If the value cannot be set for this field
  2453. * @expose
  2454. */
  2455. FieldPrototype.verifyValue = function(value, skipRepeated) {
  2456. skipRepeated = skipRepeated || false;
  2457. var fail = function(val, msg) {
  2458. throw Error("Illegal value for "+this.toString(true)+" of type "+this.type.name+": "+val+" ("+msg+")");
  2459. }.bind(this);
  2460. if (value === null) { // NULL values for optional fields
  2461. if (this.required)
  2462. fail(typeof value, "required");
  2463. return null;
  2464. }
  2465. var i;
  2466. if (this.repeated && !skipRepeated) { // Repeated values as arrays
  2467. if (!ProtoBuf.Util.isArray(value))
  2468. value = [value];
  2469. var res = [];
  2470. for (i=0; i<value.length; i++)
  2471. res.push(this.verifyValue(value[i], true));
  2472. return res;
  2473. }
  2474. // All non-repeated fields expect no array
  2475. if (!this.repeated && ProtoBuf.Util.isArray(value))
  2476. fail(typeof value, "no array expected");
  2477. switch (this.type) {
  2478. // Signed 32bit
  2479. case ProtoBuf.TYPES["int32"]:
  2480. case ProtoBuf.TYPES["sint32"]:
  2481. case ProtoBuf.TYPES["sfixed32"]:
  2482. // Account for !NaN: value === value
  2483. if (typeof value !== 'number' || (value === value && value % 1 !== 0))
  2484. fail(typeof value, "not an integer");
  2485. return value > 4294967295 ? value | 0 : value;
  2486. // Unsigned 32bit
  2487. case ProtoBuf.TYPES["uint32"]:
  2488. case ProtoBuf.TYPES["fixed32"]:
  2489. if (typeof value !== 'number' || (value === value && value % 1 !== 0))
  2490. fail(typeof value, "not an integer");
  2491. return value < 0 ? value >>> 0 : value;
  2492. // Signed 64bit
  2493. case ProtoBuf.TYPES["int64"]:
  2494. case ProtoBuf.TYPES["sint64"]:
  2495. case ProtoBuf.TYPES["sfixed64"]: {
  2496. if (ProtoBuf.Long)
  2497. try {
  2498. return mkLong(value, false);
  2499. } catch (e) {
  2500. fail(typeof value, e.message);
  2501. }
  2502. else
  2503. fail(typeof value, "requires Long.js");
  2504. }
  2505. // Unsigned 64bit
  2506. case ProtoBuf.TYPES["uint64"]:
  2507. case ProtoBuf.TYPES["fixed64"]: {
  2508. if (ProtoBuf.Long)
  2509. try {
  2510. return mkLong(value, true);
  2511. } catch (e) {
  2512. fail(typeof value, e.message);
  2513. }
  2514. else
  2515. fail(typeof value, "requires Long.js");
  2516. }
  2517. // Bool
  2518. case ProtoBuf.TYPES["bool"]:
  2519. if (typeof value !== 'boolean')
  2520. fail(typeof value, "not a boolean");
  2521. return value;
  2522. // Float
  2523. case ProtoBuf.TYPES["float"]:
  2524. case ProtoBuf.TYPES["double"]:
  2525. if (typeof value !== 'number')
  2526. fail(typeof value, "not a number");
  2527. return value;
  2528. // Length-delimited string
  2529. case ProtoBuf.TYPES["string"]:
  2530. if (typeof value !== 'string' && !(value && value instanceof String))
  2531. fail(typeof value, "not a string");
  2532. return ""+value; // Convert String object to string
  2533. // Length-delimited bytes
  2534. case ProtoBuf.TYPES["bytes"]:
  2535. if (ByteBuffer.isByteBuffer(value))
  2536. return value;
  2537. return ByteBuffer.wrap(value, "base64");
  2538. // Constant enum value
  2539. case ProtoBuf.TYPES["enum"]: {
  2540. var values = this.resolvedType.getChildren(Enum.Value);
  2541. for (i=0; i<values.length; i++)
  2542. if (values[i].name == value)
  2543. return values[i].id;
  2544. else if (values[i].id == value)
  2545. return values[i].id;
  2546. fail(value, "not a valid enum value");
  2547. }
  2548. // Embedded message
  2549. case ProtoBuf.TYPES["group"]:
  2550. case ProtoBuf.TYPES["message"]: {
  2551. if (!value || typeof value !== 'object')
  2552. fail(typeof value, "object expected");
  2553. if (value instanceof this.resolvedType.clazz)
  2554. return value;
  2555. if (value instanceof ProtoBuf.Builder.Message) {
  2556. // Mismatched type: Convert to object (see: https://github.com/dcodeIO/ProtoBuf.js/issues/180)
  2557. var obj = {};
  2558. for (var i in value)
  2559. if (value.hasOwnProperty(i))
  2560. obj[i] = value[i];
  2561. value = obj;
  2562. }
  2563. // Else let's try to construct one from a key-value object
  2564. return new (this.resolvedType.clazz)(value); // May throw for a hundred of reasons
  2565. }
  2566. }
  2567. // We should never end here
  2568. throw Error("[INTERNAL] Illegal value for "+this.toString(true)+": "+value+" (undefined type "+this.type+")");
  2569. };
  2570. /**
  2571. * Encodes the specified field value to the specified buffer.
  2572. * @param {*} value Verified field value
  2573. * @param {ByteBuffer} buffer ByteBuffer to encode to
  2574. * @return {ByteBuffer} The ByteBuffer for chaining
  2575. * @throws {Error} If the field cannot be encoded
  2576. * @expose
  2577. */
  2578. FieldPrototype.encode = function(value, buffer) {
  2579. if (this.type === null || typeof this.type !== 'object')
  2580. throw Error("[INTERNAL] Unresolved type in "+this.toString(true)+": "+this.type);
  2581. if (value === null || (this.repeated && value.length == 0))
  2582. return buffer; // Optional omitted
  2583. try {
  2584. if (this.repeated) {
  2585. var i;
  2586. // "Only repeated fields of primitive numeric types (types which use the varint, 32-bit, or 64-bit wire
  2587. // types) can be declared 'packed'."
  2588. if (this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) {
  2589. // "All of the elements of the field are packed into a single key-value pair with wire type 2
  2590. // (length-delimited). Each element is encoded the same way it would be normally, except without a
  2591. // tag preceding it."
  2592. buffer.writeVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);
  2593. buffer.ensureCapacity(buffer.offset += 1); // We do not know the length yet, so let's assume a varint of length 1
  2594. var start = buffer.offset; // Remember where the contents begin
  2595. for (i=0; i<value.length; i++)
  2596. this.encodeValue(value[i], buffer);
  2597. var len = buffer.offset-start,
  2598. varintLen = ByteBuffer.calculateVarint32(len);
  2599. if (varintLen > 1) { // We need to move the contents
  2600. var contents = buffer.slice(start, buffer.offset);
  2601. start += varintLen-1;
  2602. buffer.offset = start;
  2603. buffer.append(contents);
  2604. }
  2605. buffer.writeVarint32(len, start-varintLen);
  2606. } else {
  2607. // "If your message definition has repeated elements (without the [packed=true] option), the encoded
  2608. // message has zero or more key-value pairs with the same tag number"
  2609. for (i=0; i<value.length; i++)
  2610. buffer.writeVarint32((this.id << 3) | this.type.wireType),
  2611. this.encodeValue(value[i], buffer);
  2612. }
  2613. } else
  2614. buffer.writeVarint32((this.id << 3) | this.type.wireType),
  2615. this.encodeValue(value, buffer);
  2616. } catch (e) {
  2617. throw Error("Illegal value for "+this.toString(true)+": "+value+" ("+e+")");
  2618. }
  2619. return buffer;
  2620. };
  2621. /**
  2622. * Encodes a value to the specified buffer. Does not encode the key.
  2623. * @param {*} value Field value
  2624. * @param {ByteBuffer} buffer ByteBuffer to encode to
  2625. * @return {ByteBuffer} The ByteBuffer for chaining
  2626. * @throws {Error} If the value cannot be encoded
  2627. * @expose
  2628. */
  2629. FieldPrototype.encodeValue = function(value, buffer) {
  2630. if (value === null) return buffer; // Nothing to encode
  2631. // Tag has already been written
  2632. switch (this.type) {
  2633. // 32bit signed varint
  2634. case ProtoBuf.TYPES["int32"]:
  2635. // "If you use int32 or int64 as the type for a negative number, the resulting varint is always ten bytes
  2636. // long – it is, effectively, treated like a very large unsigned integer." (see #122)
  2637. if (value < 0)
  2638. buffer.writeVarint64(value);
  2639. else
  2640. buffer.writeVarint32(value);
  2641. break;
  2642. // 32bit unsigned varint
  2643. case ProtoBuf.TYPES["uint32"]:
  2644. buffer.writeVarint32(value);
  2645. break;
  2646. // 32bit varint zig-zag
  2647. case ProtoBuf.TYPES["sint32"]:
  2648. buffer.writeVarint32ZigZag(value);
  2649. break;
  2650. // Fixed unsigned 32bit
  2651. case ProtoBuf.TYPES["fixed32"]:
  2652. buffer.writeUint32(value);
  2653. break;
  2654. // Fixed signed 32bit
  2655. case ProtoBuf.TYPES["sfixed32"]:
  2656. buffer.writeInt32(value);
  2657. break;
  2658. // 64bit varint as-is
  2659. case ProtoBuf.TYPES["int64"]:
  2660. case ProtoBuf.TYPES["uint64"]:
  2661. buffer.writeVarint64(value); // throws
  2662. break;
  2663. // 64bit varint zig-zag
  2664. case ProtoBuf.TYPES["sint64"]:
  2665. buffer.writeVarint64ZigZag(value); // throws
  2666. break;
  2667. // Fixed unsigned 64bit
  2668. case ProtoBuf.TYPES["fixed64"]:
  2669. buffer.writeUint64(value); // throws
  2670. break;
  2671. // Fixed signed 64bit
  2672. case ProtoBuf.TYPES["sfixed64"]:
  2673. buffer.writeInt64(value); // throws
  2674. break;
  2675. // Bool
  2676. case ProtoBuf.TYPES["bool"]:
  2677. if (typeof value === 'string')
  2678. buffer.writeVarint32(value.toLowerCase() === 'false' ? 0 : !!value);
  2679. else
  2680. buffer.writeVarint32(value ? 1 : 0);
  2681. break;
  2682. // Constant enum value
  2683. case ProtoBuf.TYPES["enum"]:
  2684. buffer.writeVarint32(value);
  2685. break;
  2686. // 32bit float
  2687. case ProtoBuf.TYPES["float"]:
  2688. buffer.writeFloat32(value);
  2689. break;
  2690. // 64bit float
  2691. case ProtoBuf.TYPES["double"]:
  2692. buffer.writeFloat64(value);
  2693. break;
  2694. // Length-delimited string
  2695. case ProtoBuf.TYPES["string"]:
  2696. buffer.writeVString(value);
  2697. break;
  2698. // Length-delimited bytes
  2699. case ProtoBuf.TYPES["bytes"]:
  2700. if (value.remaining() < 0)
  2701. throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining");
  2702. var prevOffset = value.offset;
  2703. buffer.writeVarint32(value.remaining());
  2704. buffer.append(value);
  2705. value.offset = prevOffset;
  2706. break;
  2707. // Embedded message
  2708. case ProtoBuf.TYPES["message"]:
  2709. var bb = new ByteBuffer().LE();
  2710. this.resolvedType.encode(value, bb);
  2711. buffer.writeVarint32(bb.offset);
  2712. buffer.append(bb.flip());
  2713. break;
  2714. // Legacy group
  2715. case ProtoBuf.TYPES["group"]:
  2716. this.resolvedType.encode(value, buffer);
  2717. buffer.writeVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP);
  2718. break;
  2719. default:
  2720. // We should never end here
  2721. throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)");
  2722. }
  2723. return buffer;
  2724. };
  2725. /**
  2726. * Calculates the length of this field's value on the network level.
  2727. * @param {*} value Field value
  2728. * @returns {number} Byte length
  2729. * @expose
  2730. */
  2731. FieldPrototype.calculate = function(value) {
  2732. value = this.verifyValue(value); // May throw
  2733. if (this.type === null || typeof this.type !== 'object')
  2734. throw Error("[INTERNAL] Unresolved type in "+this.toString(true)+": "+this.type);
  2735. if (value === null || (this.repeated && value.length == 0))
  2736. return 0; // Optional omitted
  2737. var n = 0;
  2738. try {
  2739. if (this.repeated) {
  2740. var i, ni;
  2741. if (this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) {
  2742. n += ByteBuffer.calculateVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);
  2743. ni = 0;
  2744. for (i=0; i<value.length; i++)
  2745. ni += this.calculateValue(value[i]);
  2746. n += ByteBuffer.calculateVarint32(ni);
  2747. n += ni;
  2748. } else {
  2749. for (i=0; i<value.length; i++)
  2750. n += ByteBuffer.calculateVarint32((this.id << 3) | this.type.wireType),
  2751. n += this.calculateValue(value[i]);
  2752. }
  2753. } else {
  2754. n += ByteBuffer.calculateVarint32((this.id << 3) | this.type.wireType);
  2755. n += this.calculateValue(value);
  2756. }
  2757. } catch (e) {
  2758. throw Error("Illegal value for "+this.toString(true)+": "+value+" ("+e+")");
  2759. }
  2760. return n;
  2761. };
  2762. /**
  2763. * Calculates the byte length of a value.
  2764. * @param {*} value Field value
  2765. * @returns {number} Byte length
  2766. * @throws {Error} If the value cannot be calculated
  2767. * @expose
  2768. */
  2769. FieldPrototype.calculateValue = function(value) {
  2770. if (value === null) return 0; // Nothing to encode
  2771. // Tag has already been written
  2772. var n;
  2773. switch (this.type) {
  2774. case ProtoBuf.TYPES["int32"]:
  2775. return value < 0 ? ByteBuffer.calculateVarint64(value) : ByteBuffer.calculateVarint32(value);
  2776. case ProtoBuf.TYPES["uint32"]:
  2777. return ByteBuffer.calculateVarint32(value);
  2778. case ProtoBuf.TYPES["sint32"]:
  2779. return ByteBuffer.calculateVarint32(ByteBuffer.zigZagEncode32(value));
  2780. case ProtoBuf.TYPES["fixed32"]:
  2781. case ProtoBuf.TYPES["sfixed32"]:
  2782. case ProtoBuf.TYPES["float"]:
  2783. return 4;
  2784. case ProtoBuf.TYPES["int64"]:
  2785. case ProtoBuf.TYPES["uint64"]:
  2786. return ByteBuffer.calculateVarint64(value);
  2787. case ProtoBuf.TYPES["sint64"]:
  2788. return ByteBuffer.calculateVarint64(ByteBuffer.zigZagEncode64(value));
  2789. case ProtoBuf.TYPES["fixed64"]:
  2790. case ProtoBuf.TYPES["sfixed64"]:
  2791. return 8;
  2792. case ProtoBuf.TYPES["bool"]:
  2793. return 1;
  2794. case ProtoBuf.TYPES["enum"]:
  2795. return ByteBuffer.calculateVarint32(value);
  2796. case ProtoBuf.TYPES["double"]:
  2797. return 8;
  2798. case ProtoBuf.TYPES["string"]:
  2799. n = ByteBuffer.calculateUTF8Bytes(value);
  2800. return ByteBuffer.calculateVarint32(n) + n;
  2801. case ProtoBuf.TYPES["bytes"]:
  2802. if (value.remaining() < 0)
  2803. throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining");
  2804. return ByteBuffer.calculateVarint32(value.remaining()) + value.remaining();
  2805. case ProtoBuf.TYPES["message"]:
  2806. n = this.resolvedType.calculate(value);
  2807. return ByteBuffer.calculateVarint32(n) + n;
  2808. case ProtoBuf.TYPES["group"]:
  2809. n = this.resolvedType.calculate(value);
  2810. return n + ByteBuffer.calculateVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP);
  2811. }
  2812. // We should never end here
  2813. throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)");
  2814. };
  2815. /**
  2816. * Decode the field value from the specified buffer.
  2817. * @param {number} wireType Leading wire type
  2818. * @param {ByteBuffer} buffer ByteBuffer to decode from
  2819. * @param {boolean=} skipRepeated Whether to skip the repeated check or not. Defaults to false.
  2820. * @return {*} Decoded value
  2821. * @throws {Error} If the field cannot be decoded
  2822. * @expose
  2823. */
  2824. FieldPrototype.decode = function(wireType, buffer, skipRepeated) {
  2825. var value, nBytes;
  2826. if (wireType != this.type.wireType && (skipRepeated || (wireType != ProtoBuf.WIRE_TYPES.LDELIM || !this.repeated)))
  2827. throw Error("Illegal wire type for field "+this.toString(true)+": "+wireType+" ("+this.type.wireType+" expected)");
  2828. if (wireType == ProtoBuf.WIRE_TYPES.LDELIM && this.repeated && this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) {
  2829. if (!skipRepeated) {
  2830. nBytes = buffer.readVarint32();
  2831. nBytes = buffer.offset + nBytes; // Limit
  2832. var values = [];
  2833. while (buffer.offset < nBytes)
  2834. values.push(this.decode(this.type.wireType, buffer, true));
  2835. return values;
  2836. }
  2837. // Read the next value otherwise...
  2838. }
  2839. switch (this.type) {
  2840. // 32bit signed varint
  2841. case ProtoBuf.TYPES["int32"]:
  2842. return buffer.readVarint32() | 0;
  2843. // 32bit unsigned varint
  2844. case ProtoBuf.TYPES["uint32"]:
  2845. return buffer.readVarint32() >>> 0;
  2846. // 32bit signed varint zig-zag
  2847. case ProtoBuf.TYPES["sint32"]:
  2848. return buffer.readVarint32ZigZag() | 0;
  2849. // Fixed 32bit unsigned
  2850. case ProtoBuf.TYPES["fixed32"]:
  2851. return buffer.readUint32() >>> 0;
  2852. case ProtoBuf.TYPES["sfixed32"]:
  2853. return buffer.readInt32() | 0;
  2854. // 64bit signed varint
  2855. case ProtoBuf.TYPES["int64"]:
  2856. return buffer.readVarint64();
  2857. // 64bit unsigned varint
  2858. case ProtoBuf.TYPES["uint64"]:
  2859. return buffer.readVarint64().toUnsigned();
  2860. // 64bit signed varint zig-zag
  2861. case ProtoBuf.TYPES["sint64"]:
  2862. return buffer.readVarint64ZigZag();
  2863. // Fixed 64bit unsigned
  2864. case ProtoBuf.TYPES["fixed64"]:
  2865. return buffer.readUint64();
  2866. // Fixed 64bit signed
  2867. case ProtoBuf.TYPES["sfixed64"]:
  2868. return buffer.readInt64();
  2869. // Bool varint
  2870. case ProtoBuf.TYPES["bool"]:
  2871. return !!buffer.readVarint32();
  2872. // Constant enum value (varint)
  2873. case ProtoBuf.TYPES["enum"]:
  2874. // The following Builder.Message#set will already throw
  2875. return buffer.readVarint32();
  2876. // 32bit float
  2877. case ProtoBuf.TYPES["float"]:
  2878. return buffer.readFloat();
  2879. // 64bit float
  2880. case ProtoBuf.TYPES["double"]:
  2881. return buffer.readDouble();
  2882. // Length-delimited string
  2883. case ProtoBuf.TYPES["string"]:
  2884. return buffer.readVString();
  2885. // Length-delimited bytes
  2886. case ProtoBuf.TYPES["bytes"]: {
  2887. nBytes = buffer.readVarint32();
  2888. if (buffer.remaining() < nBytes)
  2889. throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining());
  2890. value = buffer.clone(); // Offset already set
  2891. value.limit = value.offset+nBytes;
  2892. buffer.offset += nBytes;
  2893. return value;
  2894. }
  2895. // Length-delimited embedded message
  2896. case ProtoBuf.TYPES["message"]: {
  2897. nBytes = buffer.readVarint32();
  2898. return this.resolvedType.decode(buffer, nBytes);
  2899. }
  2900. // Legacy group
  2901. case ProtoBuf.TYPES["group"]:
  2902. return this.resolvedType.decode(buffer, -1, this.id);
  2903. }
  2904. // We should never end here
  2905. throw Error("[INTERNAL] Illegal wire type for "+this.toString(true)+": "+wireType);
  2906. };
  2907. /**
  2908. * @alias ProtoBuf.Reflect.Message.Field
  2909. * @expose
  2910. */
  2911. Reflect.Message.Field = Field;
  2912. /**
  2913. * Constructs a new Message ExtensionField.
  2914. * @exports ProtoBuf.Reflect.Message.ExtensionField
  2915. * @param {!ProtoBuf.Builder} builder Builder reference
  2916. * @param {!ProtoBuf.Reflect.Message} message Message reference
  2917. * @param {string} rule Rule, one of requried, optional, repeated
  2918. * @param {string} type Data type, e.g. int32
  2919. * @param {string} name Field name
  2920. * @param {number} id Unique field id
  2921. * @param {Object.<string,*>=} options Options
  2922. * @constructor
  2923. * @extends ProtoBuf.Reflect.Message.Field
  2924. */
  2925. var ExtensionField = function(builder, message, rule, type, name, id, options) {
  2926. Field.call(this, builder, message, rule, type, name, id, options);
  2927. /**
  2928. * Extension reference.
  2929. * @type {!ProtoBuf.Reflect.Extension}
  2930. * @expose
  2931. */
  2932. this.extension;
  2933. };
  2934. // Extends Field
  2935. ExtensionField.prototype = Object.create(Field.prototype);
  2936. /**
  2937. * @alias ProtoBuf.Reflect.Message.ExtensionField
  2938. * @expose
  2939. */
  2940. Reflect.Message.ExtensionField = ExtensionField;
  2941. /**
  2942. * Constructs a new Message OneOf.
  2943. * @exports ProtoBuf.Reflect.Message.OneOf
  2944. * @param {!ProtoBuf.Builder} builder Builder reference
  2945. * @param {!ProtoBuf.Reflect.Message} message Message reference
  2946. * @param {string} name OneOf name
  2947. * @constructor
  2948. * @extends ProtoBuf.Reflect.T
  2949. */
  2950. var OneOf = function(builder, message, name) {
  2951. T.call(this, builder, message, name);
  2952. /**
  2953. * Enclosed fields.
  2954. * @type {!Array.<!ProtoBuf.Reflect.Message.Field>}
  2955. * @expose
  2956. */
  2957. this.fields = [];
  2958. };
  2959. /**
  2960. * @alias ProtoBuf.Reflect.Message.OneOf
  2961. * @expose
  2962. */
  2963. Reflect.Message.OneOf = OneOf;
  2964. /**
  2965. * Constructs a new Enum.
  2966. * @exports ProtoBuf.Reflect.Enum
  2967. * @param {!ProtoBuf.Builder} builder Builder reference
  2968. * @param {!ProtoBuf.Reflect.T} parent Parent Reflect object
  2969. * @param {string} name Enum name
  2970. * @param {Object.<string,*>=} options Enum options
  2971. * @constructor
  2972. * @extends ProtoBuf.Reflect.Namespace
  2973. */
  2974. var Enum = function(builder, parent, name, options) {
  2975. Namespace.call(this, builder, parent, name, options);
  2976. /**
  2977. * @override
  2978. */
  2979. this.className = "Enum";
  2980. /**
  2981. * Runtime enum object.
  2982. * @type {Object.<string,number>|null}
  2983. * @expose
  2984. */
  2985. this.object = null;
  2986. };
  2987. /**
  2988. * @alias ProtoBuf.Reflect.Enum.prototype
  2989. * @inner
  2990. */
  2991. var EnumPrototype = Enum.prototype = Object.create(Namespace.prototype);
  2992. /**
  2993. * Builds this enum and returns the runtime counterpart.
  2994. * @return {Object<string,*>}
  2995. * @expose
  2996. */
  2997. EnumPrototype.build = function() {
  2998. var enm = {},
  2999. values = this.getChildren(Enum.Value);
  3000. for (var i=0, k=values.length; i<k; ++i)
  3001. enm[values[i]['name']] = values[i]['id'];
  3002. if (Object.defineProperty)
  3003. Object.defineProperty(enm, '$options', { "value": this.buildOpt() });
  3004. return this.object = enm;
  3005. };
  3006. /**
  3007. * @alias ProtoBuf.Reflect.Enum
  3008. * @expose
  3009. */
  3010. Reflect.Enum = Enum;
  3011. /**
  3012. * Constructs a new Enum Value.
  3013. * @exports ProtoBuf.Reflect.Enum.Value
  3014. * @param {!ProtoBuf.Builder} builder Builder reference
  3015. * @param {!ProtoBuf.Reflect.Enum} enm Enum reference
  3016. * @param {string} name Field name
  3017. * @param {number} id Unique field id
  3018. * @constructor
  3019. * @extends ProtoBuf.Reflect.T
  3020. */
  3021. var Value = function(builder, enm, name, id) {
  3022. T.call(this, builder, enm, name);
  3023. /**
  3024. * @override
  3025. */
  3026. this.className = "Enum.Value";
  3027. /**
  3028. * Unique enum value id.
  3029. * @type {number}
  3030. * @expose
  3031. */
  3032. this.id = id;
  3033. };
  3034. // Extends T
  3035. Value.prototype = Object.create(T.prototype);
  3036. /**
  3037. * @alias ProtoBuf.Reflect.Enum.Value
  3038. * @expose
  3039. */
  3040. Reflect.Enum.Value = Value;
  3041. /**
  3042. * An extension (field).
  3043. * @exports ProtoBuf.Reflect.Extension
  3044. * @constructor
  3045. * @param {!ProtoBuf.Builder} builder Builder reference
  3046. * @param {!ProtoBuf.Reflect.T} parent Parent object
  3047. * @param {string} name Object name
  3048. * @param {!ProtoBuf.Reflect.Message.Field} field Extension field
  3049. */
  3050. var Extension = function(builder, parent, name, field) {
  3051. T.call(this, builder, parent, name);
  3052. /**
  3053. * Extended message field.
  3054. * @type {!ProtoBuf.Reflect.Message.Field}
  3055. * @expose
  3056. */
  3057. this.field = field;
  3058. };
  3059. // Extends T
  3060. Extension.prototype = Object.create(T.prototype);
  3061. /**
  3062. * @alias ProtoBuf.Reflect.Extension
  3063. * @expose
  3064. */
  3065. Reflect.Extension = Extension;
  3066. /**
  3067. * Constructs a new Service.
  3068. * @exports ProtoBuf.Reflect.Service
  3069. * @param {!ProtoBuf.Builder} builder Builder reference
  3070. * @param {!ProtoBuf.Reflect.Namespace} root Root
  3071. * @param {string} name Service name
  3072. * @param {Object.<string,*>=} options Options
  3073. * @constructor
  3074. * @extends ProtoBuf.Reflect.Namespace
  3075. */
  3076. var Service = function(builder, root, name, options) {
  3077. Namespace.call(this, builder, root, name, options);
  3078. /**
  3079. * @override
  3080. */
  3081. this.className = "Service";
  3082. /**
  3083. * Built runtime service class.
  3084. * @type {?function(new:ProtoBuf.Builder.Service)}
  3085. */
  3086. this.clazz = null;
  3087. };
  3088. /**
  3089. * @alias ProtoBuf.Reflect.Service.prototype
  3090. * @inner
  3091. */
  3092. var ServicePrototype = Service.prototype = Object.create(Namespace.prototype);
  3093. /**
  3094. * Builds the service and returns the runtime counterpart, which is a fully functional class.
  3095. * @see ProtoBuf.Builder.Service
  3096. * @param {boolean=} rebuild Whether to rebuild or not
  3097. * @return {Function} Service class
  3098. * @throws {Error} If the message cannot be built
  3099. * @expose
  3100. */
  3101. ServicePrototype.build = function(rebuild) {
  3102. if (this.clazz && !rebuild)
  3103. return this.clazz;
  3104. // Create the runtime Service class in its own scope
  3105. return this.clazz = (function(ProtoBuf, T) {
  3106. /**
  3107. * Constructs a new runtime Service.
  3108. * @name ProtoBuf.Builder.Service
  3109. * @param {function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))=} rpcImpl RPC implementation receiving the method name and the message
  3110. * @class Barebone of all runtime services.
  3111. * @constructor
  3112. * @throws {Error} If the service cannot be created
  3113. */
  3114. var Service = function(rpcImpl) {
  3115. ProtoBuf.Builder.Service.call(this);
  3116. /**
  3117. * Service implementation.
  3118. * @name ProtoBuf.Builder.Service#rpcImpl
  3119. * @type {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))}
  3120. * @expose
  3121. */
  3122. this.rpcImpl = rpcImpl || function(name, msg, callback) {
  3123. // This is what a user has to implement: A function receiving the method name, the actual message to
  3124. // send (type checked) and the callback that's either provided with the error as its first
  3125. // argument or null and the actual response message.
  3126. setTimeout(callback.bind(this, Error("Not implemented, see: https://github.com/dcodeIO/ProtoBuf.js/wiki/Services")), 0); // Must be async!
  3127. };
  3128. };
  3129. /**
  3130. * @alias ProtoBuf.Builder.Service.prototype
  3131. * @inner
  3132. */
  3133. var ServicePrototype = Service.prototype = Object.create(ProtoBuf.Builder.Service.prototype);
  3134. if (Object.defineProperty)
  3135. Object.defineProperty(Service, "$options", { "value": T.buildOpt() }),
  3136. Object.defineProperty(ServicePrototype, "$options", { "value": Service["$options"] });
  3137. /**
  3138. * Asynchronously performs an RPC call using the given RPC implementation.
  3139. * @name ProtoBuf.Builder.Service.[Method]
  3140. * @function
  3141. * @param {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))} rpcImpl RPC implementation
  3142. * @param {ProtoBuf.Builder.Message} req Request
  3143. * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving
  3144. * the error if any and the response either as a pre-parsed message or as its raw bytes
  3145. * @abstract
  3146. */
  3147. /**
  3148. * Asynchronously performs an RPC call using the instance's RPC implementation.
  3149. * @name ProtoBuf.Builder.Service#[Method]
  3150. * @function
  3151. * @param {ProtoBuf.Builder.Message} req Request
  3152. * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving
  3153. * the error if any and the response either as a pre-parsed message or as its raw bytes
  3154. * @abstract
  3155. */
  3156. var rpc = T.getChildren(ProtoBuf.Reflect.Service.RPCMethod);
  3157. for (var i=0; i<rpc.length; i++) {
  3158. (function(method) {
  3159. // service#Method(message, callback)
  3160. ServicePrototype[method.name] = function(req, callback) {
  3161. try {
  3162. if (!req || !(req instanceof method.resolvedRequestType.clazz)) {
  3163. setTimeout(callback.bind(this, Error("Illegal request type provided to service method "+T.name+"#"+method.name)), 0);
  3164. return;
  3165. }
  3166. this.rpcImpl(method.fqn(), req, function(err, res) { // Assumes that this is properly async
  3167. if (err) {
  3168. callback(err);
  3169. return;
  3170. }
  3171. try { res = method.resolvedResponseType.clazz.decode(res); } catch (notABuffer) {}
  3172. if (!res || !(res instanceof method.resolvedResponseType.clazz)) {
  3173. callback(Error("Illegal response type received in service method "+ T.name+"#"+method.name));
  3174. return;
  3175. }
  3176. callback(null, res);
  3177. });
  3178. } catch (err) {
  3179. setTimeout(callback.bind(this, err), 0);
  3180. }
  3181. };
  3182. // Service.Method(rpcImpl, message, callback)
  3183. Service[method.name] = function(rpcImpl, req, callback) {
  3184. new Service(rpcImpl)[method.name](req, callback);
  3185. };
  3186. if (Object.defineProperty)
  3187. Object.defineProperty(Service[method.name], "$options", { "value": method.buildOpt() }),
  3188. Object.defineProperty(ServicePrototype[method.name], "$options", { "value": Service[method.name]["$options"] });
  3189. })(rpc[i]);
  3190. }
  3191. return Service;
  3192. })(ProtoBuf, this);
  3193. };
  3194. /**
  3195. * @alias ProtoBuf.Reflect.Service
  3196. * @expose
  3197. */
  3198. Reflect.Service = Service;
  3199. /**
  3200. * Abstract service method.
  3201. * @exports ProtoBuf.Reflect.Service.Method
  3202. * @param {!ProtoBuf.Builder} builder Builder reference
  3203. * @param {!ProtoBuf.Reflect.Service} svc Service
  3204. * @param {string} name Method name
  3205. * @param {Object.<string,*>=} options Options
  3206. * @constructor
  3207. * @extends ProtoBuf.Reflect.T
  3208. */
  3209. var Method = function(builder, svc, name, options) {
  3210. T.call(this, builder, svc, name);
  3211. /**
  3212. * @override
  3213. */
  3214. this.className = "Service.Method";
  3215. /**
  3216. * Options.
  3217. * @type {Object.<string, *>}
  3218. * @expose
  3219. */
  3220. this.options = options || {};
  3221. };
  3222. /**
  3223. * @alias ProtoBuf.Reflect.Service.Method.prototype
  3224. * @inner
  3225. */
  3226. var MethodPrototype = Method.prototype = Object.create(T.prototype);
  3227. /**
  3228. * Builds the method's '$options' property.
  3229. * @name ProtoBuf.Reflect.Service.Method#buildOpt
  3230. * @function
  3231. * @return {Object.<string,*>}
  3232. */
  3233. MethodPrototype.buildOpt = NamespacePrototype.buildOpt;
  3234. /**
  3235. * @alias ProtoBuf.Reflect.Service.Method
  3236. * @expose
  3237. */
  3238. Reflect.Service.Method = Method;
  3239. /**
  3240. * RPC service method.
  3241. * @exports ProtoBuf.Reflect.Service.RPCMethod
  3242. * @param {!ProtoBuf.Builder} builder Builder reference
  3243. * @param {!ProtoBuf.Reflect.Service} svc Service
  3244. * @param {string} name Method name
  3245. * @param {string} request Request message name
  3246. * @param {string} response Response message name
  3247. * @param {Object.<string,*>=} options Options
  3248. * @constructor
  3249. * @extends ProtoBuf.Reflect.Service.Method
  3250. */
  3251. var RPCMethod = function(builder, svc, name, request, response, options) {
  3252. Method.call(this, builder, svc, name, options);
  3253. /**
  3254. * @override
  3255. */
  3256. this.className = "Service.RPCMethod";
  3257. /**
  3258. * Request message name.
  3259. * @type {string}
  3260. * @expose
  3261. */
  3262. this.requestName = request;
  3263. /**
  3264. * Response message name.
  3265. * @type {string}
  3266. * @expose
  3267. */
  3268. this.responseName = response;
  3269. /**
  3270. * Resolved request message type.
  3271. * @type {ProtoBuf.Reflect.Message}
  3272. * @expose
  3273. */
  3274. this.resolvedRequestType = null;
  3275. /**
  3276. * Resolved response message type.
  3277. * @type {ProtoBuf.Reflect.Message}
  3278. * @expose
  3279. */
  3280. this.resolvedResponseType = null;
  3281. };
  3282. // Extends Method
  3283. RPCMethod.prototype = Object.create(Method.prototype);
  3284. /**
  3285. * @alias ProtoBuf.Reflect.Service.RPCMethod
  3286. * @expose
  3287. */
  3288. Reflect.Service.RPCMethod = RPCMethod;
  3289. return Reflect;
  3290. })(ProtoBuf);
  3291. /**
  3292. * @alias ProtoBuf.Builder
  3293. * @expose
  3294. */
  3295. ProtoBuf.Builder = (function(ProtoBuf, Lang, Reflect) {
  3296. "use strict";
  3297. /**
  3298. * Constructs a new Builder.
  3299. * @exports ProtoBuf.Builder
  3300. * @class Provides the functionality to build protocol messages.
  3301. * @param {Object.<string,*>=} options Options
  3302. * @constructor
  3303. */
  3304. var Builder = function(options) {
  3305. /**
  3306. * Namespace.
  3307. * @type {ProtoBuf.Reflect.Namespace}
  3308. * @expose
  3309. */
  3310. this.ns = new Reflect.Namespace(this, null, ""); // Global namespace
  3311. /**
  3312. * Namespace pointer.
  3313. * @type {ProtoBuf.Reflect.T}
  3314. * @expose
  3315. */
  3316. this.ptr = this.ns;
  3317. /**
  3318. * Resolved flag.
  3319. * @type {boolean}
  3320. * @expose
  3321. */
  3322. this.resolved = false;
  3323. /**
  3324. * The current building result.
  3325. * @type {Object.<string,ProtoBuf.Builder.Message|Object>|null}
  3326. * @expose
  3327. */
  3328. this.result = null;
  3329. /**
  3330. * Imported files.
  3331. * @type {Array.<string>}
  3332. * @expose
  3333. */
  3334. this.files = {};
  3335. /**
  3336. * Import root override.
  3337. * @type {?string}
  3338. * @expose
  3339. */
  3340. this.importRoot = null;
  3341. /**
  3342. * Options.
  3343. * @type {!Object.<string, *>}
  3344. * @expose
  3345. */
  3346. this.options = options || {};
  3347. };
  3348. /**
  3349. * @alias ProtoBuf.Builder.prototype
  3350. * @inner
  3351. */
  3352. var BuilderPrototype = Builder.prototype;
  3353. /**
  3354. * Resets the pointer to the root namespace.
  3355. * @expose
  3356. */
  3357. BuilderPrototype.reset = function() {
  3358. this.ptr = this.ns;
  3359. };
  3360. /**
  3361. * Defines a package on top of the current pointer position and places the pointer on it.
  3362. * @param {string} pkg
  3363. * @param {Object.<string,*>=} options
  3364. * @return {ProtoBuf.Builder} this
  3365. * @throws {Error} If the package name is invalid
  3366. * @expose
  3367. */
  3368. BuilderPrototype.define = function(pkg, options) {
  3369. if (typeof pkg !== 'string' || !Lang.TYPEREF.test(pkg))
  3370. throw Error("Illegal package: "+pkg);
  3371. var part = pkg.split("."), i;
  3372. for (i=0; i<part.length; i++) // To be absolutely sure
  3373. if (!Lang.NAME.test(part[i]))
  3374. throw Error("Illegal package: "+part[i]);
  3375. for (i=0; i<part.length; i++) {
  3376. if (this.ptr.getChild(part[i]) === null) // Keep existing namespace
  3377. this.ptr.addChild(new Reflect.Namespace(this, this.ptr, part[i], options));
  3378. this.ptr = this.ptr.getChild(part[i]);
  3379. }
  3380. return this;
  3381. };
  3382. /**
  3383. * Tests if a definition is a valid message definition.
  3384. * @param {Object.<string,*>} def Definition
  3385. * @return {boolean} true if valid, else false
  3386. * @expose
  3387. */
  3388. Builder.isValidMessage = function(def) {
  3389. // Messages require a string name
  3390. if (typeof def["name"] !== 'string' || !Lang.NAME.test(def["name"]))
  3391. return false;
  3392. // Messages must not contain values (that'd be an enum) or methods (that'd be a service)
  3393. if (typeof def["values"] !== 'undefined' || typeof def["rpc"] !== 'undefined')
  3394. return false;
  3395. // Fields, enums and messages are arrays if provided
  3396. var i;
  3397. if (typeof def["fields"] !== 'undefined') {
  3398. if (!ProtoBuf.Util.isArray(def["fields"]))
  3399. return false;
  3400. var ids = [], id; // IDs must be unique
  3401. for (i=0; i<def["fields"].length; i++) {
  3402. if (!Builder.isValidMessageField(def["fields"][i]))
  3403. return false;
  3404. id = parseInt(def["fields"][i]["id"], 10);
  3405. if (ids.indexOf(id) >= 0)
  3406. return false;
  3407. ids.push(id);
  3408. }
  3409. ids = null;
  3410. }
  3411. if (typeof def["enums"] !== 'undefined') {
  3412. if (!ProtoBuf.Util.isArray(def["enums"]))
  3413. return false;
  3414. for (i=0; i<def["enums"].length; i++)
  3415. if (!Builder.isValidEnum(def["enums"][i]))
  3416. return false;
  3417. }
  3418. if (typeof def["messages"] !== 'undefined') {
  3419. if (!ProtoBuf.Util.isArray(def["messages"]))
  3420. return false;
  3421. for (i=0; i<def["messages"].length; i++)
  3422. if (!Builder.isValidMessage(def["messages"][i]) && !Builder.isValidExtend(def["messages"][i]))
  3423. return false;
  3424. }
  3425. if (typeof def["extensions"] !== 'undefined')
  3426. if (!ProtoBuf.Util.isArray(def["extensions"]) || def["extensions"].length !== 2 || typeof def["extensions"][0] !== 'number' || typeof def["extensions"][1] !== 'number')
  3427. return false;
  3428. return true;
  3429. };
  3430. /**
  3431. * Tests if a definition is a valid message field definition.
  3432. * @param {Object} def Definition
  3433. * @return {boolean} true if valid, else false
  3434. * @expose
  3435. */
  3436. Builder.isValidMessageField = function(def) {
  3437. // Message fields require a string rule, name and type and an id
  3438. if (typeof def["rule"] !== 'string' || typeof def["name"] !== 'string' || typeof def["type"] !== 'string' || typeof def["id"] === 'undefined')
  3439. return false;
  3440. if (!Lang.RULE.test(def["rule"]) || !Lang.NAME.test(def["name"]) || !Lang.TYPEREF.test(def["type"]) || !Lang.ID.test(""+def["id"]))
  3441. return false;
  3442. if (typeof def["options"] !== 'undefined') {
  3443. // Options are objects
  3444. if (typeof def["options"] !== 'object')
  3445. return false;
  3446. // Options are <string,string|number|boolean>
  3447. var keys = Object.keys(def["options"]);
  3448. for (var i=0, key; i<keys.length; i++)
  3449. if (typeof (key = keys[i]) !== 'string' || (typeof def["options"][key] !== 'string' && typeof def["options"][key] !== 'number' && typeof def["options"][key] !== 'boolean'))
  3450. return false;
  3451. }
  3452. return true;
  3453. };
  3454. /**
  3455. * Tests if a definition is a valid enum definition.
  3456. * @param {Object} def Definition
  3457. * @return {boolean} true if valid, else false
  3458. * @expose
  3459. */
  3460. Builder.isValidEnum = function(def) {
  3461. // Enums require a string name
  3462. if (typeof def["name"] !== 'string' || !Lang.NAME.test(def["name"]))
  3463. return false;
  3464. // Enums require at least one value
  3465. if (typeof def["values"] === 'undefined' || !ProtoBuf.Util.isArray(def["values"]) || def["values"].length == 0)
  3466. return false;
  3467. for (var i=0; i<def["values"].length; i++) {
  3468. // Values are objects
  3469. if (typeof def["values"][i] != "object")
  3470. return false;
  3471. // Values require a string name and an id
  3472. if (typeof def["values"][i]["name"] !== 'string' || typeof def["values"][i]["id"] === 'undefined')
  3473. return false;
  3474. if (!Lang.NAME.test(def["values"][i]["name"]) || !Lang.NEGID.test(""+def["values"][i]["id"]))
  3475. return false;
  3476. }
  3477. // It's not important if there are other fields because ["values"] is already unique
  3478. return true;
  3479. };
  3480. /**
  3481. * Creates ths specified protocol types at the current pointer position.
  3482. * @param {Array.<Object.<string,*>>} defs Messages, enums or services to create
  3483. * @return {ProtoBuf.Builder} this
  3484. * @throws {Error} If a message definition is invalid
  3485. * @expose
  3486. */
  3487. BuilderPrototype.create = function(defs) {
  3488. if (!defs)
  3489. return this; // Nothing to create
  3490. if (!ProtoBuf.Util.isArray(defs))
  3491. defs = [defs];
  3492. if (defs.length == 0)
  3493. return this;
  3494. // It's quite hard to keep track of scopes and memory here, so let's do this iteratively.
  3495. var stack = [];
  3496. stack.push(defs); // One level [a, b, c]
  3497. while (stack.length > 0) {
  3498. defs = stack.pop();
  3499. if (ProtoBuf.Util.isArray(defs)) { // Stack always contains entire namespaces
  3500. while (defs.length > 0) {
  3501. var def = defs.shift(); // Namespace always contains an array of messages, enums and services
  3502. if (Builder.isValidMessage(def)) {
  3503. var obj = new Reflect.Message(this, this.ptr, def["name"], def["options"], def["isGroup"]);
  3504. // Create OneOfs
  3505. var oneofs = {};
  3506. if (def["oneofs"]) {
  3507. var keys = Object.keys(def["oneofs"]);
  3508. for (var i=0, k=keys.length; i<k; ++i)
  3509. obj.addChild(oneofs[keys[i]] = new Reflect.Message.OneOf(this, obj, keys[i]));
  3510. }
  3511. // Create fields
  3512. if (def["fields"] && def["fields"].length > 0) {
  3513. for (i=0, k=def["fields"].length; i<k; ++i) { // i:k=Fields
  3514. var fld = def['fields'][i];
  3515. if (obj.getChild(fld['id']) !== null)
  3516. throw Error("Duplicate field id in message "+obj.name+": "+fld['id']);
  3517. if (fld["options"]) {
  3518. var opts = Object.keys(fld["options"]);
  3519. for (var j= 0,l=opts.length; j<l; ++j) { // j:l=Option names
  3520. if (typeof opts[j] !== 'string')
  3521. throw Error("Illegal field option name in message "+obj.name+"#"+fld["name"]+": "+opts[j]);
  3522. if (typeof fld["options"][opts[j]] !== 'string' && typeof fld["options"][opts[j]] !== 'number' && typeof fld["options"][opts[j]] !== 'boolean')
  3523. throw Error("Illegal field option value in message "+obj.name+"#"+fld["name"]+"#"+opts[j]+": "+fld["options"][opts[j]]);
  3524. }
  3525. }
  3526. var oneof = null;
  3527. if (typeof fld["oneof"] === 'string') {
  3528. oneof = oneofs[fld["oneof"]];
  3529. if (typeof oneof === 'undefined')
  3530. throw Error("Illegal oneof in message "+obj.name+"#"+fld["name"]+": "+fld["oneof"]);
  3531. }
  3532. fld = new Reflect.Message.Field(this, obj, fld["rule"], fld["type"], fld["name"], fld["id"], fld["options"], oneof);
  3533. if (oneof)
  3534. oneof.fields.push(fld);
  3535. obj.addChild(fld);
  3536. }
  3537. }
  3538. // Push enums and messages to stack
  3539. var subObj = [];
  3540. if (typeof def["enums"] !== 'undefined' && def['enums'].length > 0)
  3541. for (i=0; i<def["enums"].length; i++)
  3542. subObj.push(def["enums"][i]);
  3543. if (def["messages"] && def["messages"].length > 0)
  3544. for (i=0; i<def["messages"].length; i++)
  3545. subObj.push(def["messages"][i]);
  3546. // Set extension range
  3547. if (def["extensions"]) {
  3548. obj.extensions = def["extensions"];
  3549. if (obj.extensions[0] < ProtoBuf.ID_MIN)
  3550. obj.extensions[0] = ProtoBuf.ID_MIN;
  3551. if (obj.extensions[1] > ProtoBuf.ID_MAX)
  3552. obj.extensions[1] = ProtoBuf.ID_MAX;
  3553. }
  3554. this.ptr.addChild(obj); // Add to current namespace
  3555. if (subObj.length > 0) {
  3556. stack.push(defs); // Push the current level back
  3557. defs = subObj; // Continue processing sub level
  3558. subObj = null;
  3559. this.ptr = obj; // And move the pointer to this namespace
  3560. obj = null;
  3561. continue;
  3562. }
  3563. subObj = null;
  3564. obj = null;
  3565. } else if (Builder.isValidEnum(def)) {
  3566. obj = new Reflect.Enum(this, this.ptr, def["name"], def["options"]);
  3567. for (i=0; i<def["values"].length; i++)
  3568. obj.addChild(new Reflect.Enum.Value(this, obj, def["values"][i]["name"], def["values"][i]["id"]));
  3569. this.ptr.addChild(obj);
  3570. obj = null;
  3571. } else if (Builder.isValidService(def)) {
  3572. obj = new Reflect.Service(this, this.ptr, def["name"], def["options"]);
  3573. for (i in def["rpc"])
  3574. if (def["rpc"].hasOwnProperty(i))
  3575. obj.addChild(new Reflect.Service.RPCMethod(this, obj, i, def["rpc"][i]["request"], def["rpc"][i]["response"], def["rpc"][i]["options"]));
  3576. this.ptr.addChild(obj);
  3577. obj = null;
  3578. } else if (Builder.isValidExtend(def)) {
  3579. obj = this.ptr.resolve(def["ref"]);
  3580. if (obj) {
  3581. for (i=0; i<def["fields"].length; i++) { // i=Fields
  3582. if (obj.getChild(def['fields'][i]['id']) !== null)
  3583. throw Error("Duplicate extended field id in message "+obj.name+": "+def['fields'][i]['id']);
  3584. if (def['fields'][i]['id'] < obj.extensions[0] || def['fields'][i]['id'] > obj.extensions[1])
  3585. throw Error("Illegal extended field id in message "+obj.name+": "+def['fields'][i]['id']+" ("+obj.extensions.join(' to ')+" expected)");
  3586. // Convert extension field names to camel case notation if the override is set
  3587. var name = def["fields"][i]["name"];
  3588. if (this.options['convertFieldsToCamelCase'])
  3589. name = Reflect.Message.Field._toCamelCase(def["fields"][i]["name"]);
  3590. // see #161: Extensions use their fully qualified name as their runtime key and...
  3591. fld = new Reflect.Message.ExtensionField(this, obj, def["fields"][i]["rule"], def["fields"][i]["type"], this.ptr.fqn()+'.'+name, def["fields"][i]["id"], def["fields"][i]["options"]);
  3592. // ...are added on top of the current namespace as an extension which is used for
  3593. // resolving their type later on (the extension always keeps the original name to
  3594. // prevent naming collisions)
  3595. var ext = new Reflect.Extension(this, this.ptr, def["fields"][i]["name"], fld);
  3596. fld.extension = ext;
  3597. this.ptr.addChild(ext);
  3598. obj.addChild(fld);
  3599. }
  3600. } else if (!/\.?google\.protobuf\./.test(def["ref"])) // Silently skip internal extensions
  3601. throw Error("Extended message "+def["ref"]+" is not defined");
  3602. } else
  3603. throw Error("Not a valid definition: "+JSON.stringify(def));
  3604. def = null;
  3605. }
  3606. // Break goes here
  3607. } else
  3608. throw Error("Not a valid namespace: "+JSON.stringify(defs));
  3609. defs = null;
  3610. this.ptr = this.ptr.parent; // This namespace is s done
  3611. }
  3612. this.resolved = false; // Require re-resolve
  3613. this.result = null; // Require re-build
  3614. return this;
  3615. };
  3616. /**
  3617. * Imports another definition into this builder.
  3618. * @param {Object.<string,*>} json Parsed import
  3619. * @param {(string|{root: string, file: string})=} filename Imported file name
  3620. * @return {ProtoBuf.Builder} this
  3621. * @throws {Error} If the definition or file cannot be imported
  3622. * @expose
  3623. */
  3624. BuilderPrototype["import"] = function(json, filename) {
  3625. if (typeof filename === 'string') {
  3626. if (ProtoBuf.Util.IS_NODE)
  3627. filename = require("path")['resolve'](filename);
  3628. if (this.files[filename] === true) {
  3629. this.reset();
  3630. return this; // Skip duplicate imports
  3631. }
  3632. this.files[filename] = true;
  3633. }
  3634. if (!!json['imports'] && json['imports'].length > 0) {
  3635. var importRoot, delim = '/', resetRoot = false;
  3636. if (typeof filename === 'object') { // If an import root is specified, override
  3637. this.importRoot = filename["root"]; resetRoot = true; // ... and reset afterwards
  3638. importRoot = this.importRoot;
  3639. filename = filename["file"];
  3640. if (importRoot.indexOf("\\") >= 0 || filename.indexOf("\\") >= 0) delim = '\\';
  3641. } else if (typeof filename === 'string') {
  3642. if (this.importRoot) // If import root is overridden, use it
  3643. importRoot = this.importRoot;
  3644. else { // Otherwise compute from filename
  3645. if (filename.indexOf("/") >= 0) { // Unix
  3646. importRoot = filename.replace(/\/[^\/]*$/, "");
  3647. if (/* /file.proto */ importRoot === "")
  3648. importRoot = "/";
  3649. } else if (filename.indexOf("\\") >= 0) { // Windows
  3650. importRoot = filename.replace(/\\[^\\]*$/, "");
  3651. delim = '\\';
  3652. } else
  3653. importRoot = ".";
  3654. }
  3655. } else
  3656. importRoot = null;
  3657. for (var i=0; i<json['imports'].length; i++) {
  3658. if (typeof json['imports'][i] === 'string') { // Import file
  3659. if (!importRoot)
  3660. throw Error("Cannot determine import root: File name is unknown");
  3661. var importFilename = json['imports'][i];
  3662. if (/^google\/protobuf\//.test(importFilename))
  3663. continue; // Not needed and therefore not used
  3664. importFilename = importRoot+delim+importFilename;
  3665. if (this.files[importFilename] === true)
  3666. continue; // Already imported
  3667. if (/\.proto$/i.test(importFilename) && !ProtoBuf.DotProto) // If this is a NOPARSE build
  3668. importFilename = importFilename.replace(/\.proto$/, ".json"); // always load the JSON file
  3669. var contents = ProtoBuf.Util.fetch(importFilename);
  3670. if (contents === null)
  3671. throw Error("Failed to import '"+importFilename+"' in '"+filename+"': File not found");
  3672. if (/\.json$/i.test(importFilename)) // Always possible
  3673. this["import"](JSON.parse(contents+""), importFilename); // May throw
  3674. else
  3675. this["import"]((new ProtoBuf.DotProto.Parser(contents+"")).parse(), importFilename); // May throw
  3676. } else // Import structure
  3677. if (!filename)
  3678. this["import"](json['imports'][i]);
  3679. else if (/\.(\w+)$/.test(filename)) // With extension: Append _importN to the name portion to make it unique
  3680. this["import"](json['imports'][i], filename.replace(/^(.+)\.(\w+)$/, function($0, $1, $2) { return $1+"_import"+i+"."+$2; }));
  3681. else // Without extension: Append _importN to make it unique
  3682. this["import"](json['imports'][i], filename+"_import"+i);
  3683. }
  3684. if (resetRoot) // Reset import root override when all imports are done
  3685. this.importRoot = null;
  3686. }
  3687. if (json['messages']) {
  3688. if (json['package'])
  3689. this.define(json['package'], json["options"]);
  3690. this.create(json['messages']);
  3691. this.reset();
  3692. }
  3693. if (json['enums']) {
  3694. if (json['package'])
  3695. this.define(json['package'], json["options"]);
  3696. this.create(json['enums']);
  3697. this.reset();
  3698. }
  3699. if (json['services']) {
  3700. if (json['package'])
  3701. this.define(json['package'], json["options"]);
  3702. this.create(json['services']);
  3703. this.reset();
  3704. }
  3705. if (json['extends']) {
  3706. if (json['package'])
  3707. this.define(json['package'], json["options"]);
  3708. this.create(json['extends']);
  3709. this.reset();
  3710. }
  3711. return this;
  3712. };
  3713. /**
  3714. * Tests if a definition is a valid service definition.
  3715. * @param {Object} def Definition
  3716. * @return {boolean} true if valid, else false
  3717. * @expose
  3718. */
  3719. Builder.isValidService = function(def) {
  3720. // Services require a string name and an rpc object
  3721. return !(typeof def["name"] !== 'string' || !Lang.NAME.test(def["name"]) || typeof def["rpc"] !== 'object');
  3722. };
  3723. /**
  3724. * Tests if a definition is a valid extension.
  3725. * @param {Object} def Definition
  3726. * @returns {boolean} true if valid, else false
  3727. * @expose
  3728. */
  3729. Builder.isValidExtend = function(def) {
  3730. if (typeof def["ref"] !== 'string' || !Lang.TYPEREF.test(def["ref"]))
  3731. return false;
  3732. var i;
  3733. if (typeof def["fields"] !== 'undefined') {
  3734. if (!ProtoBuf.Util.isArray(def["fields"]))
  3735. return false;
  3736. var ids = [], id; // IDs must be unique (does not yet test for the extended message's ids)
  3737. for (i=0; i<def["fields"].length; i++) {
  3738. if (!Builder.isValidMessageField(def["fields"][i]))
  3739. return false;
  3740. id = parseInt(def["id"], 10);
  3741. if (ids.indexOf(id) >= 0)
  3742. return false;
  3743. ids.push(id);
  3744. }
  3745. ids = null;
  3746. }
  3747. return true;
  3748. };
  3749. /**
  3750. * Resolves all namespace objects.
  3751. * @throws {Error} If a type cannot be resolved
  3752. * @expose
  3753. */
  3754. BuilderPrototype.resolveAll = function() {
  3755. // Resolve all reflected objects
  3756. var res;
  3757. if (this.ptr == null || typeof this.ptr.type === 'object')
  3758. return; // Done (already resolved)
  3759. if (this.ptr instanceof Reflect.Namespace) {
  3760. // Build all children
  3761. var children = this.ptr.children;
  3762. for (var i= 0, k=children.length; i<k; ++i)
  3763. this.ptr = children[i],
  3764. this.resolveAll();
  3765. } else if (this.ptr instanceof Reflect.Message.Field) {
  3766. if (!Lang.TYPE.test(this.ptr.type)) { // Resolve type...
  3767. if (!Lang.TYPEREF.test(this.ptr.type))
  3768. throw Error("Illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.type);
  3769. res = (this.ptr instanceof Reflect.Message.ExtensionField ? this.ptr.extension.parent : this.ptr.parent).resolve(this.ptr.type, true);
  3770. if (!res)
  3771. throw Error("Unresolvable type reference in "+this.ptr.toString(true)+": "+this.ptr.type);
  3772. this.ptr.resolvedType = res;
  3773. if (res instanceof Reflect.Enum)
  3774. this.ptr.type = ProtoBuf.TYPES["enum"];
  3775. else if (res instanceof Reflect.Message)
  3776. this.ptr.type = res.isGroup ? ProtoBuf.TYPES["group"] : ProtoBuf.TYPES["message"];
  3777. else
  3778. throw Error("Illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.type);
  3779. } else
  3780. this.ptr.type = ProtoBuf.TYPES[this.ptr.type];
  3781. } else if (this.ptr instanceof ProtoBuf.Reflect.Enum.Value) {
  3782. // No need to build enum values (built in enum)
  3783. } else if (this.ptr instanceof ProtoBuf.Reflect.Service.Method) {
  3784. if (this.ptr instanceof ProtoBuf.Reflect.Service.RPCMethod) {
  3785. res = this.ptr.parent.resolve(this.ptr.requestName);
  3786. if (!res || !(res instanceof ProtoBuf.Reflect.Message))
  3787. throw Error("Illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.requestName);
  3788. this.ptr.resolvedRequestType = res;
  3789. res = this.ptr.parent.resolve(this.ptr.responseName);
  3790. if (!res || !(res instanceof ProtoBuf.Reflect.Message))
  3791. throw Error("Illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.responseName);
  3792. this.ptr.resolvedResponseType = res;
  3793. } else {
  3794. // Should not happen as nothing else is implemented
  3795. throw Error("Illegal service type in "+this.ptr.toString(true));
  3796. }
  3797. } else if (!(this.ptr instanceof ProtoBuf.Reflect.Message.OneOf) && !(this.ptr instanceof ProtoBuf.Reflect.Extension))
  3798. throw Error("Illegal object in namespace: "+typeof(this.ptr)+":"+this.ptr);
  3799. this.reset();
  3800. };
  3801. /**
  3802. * Builds the protocol. This will first try to resolve all definitions and, if this has been successful,
  3803. * return the built package.
  3804. * @param {string=} path Specifies what to return. If omitted, the entire namespace will be returned.
  3805. * @return {ProtoBuf.Builder.Message|Object.<string,*>}
  3806. * @throws {Error} If a type could not be resolved
  3807. * @expose
  3808. */
  3809. BuilderPrototype.build = function(path) {
  3810. this.reset();
  3811. if (!this.resolved)
  3812. this.resolveAll(),
  3813. this.resolved = true,
  3814. this.result = null; // Require re-build
  3815. if (this.result == null) // (Re-)Build
  3816. this.result = this.ns.build();
  3817. if (!path)
  3818. return this.result;
  3819. else {
  3820. var part = path.split(".");
  3821. var ptr = this.result; // Build namespace pointer (no hasChild etc.)
  3822. for (var i=0; i<part.length; i++)
  3823. if (ptr[part[i]])
  3824. ptr = ptr[part[i]];
  3825. else {
  3826. ptr = null;
  3827. break;
  3828. }
  3829. return ptr;
  3830. }
  3831. };
  3832. /**
  3833. * Similar to {@link ProtoBuf.Builder#build}, but looks up the internal reflection descriptor.
  3834. * @param {string=} path Specifies what to return. If omitted, the entire namespace wiil be returned.
  3835. * @return {ProtoBuf.Reflect.T} Reflection descriptor or `null` if not found
  3836. */
  3837. BuilderPrototype.lookup = function(path) {
  3838. return path ? this.ns.resolve(path) : this.ns;
  3839. };
  3840. /**
  3841. * Returns a string representation of this object.
  3842. * @return {string} String representation as of "Builder"
  3843. * @expose
  3844. */
  3845. BuilderPrototype.toString = function() {
  3846. return "Builder";
  3847. };
  3848. // Pseudo types documented in Reflect.js.
  3849. // Exist for the sole purpose of being able to "... instanceof ProtoBuf.Builder.Message" etc.
  3850. Builder.Message = function() {};
  3851. Builder.Service = function() {};
  3852. return Builder;
  3853. })(ProtoBuf, ProtoBuf.Lang, ProtoBuf.Reflect);
  3854. /**
  3855. * Loads a .proto string and returns the Builder.
  3856. * @param {string} proto .proto file contents
  3857. * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted.
  3858. * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports.
  3859. * @return {ProtoBuf.Builder} Builder to create new messages
  3860. * @throws {Error} If the definition cannot be parsed or built
  3861. * @expose
  3862. */
  3863. ProtoBuf.loadProto = function(proto, builder, filename) {
  3864. if (typeof builder === 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string'))
  3865. filename = builder,
  3866. builder = undefined;
  3867. return ProtoBuf.loadJson((new ProtoBuf.DotProto.Parser(proto)).parse(), builder, filename);
  3868. };
  3869. /**
  3870. * Loads a .proto string and returns the Builder. This is an alias of {@link ProtoBuf.loadProto}.
  3871. * @function
  3872. * @param {string} proto .proto file contents
  3873. * @param {(ProtoBuf.Builder|string)=} builder Builder to append to. Will create a new one if omitted.
  3874. * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports.
  3875. * @return {ProtoBuf.Builder} Builder to create new messages
  3876. * @throws {Error} If the definition cannot be parsed or built
  3877. * @expose
  3878. */
  3879. ProtoBuf.protoFromString = ProtoBuf.loadProto; // Legacy
  3880. /**
  3881. * Loads a .proto file and returns the Builder.
  3882. * @param {string|{root: string, file: string}} filename Path to proto file or an object specifying 'file' with
  3883. * an overridden 'root' path for all imported files.
  3884. * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and
  3885. * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the
  3886. * file will be read synchronously and this function will return the Builder.
  3887. * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted.
  3888. * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the
  3889. * request has failed), else undefined
  3890. * @expose
  3891. */
  3892. ProtoBuf.loadProtoFile = function(filename, callback, builder) {
  3893. if (callback && typeof callback === 'object')
  3894. builder = callback,
  3895. callback = null;
  3896. else if (!callback || typeof callback !== 'function')
  3897. callback = null;
  3898. if (callback)
  3899. return ProtoBuf.Util.fetch(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(contents) {
  3900. if (contents === null) {
  3901. callback(Error("Failed to fetch file"));
  3902. return;
  3903. }
  3904. try {
  3905. callback(null, ProtoBuf.loadProto(contents, builder, filename));
  3906. } catch (e) {
  3907. callback(e);
  3908. }
  3909. });
  3910. var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename);
  3911. return contents === null ? null : ProtoBuf.loadProto(contents, builder, filename);
  3912. };
  3913. /**
  3914. * Loads a .proto file and returns the Builder. This is an alias of {@link ProtoBuf.loadProtoFile}.
  3915. * @function
  3916. * @param {string|{root: string, file: string}} filename Path to proto file or an object specifying 'file' with
  3917. * an overridden 'root' path for all imported files.
  3918. * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and
  3919. * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the
  3920. * file will be read synchronously and this function will return the Builder.
  3921. * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted.
  3922. * @return {!ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the
  3923. * request has failed), else undefined
  3924. * @expose
  3925. */
  3926. ProtoBuf.protoFromFile = ProtoBuf.loadProtoFile; // Legacy
  3927. /**
  3928. * Constructs a new empty Builder.
  3929. * @param {Object.<string,*>=} options Builder options, defaults to global options set on ProtoBuf
  3930. * @return {!ProtoBuf.Builder} Builder
  3931. * @expose
  3932. */
  3933. ProtoBuf.newBuilder = function(options) {
  3934. options = options || {};
  3935. if (typeof options['convertFieldsToCamelCase'] === 'undefined')
  3936. options['convertFieldsToCamelCase'] = ProtoBuf.convertFieldsToCamelCase;
  3937. if (typeof options['populateAccessors'] === 'undefined')
  3938. options['populateAccessors'] = ProtoBuf.populateAccessors;
  3939. return new ProtoBuf.Builder(options);
  3940. };
  3941. /**
  3942. * Loads a .json definition and returns the Builder.
  3943. * @param {!*|string} json JSON definition
  3944. * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted.
  3945. * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports.
  3946. * @return {ProtoBuf.Builder} Builder to create new messages
  3947. * @throws {Error} If the definition cannot be parsed or built
  3948. * @expose
  3949. */
  3950. ProtoBuf.loadJson = function(json, builder, filename) {
  3951. if (typeof builder === 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string'))
  3952. filename = builder,
  3953. builder = null;
  3954. if (!builder || typeof builder !== 'object')
  3955. builder = ProtoBuf.newBuilder();
  3956. if (typeof json === 'string')
  3957. json = JSON.parse(json);
  3958. builder["import"](json, filename);
  3959. builder.resolveAll();
  3960. builder.build();
  3961. return builder;
  3962. };
  3963. /**
  3964. * Loads a .json file and returns the Builder.
  3965. * @param {string|!{root: string, file: string}} filename Path to json file or an object specifying 'file' with
  3966. * an overridden 'root' path for all imported files.
  3967. * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and
  3968. * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the
  3969. * file will be read synchronously and this function will return the Builder.
  3970. * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted.
  3971. * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the
  3972. * request has failed), else undefined
  3973. * @expose
  3974. */
  3975. ProtoBuf.loadJsonFile = function(filename, callback, builder) {
  3976. if (callback && typeof callback === 'object')
  3977. builder = callback,
  3978. callback = null;
  3979. else if (!callback || typeof callback !== 'function')
  3980. callback = null;
  3981. if (callback)
  3982. return ProtoBuf.Util.fetch(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(contents) {
  3983. if (contents === null) {
  3984. callback(Error("Failed to fetch file"));
  3985. return;
  3986. }
  3987. try {
  3988. callback(null, ProtoBuf.loadJson(JSON.parse(contents), builder, filename));
  3989. } catch (e) {
  3990. callback(e);
  3991. }
  3992. });
  3993. var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename);
  3994. return contents === null ? null : ProtoBuf.loadJson(JSON.parse(contents), builder, filename);
  3995. };
  3996. return ProtoBuf;
  3997. }
  3998. /* CommonJS */ if (typeof require === 'function' && typeof module === 'object' && module && typeof exports === 'object' && exports)
  3999. module['exports'] = init(require("bytebuffer"));
  4000. /* AMD */ else if (typeof define === 'function' && define["amd"])
  4001. define(["ByteBuffer"], init);
  4002. /* Global */ else
  4003. (global["dcodeIO"] = global["dcodeIO"] || {})["ProtoBuf"] = init(global["dcodeIO"]["ByteBuffer"]);
  4004. })(this);