Initial Contribution
diff --git a/froofle/protobuf/internal/encoder.py b/froofle/protobuf/internal/encoder.py
new file mode 100644
index 0000000..8b924b3
--- /dev/null
+++ b/froofle/protobuf/internal/encoder.py
@@ -0,0 +1,206 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# http://code.google.com/p/protobuf/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Class for encoding protocol message primitives.
+
+Contains the logic for encoding every logical protocol field type
+into one of the 5 physical wire types.
+"""
+
+__author__ = 'robinson@google.com (Will Robinson)'
+
+import struct
+from froofle.protobuf import message
+from froofle.protobuf.internal import wire_format
+from froofle.protobuf.internal import output_stream
+
+
+# Note that much of this code is ported from //net/proto/ProtocolBuffer, and
+# that the interface is strongly inspired by WireFormat from the C++ proto2
+# implementation.
+
+
+class Encoder(object):
+
+  """Encodes logical protocol buffer fields to the wire format."""
+
+  def __init__(self):
+    self._stream = output_stream.OutputStream()
+
+  def ToString(self):
+    """Returns all values encoded in this object as a string."""
+    return self._stream.ToString()
+
+  # All the Append*() methods below first append a tag+type pair to the buffer
+  # before appending the specified value.
+
+  def AppendInt32(self, field_number, value):
+    """Appends a 32-bit integer to our buffer, varint-encoded."""
+    self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
+    self._stream.AppendVarint32(value)
+
+  def AppendInt64(self, field_number, value):
+    """Appends a 64-bit integer to our buffer, varint-encoded."""
+    self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
+    self._stream.AppendVarint64(value)
+
+  def AppendUInt32(self, field_number, unsigned_value):
+    """Appends an unsigned 32-bit integer to our buffer, varint-encoded."""
+    self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
+    self._stream.AppendVarUInt32(unsigned_value)
+
+  def AppendUInt64(self, field_number, unsigned_value):
+    """Appends an unsigned 64-bit integer to our buffer, varint-encoded."""
+    self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
+    self._stream.AppendVarUInt64(unsigned_value)
+
+  def AppendSInt32(self, field_number, value):
+    """Appends a 32-bit integer to our buffer, zigzag-encoded and then
+    varint-encoded.
+    """
+    self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
+    zigzag_value = wire_format.ZigZagEncode(value)
+    self._stream.AppendVarUInt32(zigzag_value)
+
+  def AppendSInt64(self, field_number, value):
+    """Appends a 64-bit integer to our buffer, zigzag-encoded and then
+    varint-encoded.
+    """
+    self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
+    zigzag_value = wire_format.ZigZagEncode(value)
+    self._stream.AppendVarUInt64(zigzag_value)
+
+  def AppendFixed32(self, field_number, unsigned_value):
+    """Appends an unsigned 32-bit integer to our buffer, in little-endian
+    byte-order.
+    """
+    self._AppendTag(field_number, wire_format.WIRETYPE_FIXED32)
+    self._stream.AppendLittleEndian32(unsigned_value)
+
+  def AppendFixed64(self, field_number, unsigned_value):
+    """Appends an unsigned 64-bit integer to our buffer, in little-endian
+    byte-order.
+    """
+    self._AppendTag(field_number, wire_format.WIRETYPE_FIXED64)
+    self._stream.AppendLittleEndian64(unsigned_value)
+
+  def AppendSFixed32(self, field_number, value):
+    """Appends a signed 32-bit integer to our buffer, in little-endian
+    byte-order.
+    """
+    sign = (value & 0x80000000) and -1 or 0
+    if value >> 32 != sign:
+      raise message.EncodeError('SFixed32 out of range: %d' % value)
+    self._AppendTag(field_number, wire_format.WIRETYPE_FIXED32)
+    self._stream.AppendLittleEndian32(value & 0xffffffff)
+
+  def AppendSFixed64(self, field_number, value):
+    """Appends a signed 64-bit integer to our buffer, in little-endian
+    byte-order.
+    """
+    sign = (value & 0x8000000000000000) and -1 or 0
+    if value >> 64 != sign:
+      raise message.EncodeError('SFixed64 out of range: %d' % value)
+    self._AppendTag(field_number, wire_format.WIRETYPE_FIXED64)
+    self._stream.AppendLittleEndian64(value & 0xffffffffffffffff)
+
+  def AppendFloat(self, field_number, value):
+    """Appends a floating-point number to our buffer."""
+    self._AppendTag(field_number, wire_format.WIRETYPE_FIXED32)
+    self._stream.AppendRawBytes(struct.pack('f', value))
+
+  def AppendDouble(self, field_number, value):
+    """Appends a double-precision floating-point number to our buffer."""
+    self._AppendTag(field_number, wire_format.WIRETYPE_FIXED64)
+    self._stream.AppendRawBytes(struct.pack('d', value))
+
+  def AppendBool(self, field_number, value):
+    """Appends a boolean to our buffer."""
+    self.AppendInt32(field_number, value)
+
+  def AppendEnum(self, field_number, value):
+    """Appends an enum value to our buffer."""
+    self.AppendInt32(field_number, value)
+
+  def AppendString(self, field_number, value):
+    """Appends a length-prefixed unicode string, encoded as UTF-8 to our buffer,
+    with the length varint-encoded.
+    """
+    self.AppendBytes(field_number, value.encode('utf-8'))
+
+  def AppendBytes(self, field_number, value):
+    """Appends a length-prefixed sequence of bytes to our buffer, with the
+    length varint-encoded.
+    """
+    self._AppendTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
+    self._stream.AppendVarUInt32(len(value))
+    self._stream.AppendRawBytes(value)
+
+  # TODO(robinson): For AppendGroup() and AppendMessage(), we'd really like to
+  # avoid the extra string copy here.  We can do so if we widen the Message
+  # interface to be able to serialize to a stream in addition to a string.  The
+  # challenge when thinking ahead to the Python/C API implementation of Message
+  # is finding a stream-like Python thing to which we can write raw bytes
+  # from C.  I'm not sure such a thing exists(?).  (array.array is pretty much
+  # what we want, but it's not directly exposed in the Python/C API).
+
+  def AppendGroup(self, field_number, group):
+    """Appends a group to our buffer.
+    """
+    self._AppendTag(field_number, wire_format.WIRETYPE_START_GROUP)
+    self._stream.AppendRawBytes(group.SerializeToString())
+    self._AppendTag(field_number, wire_format.WIRETYPE_END_GROUP)
+
+  def AppendMessage(self, field_number, msg):
+    """Appends a nested message to our buffer.
+    """
+    self._AppendTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
+    self._stream.AppendVarUInt32(msg.ByteSize())
+    self._stream.AppendRawBytes(msg.SerializeToString())
+
+  def AppendMessageSetItem(self, field_number, msg):
+    """Appends an item using the message set wire format.
+
+    The message set message looks like this:
+      message MessageSet {
+        repeated group Item = 1 {
+          required int32 type_id = 2;
+          required string message = 3;
+        }
+      }
+    """
+    self._AppendTag(1, wire_format.WIRETYPE_START_GROUP)
+    self.AppendInt32(2, field_number)
+    self.AppendMessage(3, msg)
+    self._AppendTag(1, wire_format.WIRETYPE_END_GROUP)
+
+  def _AppendTag(self, field_number, wire_type):
+    """Appends a tag containing field number and wire type information."""
+    self._stream.AppendVarUInt32(wire_format.PackTag(field_number, wire_type))