Commits

Christoph Schindler committed fe75087

Return encoded data instead of directly writing to file.

  • Participants
  • Parent commits 1511142

Comments (0)

Files changed (1)

File plist/encoder.py

         """Serialize ``obj`` as a Property List formatted stream to ``fp`` (a
         file-like object).
         """
-        self.write_header()
-        self.write_object_table(obj)
-        self.write_offset_table()
-        self.write_trailer()
+        self.write(self.enc_header())
+        self.write(self.enc_object_table(obj))
+        self.write(self.enc_offset_table())
+        self.write(self.enc_trailer())
 
-    def write_header(self):
-        self.write('bplist')
-        self.write('00')
+    def enc_header(self):
         self.offset_table_offset += 8
+        magic_number = 'bplist'
+        version = '00'
+        return magic_number + version
 
-    def write_object_table(self, obj):
+    def enc_object_table(self, obj):
         t = type(obj)
         f = self.dispatch.get(t)
 
         self.offset_table.append(self.offset_table_offset)
 
         if f:
-            f(self, obj) # unbound method
-            return
+            return f(self, obj) # unbound method
 
         raise TypeError("Don't know how to encode %s object" % t)
 
-    def write_offset_table(self):
+    def enc_offset_table(self):
         for offset in self.offset_table:
             ref = struct.pack('B', offset)
-            self.write(ref)
+            return ref
 
-    def write_trailer(self):
+    def enc_trailer(self):
         trailer = struct.pack('!xxxxxxBBQQQ', self.offset_size, self.ref_size,
                               len(self.offset_table), self.top_level_object,
                               self.offset_table_offset)
-        self.write(trailer)
+        return trailer
 
     # Methods below are dispatched through the dispatch table
 
     dispatch = {}
 
-    def write_simple(self, payload):
-        self.write(struct.pack('>B', M_SIMPLE | payload))
+    def enc_simple(self, payload):
         self.offset_table_offset += 1
+        return struct.pack('>B', M_SIMPLE | payload)
 
-    def write_none(self, obj):
+    def enc_none(self, obj):
         # Null values seem to be supported by the binary format but not by
         # the xml format - at least plutil -lint doesn't complain.
         payload = M_NULL
-        self.write_simple(payload)
-    dispatch[NoneType] = write_none
+        return self.enc_simple(payload)
+    dispatch[NoneType] = enc_none
 
-    def write_bool(self, obj):
+    def enc_bool(self, obj):
         payload = M_TRUE if obj else M_FALSE
-        self.write_simple(payload)
-    dispatch[BooleanType] = write_bool
+        return self.enc_simple(payload)
+    dispatch[BooleanType] = enc_bool
 
-    def write_int(self, obj):
+    def enc_int(self, obj):
         # CFBinaryPlist.c:
         # in format version '00', 1, 2, and 4-byte integers have to be
         # interpreted as unsigned, whereas 8-byte integers are signed (and
         else:
             raise ValueError("int too big.")
 
-        self.write(struct.pack('>B%s' % type, M_INT | size, obj))
         self.offset_table_offset += 1 + 2**size
-    dispatch[IntType] = write_int
+        return struct.pack('>B%s' % type, M_INT | size, obj)
+    dispatch[IntType] = enc_int
 
-    def write_float(self, obj):
+    def enc_float(self, obj):
         size = 3
-        self.write(struct.pack('>Bd', M_REAL | size, obj))
         self.offset_table_offset += 1 + 2**size
-    dispatch[FloatType] = write_float
+        return struct.pack('>Bd', M_REAL | size, obj)
+    dispatch[FloatType] = enc_float
 
-    def write_date(self, obj):
+    def enc_date(self, obj):
         # convert to naive datetime object so we can subtract
         if obj.tzinfo:
             obj = obj.replace(tzinfo=None) - obj.utcoffset()
         seconds = timedelta.total_seconds()
 
         size = 3
-        self.write(struct.pack('>Bd', M_DATE | size, seconds))
         self.offset_table_offset += 1 + 2**size
-    dispatch[datetime.datetime] = write_date
+        return struct.pack('>Bd', M_DATE | size, seconds)
+    dispatch[datetime.datetime] = enc_date
 
-    def write_object_with_count(self, marker, count, payload):
+    def enc_object_with_count(self, marker, count, payload):
         # common structure for most types
         if count > 14:
-            self.write(struct.pack('>B', marker | 0x0f))
-            self.write_int(count)
+            wrapper = struct.pack('>B', marker | 0x0f)
+            wrapper += self.enc_int(count)
         else:
-            self.write(struct.pack('>B', marker | count))
-        self.write(payload)
+            wrapper = struct.pack('>B', marker | count)
         self.offset_table_offset += 1 + len(payload)
+        return wrapper + payload
 
-    def write_string(self, obj):
+    def enc_string(self, obj):
         count = len(obj)
         payload = obj
-        self.write_object_with_count(M_STRING, count, payload)
-    dispatch[StringType] = write_string
+        return self.enc_object_with_count(M_STRING, count, payload)
+    dispatch[StringType] = enc_string
 
-    def write_unicode(self, obj):
+    def enc_unicode(self, obj):
         count = len(obj)
         payload = obj.encode('UTF-16BE', 'strict')
-        self.write_object_with_count(M_USTRING, count, payload)
-    dispatch[UnicodeType] = write_unicode
+        return self.enc_object_with_count(M_USTRING, count, payload)
+    dispatch[UnicodeType] = enc_unicode
 
-    def write_list(self, obj):
+    def enc_list(self, obj):
         count = 0
         payload = ''
-        self.write_object_with_count(M_ARRAY, count, payload)
-    dispatch[ListType] = write_list
+        return self.enc_object_with_count(M_ARRAY, count, payload)
+    dispatch[ListType] = enc_list
 
-    def write_dict(self, obj):
+    def enc_dict(self, obj):
         count = 0
         payload = ''
-        self.write_object_with_count(M_DICT, count, payload)
-    dispatch[DictType] = write_dict
+        return self.enc_object_with_count(M_DICT, count, payload)
+    dispatch[DictType] = enc_dict