• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2007 Google Inc.
2 // All Rights Reserved.
3 
4 package com.google.common.io.protocol;
5 
6 import java.util.*;
7 
8 /**
9  * This class can be used to create a memory model of a .proto file. Currently,
10  * it is assumed that tags ids are not large. This could be improved by storing
11  * a start offset, relaxing the assumption to a dense number space.
12  */
13 public class ProtoBufType {
14   // Note: Values 0..15 are reserved for wire types!
15   public static final int TYPE_UNDEFINED = 16;
16   public static final int TYPE_DOUBLE = 17;
17   public static final int TYPE_FLOAT = 18;
18   public static final int TYPE_INT64 = 19;
19   public static final int TYPE_UINT64 = 20;
20   public static final int TYPE_INT32 = 21;
21   public static final int TYPE_FIXED64 = 22;
22   public static final int TYPE_FIXED32 = 23;
23   public static final int TYPE_BOOL = 24;
24   public static final int TYPE_DATA = 25;
25   public static final int TYPE_GROUP = 26;
26   public static final int TYPE_MESSAGE = 27;
27   public static final int TYPE_TEXT = 28;
28   public static final int TYPE_UINT32 = 29;
29   public static final int TYPE_ENUM = 30;
30   public static final int TYPE_SFIXED32 = 31;
31   public static final int TYPE_SFIXED64 = 32;
32 
33   // new protobuf 2 types
34   public static final int TYPE_SINT32 = 33;
35   public static final int TYPE_SINT64 = 34;
36   public static final int TYPE_BYTES = 35;
37   public static final int TYPE_STRING = 36;
38 
39   public static final int MASK_TYPE = 0x0ff;
40   public static final int MASK_MODIFIER = 0x0ff00;
41 
42   public static final int REQUIRED = 0x100;
43   public static final int OPTIONAL = 0x200;
44   public static final int REPEATED = 0x400;
45 
46   private final StringBuffer types = new StringBuffer();
47   private final Vector data = new Vector();
48   private final String typeName;
49 
50   /**
51    * Empty constructor.
52    */
ProtoBufType()53   public ProtoBufType() {
54     typeName = null;
55   }
56 
57   /**
58    * Constructor including a type name for debugging purposes.
59    */
ProtoBufType(String typeName)60   public ProtoBufType(String typeName) {
61     this.typeName = typeName;
62   }
63 
64   /**
65    * Adds a tag description. The data parameter contains the group definition
66    * for group elements and the default value for regular elements.
67    *
68    * @param optionsAndType any legal combination (bitwise or) of REQUIRED
69    *                       or OPTIONAL and REPEATED and one of the TYPE_
70    *                       constants
71    * @param tag            the tag id
72    * @param data           the type for group elements (or the default value for
73    *                       regular elements in future versions)
74    * @return               this is returned to permit cascading
75    */
addElement(int optionsAndType, int tag, Object data)76   public ProtoBufType addElement(int optionsAndType, int tag, Object data) {
77     while (types.length() <= tag) {
78       types.append((char) TYPE_UNDEFINED);
79       this.data.addElement(null);
80     }
81     types.setCharAt(tag, (char) optionsAndType);
82     this.data.setElementAt(data, tag);
83 
84     return this;
85   }
86 
87   /**
88    * Returns the type for the given tag id (without modifiers such as OPTIONAL,
89    * REPEATED). For undefined tags, TYPE_UNDEFINED is returned.
90    */
getType(int tag)91   public int getType(int tag) {
92     return (tag < 0 || tag >= types.length())
93         ? TYPE_UNDEFINED
94         : (types.charAt(tag) & MASK_TYPE);
95   }
96 
97   /**
98    * Returns a bit combination of the modifiers for the given tag id
99    * (OPTIONAL, REPEATED, REQUIRED). For undefined tags, OPTIONAL|REPEATED
100    * is returned.
101    */
getModifiers(int tag)102   public int getModifiers(int tag) {
103     return (tag < 0 || tag >= types.length())
104         ? (OPTIONAL | REPEATED)
105         : (types.charAt(tag) & MASK_MODIFIER);
106   }
107 
108   /**
109    * Returns the data associated to a given tag (either the default value for
110    * regular elements or a ProtoBufType for groups and messages). For undefined
111    * tags, null is returned.
112    */
getData(int tag)113   public Object getData(int tag) {
114     return (tag < 0 || tag >= data.size()) ? null : data.elementAt(tag);
115   }
116 
117   /**
118    * Returns the type name set in the constructor for debugging purposes.
119    */
toString()120   public String toString() {
121     return typeName;
122   }
123 
124   /**
125    * {@inheritDoc}
126    * <p>Two ProtoBufTypes are equals if the fields types are the same.
127    */
equals(Object object)128   public boolean equals(Object object) {
129     if (null == object) {
130       // trivial check
131       return false;
132     } else if (this == object) {
133       // trivial check
134       return true;
135     } else if (this.getClass() != object.getClass()) {
136       // different class
137       return false;
138     }
139     ProtoBufType other = (ProtoBufType) object;
140 
141     return stringEquals(types, other.types);
142   }
143 
144   /**
145    * {@inheritDoc}
146    */
hashCode()147   public int hashCode() {
148     if (types != null) {
149       return types.hashCode();
150     } else {
151       return super.hashCode();
152     }
153   }
154 
stringEquals(CharSequence a, CharSequence b)155   public static boolean stringEquals(CharSequence a, CharSequence b) {
156     if (a == b) return true;
157     int length;
158     if (a != null && b != null && (length = a.length()) == b.length()) {
159       if (a instanceof String && b instanceof String) {
160         return a.equals(b);
161       } else {
162         for (int i = 0; i < length; i++) {
163           if (a.charAt(i) != b.charAt(i)) return false;
164         }
165         return true;
166       }
167     }
168     return false;
169   }
170 }
171