ProtoBuf.java 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338
  1. // Copyright 2007 The Android Open Source Project
  2. // All Rights Reserved.
  3. package com.google.common.io.protocol;
  4. import java.io.*;
  5. import java.util.*;
  6. /**
  7. * Protocol buffer message object. Currently, it is assumed that tags ids are
  8. * not large. This could be improved by storing a start offset, reducing the
  9. * assumption to a dense number space.
  10. * <p>
  11. * ProtoBuf instances may or may not reference a ProtoBufType instance,
  12. * representing information from a corresponding .proto file, which defines tag
  13. * data types. The type can only be set in the constructor, it cannot be
  14. * changed later.
  15. * <p>
  16. * If the type is null, the ProtoBuffer should be used only for reading or
  17. * as a local persistent storage buffer. An untyped Protocol Buffer must never
  18. * be sent to a server.
  19. * <p>
  20. * If a ProtoBufType is set, unknown values are read from the stream and
  21. * preserved, but it is not possible to add values for undefined tags using
  22. * this API. Attempts to set undefined tags will result in an exception.
  23. * <p>
  24. * This class provides two different sets of access methods for simple and
  25. * repeated tags. Simple access methods are has(tag), getXXX(tag),
  26. * and setXXX(tag, value). Access methods for repeated tags are getCount(tag),
  27. * getXXX(tag, index), remove(tag, index), insert(tag, index, value) and
  28. * addXXX(tag, value). Note that both sets of methods can be used in both cases,
  29. * but only the simple methods take default values into account. The reason for
  30. * this behavior is that default values cannot be removed -- they would reappear
  31. * after a serialization cycle. If a tag has repeated values, setXXX(tag, value)
  32. * will overwrite all of them and getXXX(tag) will throw an exception.
  33. *
  34. */
  35. public class ProtoBuf {
  36. public static final Boolean FALSE = new Boolean(false);
  37. public static final Boolean TRUE = new Boolean(true);
  38. private static final String MSG_EOF = "Unexp.EOF";
  39. private static final String MSG_MISMATCH = "Type mismatch";
  40. private static final String MSG_UNSUPPORTED = "Unsupp.Type";
  41. // names copied from //net/proto2/internal/wire_format.cc
  42. static final int WIRETYPE_END_GROUP = 4;
  43. static final int WIRETYPE_FIXED32 = 5;
  44. static final int WIRETYPE_FIXED64 = 1;
  45. static final int WIRETYPE_LENGTH_DELIMITED = 2;
  46. static final int WIRETYPE_START_GROUP = 3;
  47. static final int WIRETYPE_VARINT = 0;
  48. /** Maximum number of bytes for VARINT wire format (64 bit, 7 bit/byte) */
  49. private static final int VARINT_MAX_BYTES = 10;
  50. private static Long[] SMALL_NUMBERS = {
  51. new Long(0), new Long(1), new Long(2), new Long(3), new Long(4),
  52. new Long(5), new Long(6), new Long(7), new Long(8), new Long(9),
  53. new Long(10), new Long(11), new Long(12), new Long(13), new Long(14),
  54. new Long(15)};
  55. private ProtoBufType msgType;
  56. private final Vector values = new Vector();
  57. /**
  58. * Wire types picked up on the wire or implied by setters (if no other
  59. * type information is available.
  60. */
  61. private final StringBuffer wireTypes = new StringBuffer();
  62. /**
  63. * Creates a protocol message according to the given description. The
  64. * description is required if it is necessary to write the protocol buffer for
  65. * data exchange with other systems relying on the .proto file.
  66. */
  67. public ProtoBuf(ProtoBufType type) {
  68. this.msgType = type;
  69. }
  70. /**
  71. * Clears all data stored in this ProtoBuf.
  72. */
  73. public void clear() {
  74. values.setSize(0);
  75. wireTypes.setLength(0);
  76. }
  77. /**
  78. * Creates a new instance of the group with the given tag.
  79. */
  80. public ProtoBuf createGroup(int tag) {
  81. return new ProtoBuf((ProtoBufType) getType().getData(tag));
  82. }
  83. /**
  84. * Appends the given (repeated) tag with the given boolean value.
  85. */
  86. public void addBool(int tag, boolean value){
  87. insertBool(tag, getCount(tag), value);
  88. }
  89. /**
  90. * Appends the given (repeated) tag with the given byte[] value.
  91. */
  92. public void addBytes(int tag, byte[] value){
  93. insertBytes(tag, getCount(tag), value);
  94. }
  95. /**
  96. * Appends the given (repeated) tag with the given int value.
  97. */
  98. public void addInt(int tag, int value){
  99. insertInt(tag, getCount(tag), value);
  100. }
  101. /**
  102. * Appends the given (repeated) tag with the given long value.
  103. */
  104. public void addLong(int tag, long value){
  105. insertLong(tag, getCount(tag), value);
  106. }
  107. /**
  108. * Appends the given (repeated) tag with the given float value.
  109. */
  110. public void addFloat(int tag, float value) {
  111. insertFloat(tag, getCount(tag), value);
  112. }
  113. /**
  114. * Appends the given (repeated) tag with the given double value.
  115. */
  116. public void addDouble(int tag, double value) {
  117. insertDouble(tag, getCount(tag), value);
  118. }
  119. /**
  120. * Appends the given (repeated) tag with the given group or message value.
  121. */
  122. public void addProtoBuf(int tag, ProtoBuf value){
  123. insertProtoBuf(tag, getCount(tag), value);
  124. }
  125. /**
  126. * Adds a new protobuf for the specified tag, setting the child protobuf's
  127. * type correctly for the tag.
  128. * @param tag the tag for which to create a new protobuf
  129. * @return the newly created protobuf
  130. */
  131. public ProtoBuf addNewProtoBuf(int tag) {
  132. ProtoBuf child = newProtoBufForTag(tag);
  133. addProtoBuf(tag, child);
  134. return child;
  135. }
  136. /**
  137. * Creates and returns a new protobuf for the specified tag, setting the new
  138. * protobuf's type correctly for the tag.
  139. * @param tag the tag for which to create a new protobuf
  140. * @return the newly created protobuf
  141. */
  142. public ProtoBuf newProtoBufForTag(int tag) {
  143. return new ProtoBuf((ProtoBufType) msgType.getData(tag));
  144. }
  145. /**
  146. * Appends the given (repeated) tag with the given String value.
  147. */
  148. public void addString(int tag, String value){
  149. insertString(tag, getCount(tag), value);
  150. }
  151. /**
  152. * Returns the boolean value for the given tag.
  153. */
  154. public boolean getBool(int tag) {
  155. return ((Boolean) getObject(tag, ProtoBufType.TYPE_BOOL))
  156. .booleanValue();
  157. }
  158. /**
  159. * Returns the boolean value for the given repeated tag at the given index.
  160. */
  161. public boolean getBool(int tag, int index) {
  162. return ((Boolean) getObject(tag, index, ProtoBufType.TYPE_BOOL))
  163. .booleanValue();
  164. }
  165. /**
  166. * Returns the given string tag as byte array.
  167. */
  168. public byte[] getBytes(int tag) {
  169. return (byte[]) getObject(tag, ProtoBufType.TYPE_DATA);
  170. }
  171. /**
  172. * Returns the given repeated string tag at the given index as byte array.
  173. */
  174. public byte[] getBytes(int tag, int index) {
  175. return (byte[]) getObject(tag, index, ProtoBufType.TYPE_DATA);
  176. }
  177. /**
  178. * Returns the integer value for the given tag.
  179. */
  180. public int getInt(int tag) {
  181. return (int) ((Long) getObject(tag, ProtoBufType.TYPE_INT32)).longValue();
  182. }
  183. /**
  184. * Returns the integer value for the given repeated tag at the given index.
  185. */
  186. public int getInt(int tag, int index) {
  187. return (int) ((Long) getObject(tag, index,
  188. ProtoBufType.TYPE_INT32)).longValue();
  189. }
  190. /**
  191. * Returns the long value for the given tag.
  192. */
  193. public long getLong(int tag) {
  194. return ((Long) getObject(tag, ProtoBufType.TYPE_INT64)).longValue();
  195. }
  196. /**
  197. * Returns the long value for the given repeated tag at the given index.
  198. */
  199. public long getLong(int tag, int index) {
  200. return ((Long) getObject(tag, index, ProtoBufType.TYPE_INT64)).longValue();
  201. }
  202. /**
  203. * Returns the float value for the given tag.
  204. */
  205. public float getFloat(int tag) {
  206. return Float.intBitsToFloat(getInt(tag));
  207. }
  208. /**
  209. * Returns the float value for the given repeated tag at the given index.
  210. */
  211. public float getFloat(int tag, int index) {
  212. return Float.intBitsToFloat(getInt(tag, index));
  213. }
  214. /**
  215. * Returns the double value for the given tag.
  216. */
  217. public double getDouble(int tag) {
  218. return Double.longBitsToDouble(getLong(tag));
  219. }
  220. /**
  221. * Returns the double value for the given repeated tag at the given index.
  222. */
  223. public double getDouble(int tag, int index) {
  224. return Double.longBitsToDouble(getLong(tag, index));
  225. }
  226. /**
  227. * Returns the group or nested message for the given tag.
  228. */
  229. public ProtoBuf getProtoBuf(int tag) {
  230. return (ProtoBuf) getObject(tag, ProtoBufType.TYPE_GROUP);
  231. }
  232. /**
  233. * Returns the group or nested message for the given repeated tag at the given
  234. * index.
  235. */
  236. public ProtoBuf getProtoBuf(int tag, int index) {
  237. return (ProtoBuf) getObject(tag, index, ProtoBufType.TYPE_GROUP);
  238. }
  239. /**
  240. * Returns the string value for a given tag converted to a Java String
  241. * assuming UTF-8 encoding.
  242. */
  243. public String getString(int tag) {
  244. return (String) getObject(tag, ProtoBufType.TYPE_TEXT);
  245. }
  246. /**
  247. * Returns the string value for a given repeated tag at the given index
  248. * converted to a Java String assuming UTF-8 encoding.
  249. */
  250. public String getString(int tag, int index) {
  251. return (String) getObject(tag, index, ProtoBufType.TYPE_TEXT);
  252. }
  253. /**
  254. * Returns the type definition of this protocol buffer or group -- if set.
  255. */
  256. public ProtoBufType getType() {
  257. return msgType;
  258. }
  259. /**
  260. * Sets the type definition of this protocol buffer. Used internally in
  261. * ProtoBufUtil for incremental reading.
  262. *
  263. * @param type the new type
  264. */
  265. void setType(ProtoBufType type) {
  266. if (values.size() != 0 ||
  267. (msgType != null && type != null && type != msgType)) {
  268. throw new IllegalArgumentException();
  269. }
  270. this.msgType = type;
  271. }
  272. /**
  273. * Convenience method for determining whether a tag has a value. Note: in
  274. * contrast to getCount(tag) &gt; 0, this method takes the default value
  275. * into account.
  276. */
  277. public boolean has(int tag){
  278. return getCount(tag) > 0 || getDefault(tag) != null;
  279. }
  280. /**
  281. * Reads the contents of this ProtocolMessage from the given byte array.
  282. * Currently, this is a shortcut for parse(new ByteArrayInputStream(data)).
  283. * However, this may change in future versions for efficiency reasons.
  284. *
  285. * @param data the byte array the ProtocolMessage is read from
  286. * @throws IOException if an unexpected "End of file" is encountered in
  287. * the byte array
  288. */
  289. public ProtoBuf parse(byte[] data) throws IOException {
  290. parse(new ByteArrayInputStream(data), data.length);
  291. return this;
  292. }
  293. /**
  294. * Reads the contents of this ProtocolMessage from the given stream.
  295. *
  296. * @param is the input stream providing the contents
  297. * @return this
  298. * @throws IOException raised if an IO exception occurs in the underlying
  299. * stream or the end of the stream is reached at an unexpected
  300. * position
  301. */
  302. public ProtoBuf parse(InputStream is) throws IOException {
  303. parse(is, Integer.MAX_VALUE);
  304. return this;
  305. }
  306. /**
  307. * Reads the contents of this ProtocolMessage from the given stream, consuming
  308. * at most the given number of bytes.
  309. *
  310. * @param is the input stream providing the contents
  311. * @param available maximum number of bytes to read
  312. * @return this
  313. * @throws IOException raised if an IO exception occurs in the
  314. * underlying stream or the end of the stream is reached at
  315. * an unexpected position
  316. */
  317. public int parse(InputStream is, int available) throws IOException {
  318. clear();
  319. while (available > 0) {
  320. long tagAndType = readVarInt(is, true /* permits EOF */);
  321. if (tagAndType == -1){
  322. break;
  323. }
  324. available -= getVarIntSize(tagAndType);
  325. int wireType = ((int) tagAndType) & 0x07;
  326. if (wireType == WIRETYPE_END_GROUP) {
  327. break;
  328. }
  329. int tag = (int) (tagAndType >>> 3);
  330. while (wireTypes.length() <= tag){
  331. wireTypes.append((char) ProtoBufType.TYPE_UNDEFINED);
  332. }
  333. wireTypes.setCharAt(tag, (char) wireType);
  334. // first step: decode tag value
  335. Object value;
  336. switch (wireType) {
  337. case WIRETYPE_VARINT:
  338. long v = readVarInt(is, false);
  339. available -= getVarIntSize(v);
  340. if (isZigZagEncodedType(tag)) {
  341. v = zigZagDecode(v);
  342. }
  343. value = (v >= 0 && v < SMALL_NUMBERS.length) ?
  344. SMALL_NUMBERS[(int) v] : new Long(v);
  345. break;
  346. // also used for fixed values
  347. case WIRETYPE_FIXED32:
  348. case WIRETYPE_FIXED64:
  349. v = 0;
  350. int shift = 0;
  351. int count = (wireType == WIRETYPE_FIXED32) ? 4 : 8;
  352. available -= count;
  353. while (count-- > 0) {
  354. long l = is.read();
  355. v |= l << shift;
  356. shift += 8;
  357. }
  358. value = (v >= 0 && v < SMALL_NUMBERS.length)
  359. ? SMALL_NUMBERS[(int) v]
  360. : new Long(v);
  361. break;
  362. case WIRETYPE_LENGTH_DELIMITED:
  363. int total = (int) readVarInt(is, false);
  364. available -= getVarIntSize(total);
  365. available -= total;
  366. if (getType(tag) == ProtoBufType.TYPE_MESSAGE) {
  367. ProtoBuf msg = new ProtoBuf((ProtoBufType) msgType.getData(tag));
  368. msg.parse(is, total);
  369. value = msg;
  370. } else {
  371. byte[] data = new byte[total];
  372. int pos = 0;
  373. while (pos < total) {
  374. count = is.read(data, pos, total - pos);
  375. if (count <= 0) {
  376. throw new IOException(MSG_EOF);
  377. }
  378. pos += count;
  379. }
  380. value = data;
  381. }
  382. break;
  383. case WIRETYPE_START_GROUP:
  384. ProtoBuf group = new ProtoBuf(msgType == null
  385. ? null
  386. : ((ProtoBufType) msgType.getData(tag)));
  387. available = group.parse(is, available);
  388. value = group;
  389. break;
  390. default:
  391. throw new RuntimeException(MSG_UNSUPPORTED + wireType);
  392. }
  393. insertObject(tag, getCount(tag), value);
  394. }
  395. if (available < 0){
  396. throw new IOException();
  397. }
  398. return available;
  399. }
  400. /**
  401. * Removes the tag value at the given index.
  402. */
  403. public void remove(int tag, int index){
  404. int count = getCount(tag);
  405. if (index >= count){
  406. throw new ArrayIndexOutOfBoundsException();
  407. }
  408. if (count == 1){
  409. values.setElementAt(null, tag);
  410. } else {
  411. Vector v = (Vector) values.elementAt(tag);
  412. v.removeElementAt(index);
  413. }
  414. }
  415. /**
  416. * Returns the number of repeated and optional (0..1) values for a given tag.
  417. * Note: Default values are not counted (and in general not considered in
  418. * access methods for repeated tags), but considered for has(tag).
  419. */
  420. public int getCount(int tag) {
  421. if (tag >= values.size()){
  422. return 0;
  423. }
  424. Object o = values.elementAt(tag);
  425. if (o == null){
  426. return 0;
  427. }
  428. return (o instanceof Vector) ? ((Vector) o).size() : 1;
  429. }
  430. /**
  431. * Returns the tag type of the given tag (one of the ProtoBufType.TYPE_XXX
  432. * constants). If no ProtoBufType is set, the wire type is returned. If no
  433. * wire type is available, the wire type is determined by looking at the
  434. * tag value (making sure the wire type is consistent for all values). If
  435. * no value is set, TYPE_UNDEFINED is returned.
  436. */
  437. public int getType(int tag){
  438. int tagType = ProtoBufType.TYPE_UNDEFINED;
  439. if (msgType != null){
  440. tagType = msgType.getType(tag);
  441. }
  442. if (tagType == ProtoBufType.TYPE_UNDEFINED && tag < wireTypes.length()) {
  443. tagType = wireTypes.charAt(tag);
  444. }
  445. if (tagType == ProtoBufType.TYPE_UNDEFINED && getCount(tag) > 0) {
  446. Object o = getObject(tag, 0, ProtoBufType.TYPE_UNDEFINED);
  447. tagType = (o instanceof Long) || (o instanceof Boolean)
  448. ? WIRETYPE_VARINT : WIRETYPE_LENGTH_DELIMITED;
  449. }
  450. return tagType;
  451. }
  452. /**
  453. * Returns the number of bytes needed to store this protocol buffer
  454. */
  455. public int getDataSize() {
  456. int size = 0;
  457. for (int tag = 0; tag <= maxTag(); tag++) {
  458. for (int i = 0; i < getCount(tag); i++) {
  459. size += getDataSize(tag, i);
  460. }
  461. }
  462. return size;
  463. }
  464. /**
  465. * Returns the size of the given value
  466. */
  467. private int getDataSize(int tag, int i) {
  468. int tagSize = getVarIntSize(tag << 3);
  469. switch(getWireType(tag)){
  470. case WIRETYPE_FIXED32:
  471. return tagSize + 4;
  472. case WIRETYPE_FIXED64:
  473. return tagSize + 8;
  474. case WIRETYPE_VARINT:
  475. long value = getLong(tag, i);
  476. if (isZigZagEncodedType(tag)) {
  477. value = zigZagEncode(value);
  478. }
  479. return tagSize + getVarIntSize(value);
  480. case WIRETYPE_START_GROUP:
  481. // take end group into account....
  482. return tagSize + getProtoBuf(tag, i).getDataSize() + tagSize;
  483. }
  484. // take the object as stored
  485. Object o = getObject(tag, i, ProtoBufType.TYPE_UNDEFINED);
  486. int contentSize;
  487. if (o instanceof byte[]){
  488. contentSize = ((byte[]) o).length;
  489. } else if (o instanceof String) {
  490. contentSize = encodeUtf8((String) o, null, 0);
  491. } else {
  492. contentSize = ((ProtoBuf) o).getDataSize();
  493. }
  494. return tagSize + getVarIntSize(contentSize) + contentSize;
  495. }
  496. /**
  497. * Returns the number of bytes needed to encode the given value using
  498. * WIRETYPE_VARINT
  499. */
  500. private static int getVarIntSize(long i) {
  501. if (i < 0) {
  502. return 10;
  503. }
  504. int size = 1;
  505. while (i >= 128) {
  506. size++;
  507. i >>= 7;
  508. }
  509. return size;
  510. }
  511. /**
  512. * Writes this and nested protocol buffers to the given output stream.
  513. *
  514. * @param os target output stream
  515. * @throws IOException thrown if there is an IOException
  516. */
  517. public void outputTo(OutputStream os) throws IOException {
  518. for (int tag = 0; tag <= maxTag(); tag++) {
  519. int size = getCount(tag);
  520. int wireType = getWireType(tag);
  521. // ignore default values
  522. for (int i = 0; i < size; i++) {
  523. writeVarInt(os, (tag << 3) | wireType);
  524. switch (wireType) {
  525. case WIRETYPE_FIXED32:
  526. case WIRETYPE_FIXED64:
  527. long v = ((Long) getObject(tag, i, ProtoBufType.TYPE_INT64))
  528. .longValue();
  529. int cnt = (wireType == WIRETYPE_FIXED32) ? 4 : 8;
  530. for (int b = 0; b < cnt; b++) {
  531. os.write((int) (v & 0x0ff));
  532. v >>= 8;
  533. }
  534. break;
  535. case WIRETYPE_VARINT:
  536. v = ((Long) getObject(tag, i, ProtoBufType.TYPE_INT64)).longValue();
  537. if (isZigZagEncodedType(tag)) {
  538. v = zigZagEncode(v);
  539. }
  540. writeVarInt(os, v);
  541. break;
  542. case WIRETYPE_LENGTH_DELIMITED:
  543. Object o = getObject(tag, i,
  544. getType(tag) == ProtoBufType.TYPE_MESSAGE
  545. ? ProtoBufType.TYPE_UNDEFINED
  546. : ProtoBufType.TYPE_DATA);
  547. if (o instanceof byte[]){
  548. byte[] data = (byte[]) o;
  549. writeVarInt(os, data.length);
  550. os.write(data);
  551. } else {
  552. ProtoBuf msg = (ProtoBuf) o;
  553. writeVarInt(os, msg.getDataSize());
  554. msg.outputTo(os);
  555. }
  556. break;
  557. case WIRETYPE_START_GROUP:
  558. ((ProtoBuf) getObject(tag, i, ProtoBufType.TYPE_GROUP))
  559. .outputTo(os);
  560. writeVarInt(os, (tag << 3) | WIRETYPE_END_GROUP);
  561. break;
  562. default:
  563. throw new IllegalArgumentException();
  564. }
  565. }
  566. }
  567. }
  568. /**
  569. * Returns true if the given tag has a signed type that should be ZigZag-
  570. * encoded on the wire.
  571. *
  572. * ZigZag encoding turns a signed number into
  573. * a non-negative number by mapping negative input numbers to positive odd
  574. * numbers in the output space, and positive input numbers to positive even
  575. * numbers in the output space. This is useful because the wire format
  576. * for protocol buffers requires a large number of bytes to encode
  577. * negative integers, while positive integers take up a smaller number
  578. * of bytes proportional to their magnitude.
  579. */
  580. private boolean isZigZagEncodedType(int tag) {
  581. int declaredType = getType(tag);
  582. return declaredType == ProtoBufType.TYPE_SINT32 ||
  583. declaredType == ProtoBufType.TYPE_SINT64;
  584. }
  585. /**
  586. * Converts a signed number into a non-negative ZigZag-encoded number.
  587. */
  588. private static long zigZagEncode(long v) {
  589. v = ((v << 1) ^ -(v >>> 63));
  590. return v;
  591. }
  592. /**
  593. * Converts a non-negative ZigZag-encoded number back into a signed number.
  594. */
  595. private static long zigZagDecode(long v) {
  596. v = (v >>> 1) ^ -(v & 1);
  597. return v;
  598. }
  599. /**
  600. * Writes this and nested protocol buffers to a byte array.
  601. *
  602. * @throws IOException thrown if there is problem writing the byte array
  603. */
  604. public byte[] toByteArray() throws IOException {
  605. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  606. outputTo(baos);
  607. return baos.toByteArray();
  608. }
  609. /**
  610. * Returns the largest tag id used in this message (to simplify testing).
  611. */
  612. public int maxTag() {
  613. return values.size() - 1;
  614. }
  615. /**
  616. * Sets the given tag to the given boolean value.
  617. */
  618. public void setBool(int tag, boolean value) {
  619. setObject(tag, value ? TRUE : FALSE);
  620. }
  621. /**
  622. * Sets the given tag to the given data bytes.
  623. */
  624. public void setBytes(int tag, byte[] value) {
  625. setObject(tag, value);
  626. }
  627. /**
  628. * Sets the given tag to the given integer value.
  629. */
  630. public void setInt(int tag, int value) {
  631. setLong(tag, value);
  632. }
  633. /**
  634. * Sets the given tag to the given long value.
  635. */
  636. public void setLong(int tag, long value) {
  637. setObject(tag, value >= 0 && value < SMALL_NUMBERS.length
  638. ? SMALL_NUMBERS[(int) value] : new Long(value));
  639. }
  640. /**
  641. * Sets the given tag to the given double value.
  642. */
  643. public void setDouble(int tag, double value) {
  644. setLong(tag, Double.doubleToLongBits(value));
  645. }
  646. /**
  647. * Sets the given tag to the given float value.
  648. */
  649. public void setFloat(int tag, float value) {
  650. setInt(tag, Float.floatToIntBits(value));
  651. }
  652. /**
  653. * Sets the given tag to the given Group or nested Message.
  654. */
  655. public void setProtoBuf(int tag, ProtoBuf pb) {
  656. setObject(tag, pb);
  657. }
  658. /**
  659. * Sets a new protobuf for the specified tag, setting the child protobuf's
  660. * type correctly for the tag.
  661. * @param tag the tag for which to create a new protobuf
  662. * @return the newly created protobuf
  663. */
  664. public ProtoBuf setNewProtoBuf(int tag) {
  665. ProtoBuf child = newProtoBufForTag(tag);
  666. setProtoBuf(tag, child);
  667. return child;
  668. }
  669. /**
  670. * Sets the given tag to the given String value.
  671. */
  672. public void setString(int tag, String value) {
  673. setObject(tag, value);
  674. }
  675. /**
  676. * Inserts the given boolean value for the given tag at the given index.
  677. */
  678. public void insertBool(int tag, int index, boolean value) {
  679. insertObject(tag, index, value ? TRUE : FALSE);
  680. }
  681. /**
  682. * Inserts the given byte array value for the given tag at the given index.
  683. */
  684. public void insertBytes(int tag, int index, byte[] value) {
  685. insertObject(tag, index, value);
  686. }
  687. /**
  688. * Inserts the given int value for the given tag at the given index.
  689. */
  690. public void insertInt(int tag, int index, int value) {
  691. insertLong(tag, index, value);
  692. }
  693. /**
  694. * Inserts the given long value for the given tag at the given index.
  695. */
  696. public void insertLong(int tag, int index, long value) {
  697. insertObject(tag, index, value >= 0 && value < SMALL_NUMBERS.length
  698. ? SMALL_NUMBERS[(int) value] : new Long(value));
  699. }
  700. /**
  701. * Inserts the given float value for the given tag at the given index.
  702. */
  703. public void insertFloat(int tag, int index, float value) {
  704. insertInt(tag, index, Float.floatToIntBits(value));
  705. }
  706. /**
  707. * Inserts the given double value for the given tag at the given index.
  708. */
  709. public void insertDouble(int tag, int index, double value) {
  710. insertLong(tag, index, Double.doubleToLongBits(value));
  711. }
  712. /**
  713. * Inserts the given group or message for the given tag at the given index.
  714. */
  715. public void insertProtoBuf(int tag, int index, ProtoBuf pb) {
  716. insertObject(tag, index, pb);
  717. }
  718. /**
  719. * Inserts the given string value for the given tag at the given index.
  720. */
  721. public void insertString(int tag, int index, String value) {
  722. insertObject(tag, index, value);
  723. }
  724. // ----------------- private stuff below this line ------------------------
  725. private void assertTypeMatch(int tag, Object object){
  726. int tagType = getType(tag);
  727. if (tagType == ProtoBufType.TYPE_UNDEFINED && msgType == null) {
  728. return;
  729. }
  730. if (object instanceof Boolean) {
  731. if (tagType == ProtoBufType.TYPE_BOOL
  732. || tagType == WIRETYPE_VARINT) {
  733. return;
  734. }
  735. } else if (object instanceof Long) {
  736. switch(tagType){
  737. case WIRETYPE_FIXED32:
  738. case WIRETYPE_FIXED64:
  739. case WIRETYPE_VARINT:
  740. case ProtoBufType.TYPE_BOOL:
  741. case ProtoBufType.TYPE_ENUM:
  742. case ProtoBufType.TYPE_FIXED32:
  743. case ProtoBufType.TYPE_FIXED64:
  744. case ProtoBufType.TYPE_INT32:
  745. case ProtoBufType.TYPE_INT64:
  746. case ProtoBufType.TYPE_SFIXED32:
  747. case ProtoBufType.TYPE_SFIXED64:
  748. case ProtoBufType.TYPE_UINT32:
  749. case ProtoBufType.TYPE_UINT64:
  750. case ProtoBufType.TYPE_SINT32:
  751. case ProtoBufType.TYPE_SINT64:
  752. case ProtoBufType.TYPE_FLOAT:
  753. case ProtoBufType.TYPE_DOUBLE:
  754. return;
  755. }
  756. } else if (object instanceof byte[]){
  757. switch (tagType){
  758. case WIRETYPE_LENGTH_DELIMITED:
  759. case ProtoBufType.TYPE_DATA:
  760. case ProtoBufType.TYPE_MESSAGE:
  761. case ProtoBufType.TYPE_TEXT:
  762. case ProtoBufType.TYPE_BYTES:
  763. return;
  764. }
  765. } else if (object instanceof ProtoBuf) {
  766. switch (tagType){
  767. case WIRETYPE_LENGTH_DELIMITED:
  768. case WIRETYPE_START_GROUP:
  769. case ProtoBufType.TYPE_DATA:
  770. case ProtoBufType.TYPE_GROUP:
  771. case ProtoBufType.TYPE_MESSAGE:
  772. if (msgType == null || msgType.getData(tag) == null ||
  773. ((ProtoBuf) object).msgType == null ||
  774. ((ProtoBuf) object).msgType == msgType.getData(tag)) {
  775. return;
  776. }
  777. }
  778. } else if (object instanceof String){
  779. switch (tagType){
  780. case WIRETYPE_LENGTH_DELIMITED:
  781. case ProtoBufType.TYPE_DATA:
  782. case ProtoBufType.TYPE_TEXT:
  783. case ProtoBufType.TYPE_STRING:
  784. return;
  785. }
  786. }
  787. throw new IllegalArgumentException(MSG_MISMATCH + " type:" + msgType +
  788. " tag:" + tag);
  789. }
  790. /**
  791. * Returns the default value for the given tag.
  792. */
  793. private Object getDefault(int tag){
  794. switch(getType(tag)){
  795. case ProtoBufType.TYPE_UNDEFINED:
  796. case ProtoBufType.TYPE_GROUP:
  797. case ProtoBufType.TYPE_MESSAGE:
  798. return null;
  799. default:
  800. return msgType.getData(tag);
  801. }
  802. }
  803. /**
  804. * Returns the indicated value converted to the given type.
  805. *
  806. * @throws ArrayIndexOutOfBoundsException for invalid tags and indices
  807. * @throws IllegalArgumentException if count is greater than one.
  808. */
  809. private Object getObject(int tag, int desiredType) {
  810. int count = getCount(tag);
  811. if (count == 0){
  812. return getDefault(tag);
  813. }
  814. if (count > 1){
  815. throw new IllegalArgumentException();
  816. }
  817. return getObject(tag, 0, desiredType);
  818. }
  819. /**
  820. * Returns the indicated value converted to the given type.
  821. *
  822. * @throws ArrayIndexOutOfBoundsException for invalid tags and indices
  823. */
  824. private Object getObject(int tag, int index, int desiredType) {
  825. if (index >= getCount(tag)) {
  826. throw new ArrayIndexOutOfBoundsException();
  827. }
  828. Object o = values.elementAt(tag);
  829. Vector v = null;
  830. if (o instanceof Vector) {
  831. v = (Vector) o;
  832. o = v.elementAt(index);
  833. }
  834. Object o2 = convert(o, desiredType);
  835. if (o2 != o && o != null) {
  836. if (v == null){
  837. setObject(tag, o2);
  838. } else {
  839. v.setElementAt(o2, index);
  840. }
  841. }
  842. return o2;
  843. }
  844. /**
  845. * Returns the wire type for the given tag. Calls getType() internally,
  846. * so a wire type should be found for all non-empty tags, even if no
  847. * message type is set and the tag was not previously read.
  848. */
  849. private final int getWireType(int tag) {
  850. int tagType = getType(tag);
  851. switch (tagType) {
  852. case WIRETYPE_VARINT:
  853. case WIRETYPE_FIXED32:
  854. case WIRETYPE_FIXED64:
  855. case WIRETYPE_LENGTH_DELIMITED:
  856. case WIRETYPE_START_GROUP:
  857. case ProtoBufType.TYPE_UNDEFINED:
  858. return tagType;
  859. case ProtoBufType.TYPE_BOOL:
  860. case ProtoBufType.TYPE_INT32:
  861. case ProtoBufType.TYPE_INT64:
  862. case ProtoBufType.TYPE_UINT32:
  863. case ProtoBufType.TYPE_UINT64:
  864. case ProtoBufType.TYPE_SINT32:
  865. case ProtoBufType.TYPE_SINT64:
  866. case ProtoBufType.TYPE_ENUM:
  867. return WIRETYPE_VARINT;
  868. case ProtoBufType.TYPE_DATA:
  869. case ProtoBufType.TYPE_MESSAGE:
  870. case ProtoBufType.TYPE_TEXT:
  871. case ProtoBufType.TYPE_BYTES:
  872. case ProtoBufType.TYPE_STRING:
  873. return WIRETYPE_LENGTH_DELIMITED;
  874. case ProtoBufType.TYPE_DOUBLE:
  875. case ProtoBufType.TYPE_FIXED64:
  876. case ProtoBufType.TYPE_SFIXED64:
  877. return WIRETYPE_FIXED64;
  878. case ProtoBufType.TYPE_FLOAT:
  879. case ProtoBufType.TYPE_FIXED32:
  880. case ProtoBufType.TYPE_SFIXED32:
  881. return WIRETYPE_FIXED32;
  882. case ProtoBufType.TYPE_GROUP:
  883. return WIRETYPE_START_GROUP;
  884. default:
  885. throw new RuntimeException(MSG_UNSUPPORTED + ':' + msgType + '/' +
  886. tag + '/' + tagType);
  887. }
  888. }
  889. /**
  890. * Inserts a value.
  891. */
  892. private void insertObject(int tag, int index, Object o) {
  893. assertTypeMatch(tag, o);
  894. int count = getCount(tag);
  895. if (count == 0) {
  896. setObject(tag, o);
  897. } else {
  898. Object curr = values.elementAt(tag);
  899. Vector v;
  900. if (curr instanceof Vector) {
  901. v = (Vector) curr;
  902. } else {
  903. v = new Vector();
  904. v.addElement(curr);
  905. values.setElementAt(v, tag);
  906. }
  907. v.insertElementAt(o, index);
  908. }
  909. }
  910. /**
  911. * Converts the object if a better suited class exists for the given .proto
  912. * type. If the formats are not compatible, an exception is thrown.
  913. */
  914. private Object convert(Object obj, int tagType) {
  915. switch (tagType) {
  916. case ProtoBufType.TYPE_UNDEFINED:
  917. return obj;
  918. case ProtoBufType.TYPE_BOOL:
  919. if (obj instanceof Boolean) {
  920. return obj;
  921. }
  922. switch ((int) ((Long) obj).longValue()) {
  923. case 0:
  924. return FALSE;
  925. case 1:
  926. return TRUE;
  927. default:
  928. throw new IllegalArgumentException(MSG_MISMATCH);
  929. }
  930. case ProtoBufType.TYPE_FIXED32:
  931. case ProtoBufType.TYPE_FIXED64:
  932. case ProtoBufType.TYPE_INT32:
  933. case ProtoBufType.TYPE_INT64:
  934. case ProtoBufType.TYPE_SFIXED32:
  935. case ProtoBufType.TYPE_SFIXED64:
  936. case ProtoBufType.TYPE_SINT32:
  937. case ProtoBufType.TYPE_SINT64:
  938. if (obj instanceof Boolean) {
  939. return SMALL_NUMBERS[((Boolean) obj).booleanValue() ? 1 : 0];
  940. }
  941. return obj;
  942. case ProtoBufType.TYPE_DATA:
  943. case ProtoBufType.TYPE_BYTES:
  944. if (obj instanceof String) {
  945. return encodeUtf8((String) obj);
  946. } else if (obj instanceof ProtoBuf) {
  947. ByteArrayOutputStream buf = new ByteArrayOutputStream();
  948. try {
  949. ((ProtoBuf) obj).outputTo(buf);
  950. return buf.toByteArray();
  951. } catch (IOException e) {
  952. throw new RuntimeException(e.toString());
  953. }
  954. }
  955. return obj;
  956. case ProtoBufType.TYPE_TEXT:
  957. case ProtoBufType.TYPE_STRING:
  958. if (obj instanceof byte[]) {
  959. byte[] data = (byte[]) obj;
  960. return decodeUtf8(data, 0, data.length, true);
  961. }
  962. return obj;
  963. case ProtoBufType.TYPE_GROUP:
  964. case ProtoBufType.TYPE_MESSAGE:
  965. if (obj instanceof byte[]) {
  966. try {
  967. return new ProtoBuf(null).parse((byte[]) obj);
  968. } catch (IOException e) {
  969. throw new RuntimeException(e.toString());
  970. }
  971. }
  972. return obj;
  973. default:
  974. // default includes FLOAT and DOUBLE
  975. throw new RuntimeException(MSG_UNSUPPORTED);
  976. }
  977. }
  978. /**
  979. * Reads a variable-size integer (up to 10 bytes for 64 bit) from the
  980. * given input stream.
  981. *
  982. * @param is the stream to read from
  983. * @param permitEOF if true, -1 is returned when EOF is reached instead of
  984. * throwing an IOException
  985. * @return the integer value read from the stream, or -1 if EOF is
  986. * reached and permitEOF is true
  987. * @throws IOException thrown for underlying IO issues and if EOF
  988. * is reached and permitEOF is false
  989. */
  990. static long readVarInt(InputStream is, boolean permitEOF) throws IOException {
  991. long result = 0;
  992. int shift = 0;
  993. // max 10 byte wire format for 64 bit integer (7 bit data per byte)
  994. for (int i = 0; i < VARINT_MAX_BYTES; i++) {
  995. int in = is.read();
  996. if (in == -1) {
  997. if (i == 0 && permitEOF) {
  998. return -1;
  999. } else {
  1000. throw new IOException("EOF");
  1001. }
  1002. }
  1003. result |= ((long) (in & 0x07f)) << shift;
  1004. if ((in & 0x80) == 0){
  1005. break; // get out early
  1006. }
  1007. shift += 7;
  1008. }
  1009. return result;
  1010. }
  1011. /**
  1012. * Internal helper method to set a (single) value. Overwrites all existing
  1013. * values.
  1014. */
  1015. private void setObject(int tag, Object o) {
  1016. if (values.size() <= tag) {
  1017. values.setSize(tag + 1);
  1018. }
  1019. if (o != null) {
  1020. assertTypeMatch(tag, o);
  1021. }
  1022. values.setElementAt(o, tag);
  1023. }
  1024. /**
  1025. * Write a variable-size integer to the given output stream.
  1026. */
  1027. static void writeVarInt(OutputStream os, long value) throws IOException {
  1028. for (int i = 0; i < VARINT_MAX_BYTES; i++) {
  1029. int toWrite = (int) (value & 0x7f);
  1030. value >>>= 7;
  1031. if (value == 0) {
  1032. os.write(toWrite);
  1033. break;
  1034. } else {
  1035. os.write(toWrite | 0x080);
  1036. }
  1037. }
  1038. }
  1039. /**
  1040. * Returns a byte array containing the given string, encoded as UTF-8. The
  1041. * returned byte array contains at least s.length() bytes and at most
  1042. * 4 * s.length() bytes. UTF-16 surrogates are transcoded to UTF-8.
  1043. *
  1044. * @param s input string to be encoded
  1045. * @return UTF-8 encoded input string
  1046. */
  1047. static byte[] encodeUtf8(String s) {
  1048. int len = encodeUtf8(s, null, 0);
  1049. byte[] result = new byte[len];
  1050. encodeUtf8(s, result, 0);
  1051. return result;
  1052. }
  1053. /**
  1054. * Encodes the given string to UTF-8 in the given buffer or calculates
  1055. * the space needed if the buffer is null.
  1056. *
  1057. * @param s the string to be UTF-8 encoded
  1058. * @param buf byte array to write to
  1059. * @return new buffer position after writing (which equals the required size
  1060. * if pos is 0)
  1061. */
  1062. static int encodeUtf8(String s, byte[] buf, int pos){
  1063. int len = s.length();
  1064. for (int i = 0; i < len; i++){
  1065. int code = s.charAt(i);
  1066. // surrogate 0xd800 .. 0xdfff?
  1067. if (code >= 0x0d800 && code <= 0x0dfff && i + 1 < len){
  1068. int codeLo = s.charAt(i + 1);
  1069. // 0xfc00 is the surrogate id mask (first six bit of 16 set)
  1070. // 0x03ff is the surrogate data mask (remaining 10 bit)
  1071. // check if actually a surrogate pair (d800 ^ dc00 == 0400)
  1072. if (((codeLo & 0xfc00) ^ (code & 0x0fc00)) == 0x0400){
  1073. i += 1;
  1074. int codeHi;
  1075. if ((codeLo & 0xfc00) == 0x0d800){
  1076. codeHi = codeLo;
  1077. codeLo = code;
  1078. } else {
  1079. codeHi = code;
  1080. }
  1081. code = (((codeHi & 0x3ff) << 10) | (codeLo & 0x3ff)) + 0x10000;
  1082. }
  1083. }
  1084. if (code <= 0x007f) {
  1085. if (buf != null){
  1086. buf[pos] = (byte) code;
  1087. }
  1088. pos += 1;
  1089. } else if (code <= 0x07FF) {
  1090. // non-ASCII <= 0x7FF
  1091. if (buf != null){
  1092. buf[pos] = (byte) (0xc0 | (code >> 6));
  1093. buf[pos + 1] = (byte) (0x80 | (code & 0x3F));
  1094. }
  1095. pos += 2;
  1096. } else if (code <= 0xFFFF){
  1097. // 0x7FF < code <= 0xFFFF
  1098. if (buf != null){
  1099. buf[pos] = (byte) ((0xe0 | (code >> 12)));
  1100. buf[pos + 1] = (byte) ((0x80 | ((code >> 6) & 0x3F)));
  1101. buf[pos + 2] = (byte) ((0x80 | (code & 0x3F)));
  1102. }
  1103. pos += 3;
  1104. } else {
  1105. if (buf != null){
  1106. buf[pos] = (byte) ((0xf0 | (code >> 18)));
  1107. buf[pos + 1] = (byte) ((0x80 | ((code >> 12) & 0x3F)));
  1108. buf[pos + 2] = (byte) ((0x80 | ((code >> 6) & 0x3F)));
  1109. buf[pos + 3] = (byte) ((0x80 | (code & 0x3F)));
  1110. }
  1111. pos += 4;
  1112. }
  1113. }
  1114. return pos;
  1115. }
  1116. /**
  1117. * Decodes an array of UTF-8 bytes to a Java string (UTF-16). The tolerant
  1118. * flag determines what to do in case of illegal or unsupported sequences.
  1119. *
  1120. * @param data input byte array containing UTF-8 data
  1121. * @param start decoding start position in byte array
  1122. * @param end decoding end position in byte array
  1123. * @param tolerant if true, an IllegalArgumentException is thrown for illegal
  1124. * UTF-8 codes
  1125. * @return the string containing the UTF-8 decoding result
  1126. */
  1127. static String decodeUtf8(byte[] data, int start, int end,
  1128. boolean tolerant){
  1129. StringBuffer sb = new StringBuffer(end - start);
  1130. int pos = start;
  1131. while (pos < end){
  1132. int b = data[pos++] & 0x0ff;
  1133. if (b <= 0x7f){
  1134. sb.append((char) b);
  1135. } else if (b >= 0xf5){ // byte sequence too long
  1136. if (!tolerant){
  1137. throw new IllegalArgumentException("Invalid UTF8");
  1138. }
  1139. sb.append((char) b);
  1140. } else {
  1141. int border = 0xe0;
  1142. int count = 1;
  1143. int minCode = 128;
  1144. int mask = 0x01f;
  1145. while (b >= border){
  1146. border = (border >> 1) | 0x80;
  1147. minCode = minCode << (count == 1 ? 4 : 5);
  1148. count++;
  1149. mask = mask >> 1;
  1150. }
  1151. int code = b & mask;
  1152. for (int i = 0; i < count; i++){
  1153. code = code << 6;
  1154. if (pos >= end){
  1155. if (!tolerant){
  1156. throw new IllegalArgumentException("Invalid UTF8");
  1157. }
  1158. // otherwise, assume zeroes
  1159. } else {
  1160. if (!tolerant && (data[pos] & 0xc0) != 0x80){
  1161. throw new IllegalArgumentException("Invalid UTF8");
  1162. }
  1163. code |= (data[pos++] & 0x3f); // six bit
  1164. }
  1165. }
  1166. // illegal code or surrogate code
  1167. if (!tolerant && code < minCode || (code >= 0xd800 && code <= 0xdfff)){
  1168. throw new IllegalArgumentException("Invalid UTF8");
  1169. }
  1170. if (code <= 0x0ffff){
  1171. sb.append((char) code);
  1172. } else { // surrogate UTF16
  1173. code -= 0x10000;
  1174. sb.append((char) (0xd800 | (code >> 10))); // high 10 bit
  1175. sb.append((char) (0xdc00 | (code & 0x3ff))); // low 10 bit
  1176. }
  1177. }
  1178. }
  1179. return sb.toString();
  1180. }
  1181. }