CodedOutputStream.cs 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346
  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2008 Google Inc. All rights reserved.
  4. // http://github.com/jskeet/dotnet-protobufs/
  5. // Original C++/Java/Python code:
  6. // http://code.google.com/p/protobuf/
  7. //
  8. // Redistribution and use in source and binary forms, with or without
  9. // modification, are permitted provided that the following conditions are
  10. // met:
  11. //
  12. // * Redistributions of source code must retain the above copyright
  13. // notice, this list of conditions and the following disclaimer.
  14. // * Redistributions in binary form must reproduce the above
  15. // copyright notice, this list of conditions and the following disclaimer
  16. // in the documentation and/or other materials provided with the
  17. // distribution.
  18. // * Neither the name of Google Inc. nor the names of its
  19. // contributors may be used to endorse or promote products derived from
  20. // this software without specific prior written permission.
  21. //
  22. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  25. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  26. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  27. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  28. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  30. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  32. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. #endregion
  34. using System;
  35. using System.Collections;
  36. using System.Collections.Generic;
  37. using System.IO;
  38. using System.Text;
  39. using Google.ProtocolBuffers.Collections;
  40. using Google.ProtocolBuffers.Descriptors;
  41. namespace Google.ProtocolBuffers
  42. {
  43. /// <summary>
  44. /// Encodes and writes protocol message fields.
  45. /// </summary>
  46. /// <remarks>
  47. /// This class contains two kinds of methods: methods that write specific
  48. /// protocol message constructs and field types (e.g. WriteTag and
  49. /// WriteInt32) and methods that write low-level values (e.g.
  50. /// WriteRawVarint32 and WriteRawBytes). If you are writing encoded protocol
  51. /// messages, you should use the former methods, but if you are writing some
  52. /// other format of your own design, use the latter. The names of the former
  53. /// methods are taken from the protocol buffer type names, not .NET types.
  54. /// (Hence WriteFloat instead of WriteSingle, and WriteBool instead of WriteBoolean.)
  55. /// </remarks>
  56. public sealed partial class CodedOutputStream : ICodedOutputStream
  57. {
  58. /// <summary>
  59. /// The buffer size used by CreateInstance(Stream).
  60. /// </summary>
  61. public static readonly int DefaultBufferSize = 4096;
  62. private readonly byte[] buffer;
  63. private readonly int limit;
  64. private int position;
  65. private readonly Stream output;
  66. #region Construction
  67. private CodedOutputStream(byte[] buffer, int offset, int length)
  68. {
  69. this.output = null;
  70. this.buffer = buffer;
  71. this.position = offset;
  72. this.limit = offset + length;
  73. }
  74. private CodedOutputStream(Stream output, byte[] buffer)
  75. {
  76. this.output = output;
  77. this.buffer = buffer;
  78. this.position = 0;
  79. this.limit = buffer.Length;
  80. }
  81. /// <summary>
  82. /// Creates a new CodedOutputStream which write to the given stream.
  83. /// </summary>
  84. public static CodedOutputStream CreateInstance(Stream output)
  85. {
  86. return CreateInstance(output, DefaultBufferSize);
  87. }
  88. /// <summary>
  89. /// Creates a new CodedOutputStream which write to the given stream and uses
  90. /// the specified buffer size.
  91. /// </summary>
  92. public static CodedOutputStream CreateInstance(Stream output, int bufferSize)
  93. {
  94. return new CodedOutputStream(output, new byte[bufferSize]);
  95. }
  96. /// <summary>
  97. /// Creates a new CodedOutputStream that writes directly to the given
  98. /// byte array. If more bytes are written than fit in the array,
  99. /// OutOfSpaceException will be thrown.
  100. /// </summary>
  101. public static CodedOutputStream CreateInstance(byte[] flatArray)
  102. {
  103. return CreateInstance(flatArray, 0, flatArray.Length);
  104. }
  105. /// <summary>
  106. /// Creates a new CodedOutputStream that writes directly to the given
  107. /// byte array slice. If more bytes are written than fit in the array,
  108. /// OutOfSpaceException will be thrown.
  109. /// </summary>
  110. public static CodedOutputStream CreateInstance(byte[] flatArray, int offset, int length)
  111. {
  112. return new CodedOutputStream(flatArray, offset, length);
  113. }
  114. #endregion
  115. void ICodedOutputStream.WriteMessageStart() { }
  116. void ICodedOutputStream.WriteMessageEnd() { Flush(); }
  117. #region Writing of unknown fields
  118. [Obsolete]
  119. public void WriteUnknownGroup(int fieldNumber, IMessageLite value)
  120. {
  121. WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
  122. value.WriteTo(this);
  123. WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
  124. }
  125. public void WriteUnknownBytes(int fieldNumber, ByteString value)
  126. {
  127. WriteBytes(fieldNumber, null /*not used*/, value);
  128. }
  129. [CLSCompliant(false)]
  130. public void WriteUnknownField(int fieldNumber, WireFormat.WireType wireType, ulong value)
  131. {
  132. if (wireType == WireFormat.WireType.Varint)
  133. {
  134. WriteUInt64(fieldNumber, null /*not used*/, value);
  135. }
  136. else if (wireType == WireFormat.WireType.Fixed32)
  137. {
  138. WriteFixed32(fieldNumber, null /*not used*/, (uint) value);
  139. }
  140. else if (wireType == WireFormat.WireType.Fixed64)
  141. {
  142. WriteFixed64(fieldNumber, null /*not used*/, value);
  143. }
  144. else
  145. {
  146. throw InvalidProtocolBufferException.InvalidWireType();
  147. }
  148. }
  149. #endregion
  150. #region Writing of tags and fields
  151. public void WriteField(FieldType fieldType, int fieldNumber, string fieldName, object value)
  152. {
  153. switch (fieldType)
  154. {
  155. case FieldType.String:
  156. WriteString(fieldNumber, fieldName, (string) value);
  157. break;
  158. case FieldType.Message:
  159. WriteMessage(fieldNumber, fieldName, (IMessageLite) value);
  160. break;
  161. case FieldType.Group:
  162. WriteGroup(fieldNumber, fieldName, (IMessageLite) value);
  163. break;
  164. case FieldType.Bytes:
  165. WriteBytes(fieldNumber, fieldName, (ByteString) value);
  166. break;
  167. case FieldType.Bool:
  168. WriteBool(fieldNumber, fieldName, (bool) value);
  169. break;
  170. case FieldType.Enum:
  171. if (value is Enum)
  172. {
  173. WriteEnum(fieldNumber, fieldName, (int) value, null /*not used*/);
  174. }
  175. else
  176. {
  177. WriteEnum(fieldNumber, fieldName, ((IEnumLite) value).Number, null /*not used*/);
  178. }
  179. break;
  180. case FieldType.Int32:
  181. WriteInt32(fieldNumber, fieldName, (int) value);
  182. break;
  183. case FieldType.Int64:
  184. WriteInt64(fieldNumber, fieldName, (long) value);
  185. break;
  186. case FieldType.UInt32:
  187. WriteUInt32(fieldNumber, fieldName, (uint) value);
  188. break;
  189. case FieldType.UInt64:
  190. WriteUInt64(fieldNumber, fieldName, (ulong) value);
  191. break;
  192. case FieldType.SInt32:
  193. WriteSInt32(fieldNumber, fieldName, (int) value);
  194. break;
  195. case FieldType.SInt64:
  196. WriteSInt64(fieldNumber, fieldName, (long) value);
  197. break;
  198. case FieldType.Fixed32:
  199. WriteFixed32(fieldNumber, fieldName, (uint) value);
  200. break;
  201. case FieldType.Fixed64:
  202. WriteFixed64(fieldNumber, fieldName, (ulong) value);
  203. break;
  204. case FieldType.SFixed32:
  205. WriteSFixed32(fieldNumber, fieldName, (int) value);
  206. break;
  207. case FieldType.SFixed64:
  208. WriteSFixed64(fieldNumber, fieldName, (long) value);
  209. break;
  210. case FieldType.Double:
  211. WriteDouble(fieldNumber, fieldName, (double) value);
  212. break;
  213. case FieldType.Float:
  214. WriteFloat(fieldNumber, fieldName, (float) value);
  215. break;
  216. }
  217. }
  218. /// <summary>
  219. /// Writes a double field value, including tag, to the stream.
  220. /// </summary>
  221. public void WriteDouble(int fieldNumber, string fieldName, double value)
  222. {
  223. WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
  224. WriteDoubleNoTag(value);
  225. }
  226. /// <summary>
  227. /// Writes a float field value, including tag, to the stream.
  228. /// </summary>
  229. public void WriteFloat(int fieldNumber, string fieldName, float value)
  230. {
  231. WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
  232. WriteFloatNoTag(value);
  233. }
  234. /// <summary>
  235. /// Writes a uint64 field value, including tag, to the stream.
  236. /// </summary>
  237. [CLSCompliant(false)]
  238. public void WriteUInt64(int fieldNumber, string fieldName, ulong value)
  239. {
  240. WriteTag(fieldNumber, WireFormat.WireType.Varint);
  241. WriteRawVarint64(value);
  242. }
  243. /// <summary>
  244. /// Writes an int64 field value, including tag, to the stream.
  245. /// </summary>
  246. public void WriteInt64(int fieldNumber, string fieldName, long value)
  247. {
  248. WriteTag(fieldNumber, WireFormat.WireType.Varint);
  249. WriteRawVarint64((ulong) value);
  250. }
  251. /// <summary>
  252. /// Writes an int32 field value, including tag, to the stream.
  253. /// </summary>
  254. public void WriteInt32(int fieldNumber, string fieldName, int value)
  255. {
  256. WriteTag(fieldNumber, WireFormat.WireType.Varint);
  257. if (value >= 0)
  258. {
  259. WriteRawVarint32((uint) value);
  260. }
  261. else
  262. {
  263. // Must sign-extend.
  264. WriteRawVarint64((ulong) value);
  265. }
  266. }
  267. /// <summary>
  268. /// Writes a fixed64 field value, including tag, to the stream.
  269. /// </summary>
  270. [CLSCompliant(false)]
  271. public void WriteFixed64(int fieldNumber, string fieldName, ulong value)
  272. {
  273. WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
  274. WriteRawLittleEndian64(value);
  275. }
  276. /// <summary>
  277. /// Writes a fixed32 field value, including tag, to the stream.
  278. /// </summary>
  279. [CLSCompliant(false)]
  280. public void WriteFixed32(int fieldNumber, string fieldName, uint value)
  281. {
  282. WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
  283. WriteRawLittleEndian32(value);
  284. }
  285. /// <summary>
  286. /// Writes a bool field value, including tag, to the stream.
  287. /// </summary>
  288. public void WriteBool(int fieldNumber, string fieldName, bool value)
  289. {
  290. WriteTag(fieldNumber, WireFormat.WireType.Varint);
  291. WriteRawByte(value ? (byte) 1 : (byte) 0);
  292. }
  293. /// <summary>
  294. /// Writes a string field value, including tag, to the stream.
  295. /// </summary>
  296. public void WriteString(int fieldNumber, string fieldName, string value)
  297. {
  298. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  299. // Optimise the case where we have enough space to write
  300. // the string directly to the buffer, which should be common.
  301. int length = Encoding.UTF8.GetByteCount(value);
  302. WriteRawVarint32((uint) length);
  303. if (limit - position >= length)
  304. {
  305. Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, position);
  306. position += length;
  307. }
  308. else
  309. {
  310. byte[] bytes = Encoding.UTF8.GetBytes(value);
  311. WriteRawBytes(bytes);
  312. }
  313. }
  314. /// <summary>
  315. /// Writes a group field value, including tag, to the stream.
  316. /// </summary>
  317. public void WriteGroup(int fieldNumber, string fieldName, IMessageLite value)
  318. {
  319. WriteTag(fieldNumber, WireFormat.WireType.StartGroup);
  320. value.WriteTo(this);
  321. WriteTag(fieldNumber, WireFormat.WireType.EndGroup);
  322. }
  323. public void WriteMessage(int fieldNumber, string fieldName, IMessageLite value)
  324. {
  325. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  326. WriteRawVarint32((uint) value.SerializedSize);
  327. value.WriteTo(this);
  328. }
  329. public void WriteBytes(int fieldNumber, string fieldName, ByteString value)
  330. {
  331. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  332. WriteRawVarint32((uint) value.Length);
  333. value.WriteRawBytesTo(this);
  334. }
  335. [CLSCompliant(false)]
  336. public void WriteUInt32(int fieldNumber, string fieldName, uint value)
  337. {
  338. WriteTag(fieldNumber, WireFormat.WireType.Varint);
  339. WriteRawVarint32(value);
  340. }
  341. public void WriteEnum(int fieldNumber, string fieldName, int value, object rawValue)
  342. {
  343. WriteTag(fieldNumber, WireFormat.WireType.Varint);
  344. WriteInt32NoTag(value);
  345. }
  346. public void WriteSFixed32(int fieldNumber, string fieldName, int value)
  347. {
  348. WriteTag(fieldNumber, WireFormat.WireType.Fixed32);
  349. WriteRawLittleEndian32((uint) value);
  350. }
  351. public void WriteSFixed64(int fieldNumber, string fieldName, long value)
  352. {
  353. WriteTag(fieldNumber, WireFormat.WireType.Fixed64);
  354. WriteRawLittleEndian64((ulong) value);
  355. }
  356. public void WriteSInt32(int fieldNumber, string fieldName, int value)
  357. {
  358. WriteTag(fieldNumber, WireFormat.WireType.Varint);
  359. WriteRawVarint32(EncodeZigZag32(value));
  360. }
  361. public void WriteSInt64(int fieldNumber, string fieldName, long value)
  362. {
  363. WriteTag(fieldNumber, WireFormat.WireType.Varint);
  364. WriteRawVarint64(EncodeZigZag64(value));
  365. }
  366. public void WriteMessageSetExtension(int fieldNumber, string fieldName, IMessageLite value)
  367. {
  368. WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.StartGroup);
  369. WriteUInt32(WireFormat.MessageSetField.TypeID, "type_id", (uint) fieldNumber);
  370. WriteMessage(WireFormat.MessageSetField.Message, "message", value);
  371. WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
  372. }
  373. public void WriteMessageSetExtension(int fieldNumber, string fieldName, ByteString value)
  374. {
  375. WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.StartGroup);
  376. WriteUInt32(WireFormat.MessageSetField.TypeID, "type_id", (uint) fieldNumber);
  377. WriteBytes(WireFormat.MessageSetField.Message, "message", value);
  378. WriteTag(WireFormat.MessageSetField.Item, WireFormat.WireType.EndGroup);
  379. }
  380. #endregion
  381. #region Writing of values without tags
  382. public void WriteFieldNoTag(FieldType fieldType, object value)
  383. {
  384. switch (fieldType)
  385. {
  386. case FieldType.String:
  387. WriteStringNoTag((string) value);
  388. break;
  389. case FieldType.Message:
  390. WriteMessageNoTag((IMessageLite) value);
  391. break;
  392. case FieldType.Group:
  393. WriteGroupNoTag((IMessageLite) value);
  394. break;
  395. case FieldType.Bytes:
  396. WriteBytesNoTag((ByteString) value);
  397. break;
  398. case FieldType.Bool:
  399. WriteBoolNoTag((bool) value);
  400. break;
  401. case FieldType.Enum:
  402. if (value is Enum)
  403. {
  404. WriteEnumNoTag((int) value);
  405. }
  406. else
  407. {
  408. WriteEnumNoTag(((IEnumLite) value).Number);
  409. }
  410. break;
  411. case FieldType.Int32:
  412. WriteInt32NoTag((int) value);
  413. break;
  414. case FieldType.Int64:
  415. WriteInt64NoTag((long) value);
  416. break;
  417. case FieldType.UInt32:
  418. WriteUInt32NoTag((uint) value);
  419. break;
  420. case FieldType.UInt64:
  421. WriteUInt64NoTag((ulong) value);
  422. break;
  423. case FieldType.SInt32:
  424. WriteSInt32NoTag((int) value);
  425. break;
  426. case FieldType.SInt64:
  427. WriteSInt64NoTag((long) value);
  428. break;
  429. case FieldType.Fixed32:
  430. WriteFixed32NoTag((uint) value);
  431. break;
  432. case FieldType.Fixed64:
  433. WriteFixed64NoTag((ulong) value);
  434. break;
  435. case FieldType.SFixed32:
  436. WriteSFixed32NoTag((int) value);
  437. break;
  438. case FieldType.SFixed64:
  439. WriteSFixed64NoTag((long) value);
  440. break;
  441. case FieldType.Double:
  442. WriteDoubleNoTag((double) value);
  443. break;
  444. case FieldType.Float:
  445. WriteFloatNoTag((float) value);
  446. break;
  447. }
  448. }
  449. /// <summary>
  450. /// Writes a double field value, including tag, to the stream.
  451. /// </summary>
  452. public void WriteDoubleNoTag(double value)
  453. {
  454. #if SILVERLIGHT2 || COMPACT_FRAMEWORK_35
  455. byte[] rawBytes = BitConverter.GetBytes(value);
  456. if (!BitConverter.IsLittleEndian)
  457. ByteArray.Reverse(rawBytes);
  458. if (limit - position >= 8)
  459. {
  460. buffer[position++] = rawBytes[0];
  461. buffer[position++] = rawBytes[1];
  462. buffer[position++] = rawBytes[2];
  463. buffer[position++] = rawBytes[3];
  464. buffer[position++] = rawBytes[4];
  465. buffer[position++] = rawBytes[5];
  466. buffer[position++] = rawBytes[6];
  467. buffer[position++] = rawBytes[7];
  468. }
  469. else
  470. WriteRawBytes(rawBytes, 0, 8);
  471. #else
  472. WriteRawLittleEndian64((ulong) BitConverter.DoubleToInt64Bits(value));
  473. #endif
  474. }
  475. /// <summary>
  476. /// Writes a float field value, without a tag, to the stream.
  477. /// </summary>
  478. public void WriteFloatNoTag(float value)
  479. {
  480. byte[] rawBytes = BitConverter.GetBytes(value);
  481. if (!BitConverter.IsLittleEndian)
  482. {
  483. ByteArray.Reverse(rawBytes);
  484. }
  485. if (limit - position >= 4)
  486. {
  487. buffer[position++] = rawBytes[0];
  488. buffer[position++] = rawBytes[1];
  489. buffer[position++] = rawBytes[2];
  490. buffer[position++] = rawBytes[3];
  491. }
  492. else
  493. {
  494. WriteRawBytes(rawBytes, 0, 4);
  495. }
  496. }
  497. /// <summary>
  498. /// Writes a uint64 field value, without a tag, to the stream.
  499. /// </summary>
  500. [CLSCompliant(false)]
  501. public void WriteUInt64NoTag(ulong value)
  502. {
  503. WriteRawVarint64(value);
  504. }
  505. /// <summary>
  506. /// Writes an int64 field value, without a tag, to the stream.
  507. /// </summary>
  508. public void WriteInt64NoTag(long value)
  509. {
  510. WriteRawVarint64((ulong) value);
  511. }
  512. /// <summary>
  513. /// Writes an int32 field value, without a tag, to the stream.
  514. /// </summary>
  515. public void WriteInt32NoTag(int value)
  516. {
  517. if (value >= 0)
  518. {
  519. WriteRawVarint32((uint) value);
  520. }
  521. else
  522. {
  523. // Must sign-extend.
  524. WriteRawVarint64((ulong) value);
  525. }
  526. }
  527. /// <summary>
  528. /// Writes a fixed64 field value, without a tag, to the stream.
  529. /// </summary>
  530. [CLSCompliant(false)]
  531. public void WriteFixed64NoTag(ulong value)
  532. {
  533. WriteRawLittleEndian64(value);
  534. }
  535. /// <summary>
  536. /// Writes a fixed32 field value, without a tag, to the stream.
  537. /// </summary>
  538. [CLSCompliant(false)]
  539. public void WriteFixed32NoTag(uint value)
  540. {
  541. WriteRawLittleEndian32(value);
  542. }
  543. /// <summary>
  544. /// Writes a bool field value, without a tag, to the stream.
  545. /// </summary>
  546. public void WriteBoolNoTag(bool value)
  547. {
  548. WriteRawByte(value ? (byte) 1 : (byte) 0);
  549. }
  550. /// <summary>
  551. /// Writes a string field value, without a tag, to the stream.
  552. /// </summary>
  553. public void WriteStringNoTag(string value)
  554. {
  555. // Optimise the case where we have enough space to write
  556. // the string directly to the buffer, which should be common.
  557. int length = Encoding.UTF8.GetByteCount(value);
  558. WriteRawVarint32((uint) length);
  559. if (limit - position >= length)
  560. {
  561. Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, position);
  562. position += length;
  563. }
  564. else
  565. {
  566. byte[] bytes = Encoding.UTF8.GetBytes(value);
  567. WriteRawBytes(bytes);
  568. }
  569. }
  570. /// <summary>
  571. /// Writes a group field value, without a tag, to the stream.
  572. /// </summary>
  573. public void WriteGroupNoTag(IMessageLite value)
  574. {
  575. value.WriteTo(this);
  576. }
  577. public void WriteMessageNoTag(IMessageLite value)
  578. {
  579. WriteRawVarint32((uint) value.SerializedSize);
  580. value.WriteTo(this);
  581. }
  582. public void WriteBytesNoTag(ByteString value)
  583. {
  584. WriteRawVarint32((uint) value.Length);
  585. value.WriteRawBytesTo(this);
  586. }
  587. [CLSCompliant(false)]
  588. public void WriteUInt32NoTag(uint value)
  589. {
  590. WriteRawVarint32(value);
  591. }
  592. public void WriteEnumNoTag(int value)
  593. {
  594. WriteInt32NoTag(value);
  595. }
  596. public void WriteSFixed32NoTag(int value)
  597. {
  598. WriteRawLittleEndian32((uint) value);
  599. }
  600. public void WriteSFixed64NoTag(long value)
  601. {
  602. WriteRawLittleEndian64((ulong) value);
  603. }
  604. public void WriteSInt32NoTag(int value)
  605. {
  606. WriteRawVarint32(EncodeZigZag32(value));
  607. }
  608. public void WriteSInt64NoTag(long value)
  609. {
  610. WriteRawVarint64(EncodeZigZag64(value));
  611. }
  612. #endregion
  613. #region Write array members
  614. public void WriteArray(FieldType fieldType, int fieldNumber, string fieldName, IEnumerable list)
  615. {
  616. foreach (object element in list)
  617. {
  618. WriteField(fieldType, fieldNumber, fieldName, element);
  619. }
  620. }
  621. public void WriteGroupArray<T>(int fieldNumber, string fieldName, IEnumerable<T> list)
  622. where T : IMessageLite
  623. {
  624. foreach (IMessageLite value in list)
  625. {
  626. WriteGroup(fieldNumber, fieldName, value);
  627. }
  628. }
  629. public void WriteMessageArray<T>(int fieldNumber, string fieldName, IEnumerable<T> list)
  630. where T : IMessageLite
  631. {
  632. foreach (IMessageLite value in list)
  633. {
  634. WriteMessage(fieldNumber, fieldName, value);
  635. }
  636. }
  637. public void WriteStringArray(int fieldNumber, string fieldName, IEnumerable<string> list)
  638. {
  639. foreach (var value in list)
  640. {
  641. WriteString(fieldNumber, fieldName, value);
  642. }
  643. }
  644. public void WriteBytesArray(int fieldNumber, string fieldName, IEnumerable<ByteString> list)
  645. {
  646. foreach (var value in list)
  647. {
  648. WriteBytes(fieldNumber, fieldName, value);
  649. }
  650. }
  651. public void WriteBoolArray(int fieldNumber, string fieldName, IEnumerable<bool> list)
  652. {
  653. foreach (var value in list)
  654. {
  655. WriteBool(fieldNumber, fieldName, value);
  656. }
  657. }
  658. public void WriteInt32Array(int fieldNumber, string fieldName, IEnumerable<int> list)
  659. {
  660. foreach (var value in list)
  661. {
  662. WriteInt32(fieldNumber, fieldName, value);
  663. }
  664. }
  665. public void WriteSInt32Array(int fieldNumber, string fieldName, IEnumerable<int> list)
  666. {
  667. foreach (var value in list)
  668. {
  669. WriteSInt32(fieldNumber, fieldName, value);
  670. }
  671. }
  672. public void WriteUInt32Array(int fieldNumber, string fieldName, IEnumerable<uint> list)
  673. {
  674. foreach (var value in list)
  675. {
  676. WriteUInt32(fieldNumber, fieldName, value);
  677. }
  678. }
  679. public void WriteFixed32Array(int fieldNumber, string fieldName, IEnumerable<uint> list)
  680. {
  681. foreach (var value in list)
  682. {
  683. WriteFixed32(fieldNumber, fieldName, value);
  684. }
  685. }
  686. public void WriteSFixed32Array(int fieldNumber, string fieldName, IEnumerable<int> list)
  687. {
  688. foreach (var value in list)
  689. {
  690. WriteSFixed32(fieldNumber, fieldName, value);
  691. }
  692. }
  693. public void WriteInt64Array(int fieldNumber, string fieldName, IEnumerable<long> list)
  694. {
  695. foreach (var value in list)
  696. {
  697. WriteInt64(fieldNumber, fieldName, value);
  698. }
  699. }
  700. public void WriteSInt64Array(int fieldNumber, string fieldName, IEnumerable<long> list)
  701. {
  702. foreach (var value in list)
  703. {
  704. WriteSInt64(fieldNumber, fieldName, value);
  705. }
  706. }
  707. public void WriteUInt64Array(int fieldNumber, string fieldName, IEnumerable<ulong> list)
  708. {
  709. foreach (var value in list)
  710. {
  711. WriteUInt64(fieldNumber, fieldName, value);
  712. }
  713. }
  714. public void WriteFixed64Array(int fieldNumber, string fieldName, IEnumerable<ulong> list)
  715. {
  716. foreach (var value in list)
  717. {
  718. WriteFixed64(fieldNumber, fieldName, value);
  719. }
  720. }
  721. public void WriteSFixed64Array(int fieldNumber, string fieldName, IEnumerable<long> list)
  722. {
  723. foreach (var value in list)
  724. {
  725. WriteSFixed64(fieldNumber, fieldName, value);
  726. }
  727. }
  728. public void WriteDoubleArray(int fieldNumber, string fieldName, IEnumerable<double> list)
  729. {
  730. foreach (var value in list)
  731. {
  732. WriteDouble(fieldNumber, fieldName, value);
  733. }
  734. }
  735. public void WriteFloatArray(int fieldNumber, string fieldName, IEnumerable<float> list)
  736. {
  737. foreach (var value in list)
  738. {
  739. WriteFloat(fieldNumber, fieldName, value);
  740. }
  741. }
  742. [CLSCompliant(false)]
  743. public void WriteEnumArray<T>(int fieldNumber, string fieldName, IEnumerable<T> list)
  744. where T : struct, IComparable, IFormattable, IConvertible
  745. {
  746. if (list is ICastArray)
  747. {
  748. foreach (int value in ((ICastArray) list).CastArray<int>())
  749. {
  750. WriteEnum(fieldNumber, fieldName, value, null /*unused*/);
  751. }
  752. }
  753. else
  754. {
  755. foreach (object value in list)
  756. {
  757. WriteEnum(fieldNumber, fieldName, (int) value, null /*unused*/);
  758. }
  759. }
  760. }
  761. #endregion
  762. #region Write packed array members
  763. public void WritePackedArray(FieldType fieldType, int fieldNumber, string fieldName, IEnumerable list)
  764. {
  765. int calculatedSize = 0;
  766. foreach (object element in list)
  767. {
  768. calculatedSize += ComputeFieldSizeNoTag(fieldType, element);
  769. }
  770. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  771. WriteRawVarint32((uint) calculatedSize);
  772. foreach (object element in list)
  773. {
  774. WriteFieldNoTag(fieldType, element);
  775. }
  776. }
  777. public void WritePackedGroupArray<T>(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<T> list)
  778. where T : IMessageLite
  779. {
  780. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  781. WriteRawVarint32((uint) calculatedSize);
  782. foreach (IMessageLite value in list)
  783. {
  784. WriteGroupNoTag(value);
  785. }
  786. }
  787. public void WritePackedMessageArray<T>(int fieldNumber, string fieldName, int calculatedSize,
  788. IEnumerable<T> list)
  789. where T : IMessageLite
  790. {
  791. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  792. WriteRawVarint32((uint) calculatedSize);
  793. foreach (IMessageLite value in list)
  794. {
  795. WriteMessageNoTag(value);
  796. }
  797. }
  798. public void WritePackedStringArray(int fieldNumber, string fieldName, int calculatedSize,
  799. IEnumerable<string> list)
  800. {
  801. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  802. WriteRawVarint32((uint) calculatedSize);
  803. foreach (var value in list)
  804. {
  805. WriteStringNoTag(value);
  806. }
  807. }
  808. public void WritePackedBytesArray(int fieldNumber, string fieldName, int calculatedSize,
  809. IEnumerable<ByteString> list)
  810. {
  811. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  812. WriteRawVarint32((uint) calculatedSize);
  813. foreach (var value in list)
  814. {
  815. WriteBytesNoTag(value);
  816. }
  817. }
  818. public void WritePackedBoolArray(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<bool> list)
  819. {
  820. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  821. WriteRawVarint32((uint) calculatedSize);
  822. foreach (var value in list)
  823. {
  824. WriteBoolNoTag(value);
  825. }
  826. }
  827. public void WritePackedInt32Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<int> list)
  828. {
  829. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  830. WriteRawVarint32((uint) calculatedSize);
  831. foreach (var value in list)
  832. {
  833. WriteInt32NoTag(value);
  834. }
  835. }
  836. public void WritePackedSInt32Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<int> list)
  837. {
  838. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  839. WriteRawVarint32((uint) calculatedSize);
  840. foreach (var value in list)
  841. {
  842. WriteSInt32NoTag(value);
  843. }
  844. }
  845. public void WritePackedUInt32Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<uint> list)
  846. {
  847. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  848. WriteRawVarint32((uint) calculatedSize);
  849. foreach (var value in list)
  850. {
  851. WriteUInt32NoTag(value);
  852. }
  853. }
  854. public void WritePackedFixed32Array(int fieldNumber, string fieldName, int calculatedSize,
  855. IEnumerable<uint> list)
  856. {
  857. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  858. WriteRawVarint32((uint) calculatedSize);
  859. foreach (var value in list)
  860. {
  861. WriteFixed32NoTag(value);
  862. }
  863. }
  864. public void WritePackedSFixed32Array(int fieldNumber, string fieldName, int calculatedSize,
  865. IEnumerable<int> list)
  866. {
  867. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  868. WriteRawVarint32((uint) calculatedSize);
  869. foreach (var value in list)
  870. {
  871. WriteSFixed32NoTag(value);
  872. }
  873. }
  874. public void WritePackedInt64Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<long> list)
  875. {
  876. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  877. WriteRawVarint32((uint) calculatedSize);
  878. foreach (var value in list)
  879. {
  880. WriteInt64NoTag(value);
  881. }
  882. }
  883. public void WritePackedSInt64Array(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<long> list)
  884. {
  885. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  886. WriteRawVarint32((uint) calculatedSize);
  887. foreach (var value in list)
  888. {
  889. WriteSInt64NoTag(value);
  890. }
  891. }
  892. public void WritePackedUInt64Array(int fieldNumber, string fieldName, int calculatedSize,
  893. IEnumerable<ulong> list)
  894. {
  895. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  896. WriteRawVarint32((uint) calculatedSize);
  897. foreach (var value in list)
  898. {
  899. WriteUInt64NoTag(value);
  900. }
  901. }
  902. public void WritePackedFixed64Array(int fieldNumber, string fieldName, int calculatedSize,
  903. IEnumerable<ulong> list)
  904. {
  905. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  906. WriteRawVarint32((uint) calculatedSize);
  907. foreach (var value in list)
  908. {
  909. WriteFixed64NoTag(value);
  910. }
  911. }
  912. public void WritePackedSFixed64Array(int fieldNumber, string fieldName, int calculatedSize,
  913. IEnumerable<long> list)
  914. {
  915. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  916. WriteRawVarint32((uint) calculatedSize);
  917. foreach (var value in list)
  918. {
  919. WriteSFixed64NoTag(value);
  920. }
  921. }
  922. public void WritePackedDoubleArray(int fieldNumber, string fieldName, int calculatedSize,
  923. IEnumerable<double> list)
  924. {
  925. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  926. WriteRawVarint32((uint) calculatedSize);
  927. foreach (var value in list)
  928. {
  929. WriteDoubleNoTag(value);
  930. }
  931. }
  932. public void WritePackedFloatArray(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<float> list)
  933. {
  934. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  935. WriteRawVarint32((uint) calculatedSize);
  936. foreach (var value in list)
  937. {
  938. WriteFloatNoTag(value);
  939. }
  940. }
  941. [CLSCompliant(false)]
  942. public void WritePackedEnumArray<T>(int fieldNumber, string fieldName, int calculatedSize, IEnumerable<T> list)
  943. where T : struct, IComparable, IFormattable, IConvertible
  944. {
  945. WriteTag(fieldNumber, WireFormat.WireType.LengthDelimited);
  946. WriteRawVarint32((uint) calculatedSize);
  947. if (list is ICastArray)
  948. {
  949. foreach (int value in ((ICastArray) list).CastArray<int>())
  950. {
  951. WriteEnumNoTag(value);
  952. }
  953. }
  954. else
  955. {
  956. foreach (object value in list)
  957. {
  958. WriteEnumNoTag((int) value);
  959. }
  960. }
  961. }
  962. #endregion
  963. #region Underlying writing primitives
  964. /// <summary>
  965. /// Encodes and writes a tag.
  966. /// </summary>
  967. [CLSCompliant(false)]
  968. public void WriteTag(int fieldNumber, WireFormat.WireType type)
  969. {
  970. WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));
  971. }
  972. /// <summary>
  973. /// Writes a 32 bit value as a varint. The fast route is taken when
  974. /// there's enough buffer space left to whizz through without checking
  975. /// for each byte; otherwise, we resort to calling WriteRawByte each time.
  976. /// </summary>
  977. [CLSCompliant(false)]
  978. public void WriteRawVarint32(uint value)
  979. {
  980. while (value > 127 && position < limit)
  981. {
  982. buffer[position++] = (byte) ((value & 0x7F) | 0x80);
  983. value >>= 7;
  984. }
  985. while (value > 127)
  986. {
  987. WriteRawByte((byte) ((value & 0x7F) | 0x80));
  988. value >>= 7;
  989. }
  990. if (position < limit)
  991. {
  992. buffer[position++] = (byte) value;
  993. }
  994. else
  995. {
  996. WriteRawByte((byte) value);
  997. }
  998. }
  999. [CLSCompliant(false)]
  1000. public void WriteRawVarint64(ulong value)
  1001. {
  1002. while (value > 127 && position < limit)
  1003. {
  1004. buffer[position++] = (byte) ((value & 0x7F) | 0x80);
  1005. value >>= 7;
  1006. }
  1007. while (value > 127)
  1008. {
  1009. WriteRawByte((byte) ((value & 0x7F) | 0x80));
  1010. value >>= 7;
  1011. }
  1012. if (position < limit)
  1013. {
  1014. buffer[position++] = (byte) value;
  1015. }
  1016. else
  1017. {
  1018. WriteRawByte((byte) value);
  1019. }
  1020. }
  1021. [CLSCompliant(false)]
  1022. public void WriteRawLittleEndian32(uint value)
  1023. {
  1024. if (position + 4 > limit)
  1025. {
  1026. WriteRawByte((byte) value);
  1027. WriteRawByte((byte) (value >> 8));
  1028. WriteRawByte((byte) (value >> 16));
  1029. WriteRawByte((byte) (value >> 24));
  1030. }
  1031. else
  1032. {
  1033. buffer[position++] = ((byte) value);
  1034. buffer[position++] = ((byte) (value >> 8));
  1035. buffer[position++] = ((byte) (value >> 16));
  1036. buffer[position++] = ((byte) (value >> 24));
  1037. }
  1038. }
  1039. [CLSCompliant(false)]
  1040. public void WriteRawLittleEndian64(ulong value)
  1041. {
  1042. if (position + 8 > limit)
  1043. {
  1044. WriteRawByte((byte) value);
  1045. WriteRawByte((byte) (value >> 8));
  1046. WriteRawByte((byte) (value >> 16));
  1047. WriteRawByte((byte) (value >> 24));
  1048. WriteRawByte((byte) (value >> 32));
  1049. WriteRawByte((byte) (value >> 40));
  1050. WriteRawByte((byte) (value >> 48));
  1051. WriteRawByte((byte) (value >> 56));
  1052. }
  1053. else
  1054. {
  1055. buffer[position++] = ((byte) value);
  1056. buffer[position++] = ((byte) (value >> 8));
  1057. buffer[position++] = ((byte) (value >> 16));
  1058. buffer[position++] = ((byte) (value >> 24));
  1059. buffer[position++] = ((byte) (value >> 32));
  1060. buffer[position++] = ((byte) (value >> 40));
  1061. buffer[position++] = ((byte) (value >> 48));
  1062. buffer[position++] = ((byte) (value >> 56));
  1063. }
  1064. }
  1065. public void WriteRawByte(byte value)
  1066. {
  1067. if (position == limit)
  1068. {
  1069. RefreshBuffer();
  1070. }
  1071. buffer[position++] = value;
  1072. }
  1073. [CLSCompliant(false)]
  1074. public void WriteRawByte(uint value)
  1075. {
  1076. WriteRawByte((byte) value);
  1077. }
  1078. /// <summary>
  1079. /// Writes out an array of bytes.
  1080. /// </summary>
  1081. public void WriteRawBytes(byte[] value)
  1082. {
  1083. WriteRawBytes(value, 0, value.Length);
  1084. }
  1085. /// <summary>
  1086. /// Writes out part of an array of bytes.
  1087. /// </summary>
  1088. public void WriteRawBytes(byte[] value, int offset, int length)
  1089. {
  1090. if (limit - position >= length)
  1091. {
  1092. ByteArray.Copy(value, offset, buffer, position, length);
  1093. // We have room in the current buffer.
  1094. position += length;
  1095. }
  1096. else
  1097. {
  1098. // Write extends past current buffer. Fill the rest of this buffer and
  1099. // flush.
  1100. int bytesWritten = limit - position;
  1101. ByteArray.Copy(value, offset, buffer, position, bytesWritten);
  1102. offset += bytesWritten;
  1103. length -= bytesWritten;
  1104. position = limit;
  1105. RefreshBuffer();
  1106. // Now deal with the rest.
  1107. // Since we have an output stream, this is our buffer
  1108. // and buffer offset == 0
  1109. if (length <= limit)
  1110. {
  1111. // Fits in new buffer.
  1112. ByteArray.Copy(value, offset, buffer, 0, length);
  1113. position = length;
  1114. }
  1115. else
  1116. {
  1117. // Write is very big. Let's do it all at once.
  1118. output.Write(value, offset, length);
  1119. }
  1120. }
  1121. }
  1122. #endregion
  1123. /// <summary>
  1124. /// Encode a 32-bit value with ZigZag encoding.
  1125. /// </summary>
  1126. /// <remarks>
  1127. /// ZigZag encodes signed integers into values that can be efficiently
  1128. /// encoded with varint. (Otherwise, negative values must be
  1129. /// sign-extended to 64 bits to be varint encoded, thus always taking
  1130. /// 10 bytes on the wire.)
  1131. /// </remarks>
  1132. [CLSCompliant(false)]
  1133. public static uint EncodeZigZag32(int n)
  1134. {
  1135. // Note: the right-shift must be arithmetic
  1136. return (uint) ((n << 1) ^ (n >> 31));
  1137. }
  1138. /// <summary>
  1139. /// Encode a 64-bit value with ZigZag encoding.
  1140. /// </summary>
  1141. /// <remarks>
  1142. /// ZigZag encodes signed integers into values that can be efficiently
  1143. /// encoded with varint. (Otherwise, negative values must be
  1144. /// sign-extended to 64 bits to be varint encoded, thus always taking
  1145. /// 10 bytes on the wire.)
  1146. /// </remarks>
  1147. [CLSCompliant(false)]
  1148. public static ulong EncodeZigZag64(long n)
  1149. {
  1150. return (ulong) ((n << 1) ^ (n >> 63));
  1151. }
  1152. private void RefreshBuffer()
  1153. {
  1154. if (output == null)
  1155. {
  1156. // We're writing to a single buffer.
  1157. throw new OutOfSpaceException();
  1158. }
  1159. // Since we have an output stream, this is our buffer
  1160. // and buffer offset == 0
  1161. output.Write(buffer, 0, position);
  1162. position = 0;
  1163. }
  1164. /// <summary>
  1165. /// Indicates that a CodedOutputStream wrapping a flat byte array
  1166. /// ran out of space.
  1167. /// </summary>
  1168. public sealed class OutOfSpaceException : IOException
  1169. {
  1170. internal OutOfSpaceException()
  1171. : base("CodedOutputStream was writing to a flat byte array and ran out of space.")
  1172. {
  1173. }
  1174. }
  1175. public void Flush()
  1176. {
  1177. if (output != null)
  1178. {
  1179. RefreshBuffer();
  1180. }
  1181. }
  1182. /// <summary>
  1183. /// Verifies that SpaceLeft returns zero. It's common to create a byte array
  1184. /// that is exactly big enough to hold a message, then write to it with
  1185. /// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that
  1186. /// the message was actually as big as expected, which can help bugs.
  1187. /// </summary>
  1188. public void CheckNoSpaceLeft()
  1189. {
  1190. if (SpaceLeft != 0)
  1191. {
  1192. throw new InvalidOperationException("Did not write as much data as expected.");
  1193. }
  1194. }
  1195. /// <summary>
  1196. /// If writing to a flat array, returns the space left in the array. Otherwise,
  1197. /// throws an InvalidOperationException.
  1198. /// </summary>
  1199. public int SpaceLeft
  1200. {
  1201. get
  1202. {
  1203. if (output == null)
  1204. {
  1205. return limit - position;
  1206. }
  1207. else
  1208. {
  1209. throw new InvalidOperationException(
  1210. "SpaceLeft can only be called on CodedOutputStreams that are " +
  1211. "writing to a flat array.");
  1212. }
  1213. }
  1214. }
  1215. }
  1216. }