def ResetForPack(self): """Reset offset/size fields so that packing can be done again""" self.Detail('ResetForPack: offset %s->%s, size %s->%s' % (to_hex(self.offset), to_hex(self.orig_offset), to_hex(self.size), to_hex(self.orig_size))) self.pre_reset_size = self.size self.offset = self.orig_offset self.size = self.orig_size
def Pack(self, offset): """Figure out how to pack the entry into the section Most of the time the entries are not fully specified. There may be an alignment but no size. In that case we take the size from the contents of the entry. If an entry has no hard-coded offset, it will be placed at @offset. Once this function is complete, both the offset and size of the entry will be know. Args: Current section offset pointer Returns: New section offset pointer (after this entry) """ self.Detail( 'Packing: offset=%s, size=%s, content_size=%x' % (to_hex(self.offset), to_hex(self.size), self.contents_size)) if self.offset is None: if self.offset_unset: self.Raise('No offset set with offset-unset: should another ' 'entry provide this correct offset?') self.offset = tools.align(offset, self.align) needed = self.pad_before + self.contents_size + self.pad_after needed = tools.align(needed, self.align_size) size = self.size if not size: size = needed new_offset = self.offset + size aligned_offset = tools.align(new_offset, self.align_end) if aligned_offset != new_offset: size = aligned_offset - self.offset new_offset = aligned_offset if not self.size: self.size = size if self.size < needed: self.Raise("Entry contents size is %#x (%d) but entry size is " "%#x (%d)" % (needed, needed, self.size, self.size)) # Check that the alignment is correct. It could be wrong if the # and offset or size values were provided (i.e. not calculated), but # conflict with the provided alignment values if self.size != tools.align(self.size, self.align_size): self.Raise( "Size %#x (%d) does not match align-size %#x (%d)" % (self.size, self.size, self.align_size, self.align_size)) if self.offset != tools.align(self.offset, self.align): self.Raise("Offset %#x (%d) does not match align %#x (%d)" % (self.offset, self.offset, self.align, self.align)) self.Detail( ' - packed: offset=%#x, size=%#x, content_size=%#x, next_offset=%x' % (self.offset, self.size, self.contents_size, new_offset)) return new_offset
def ProcessContentsUpdate(self, data): """Update the contents of an entry, after the size is fixed This checks that the new data is the same size as the old. If the size has changed, this triggers a re-run of the packing algorithm. Args: data: Data to set to the contents (bytes) Raises: ValueError if the new data size is not the same as the old """ size_ok = True new_size = len(data) if state.AllowEntryExpansion() and new_size > self.contents_size: # self.data will indicate the new size needed size_ok = False elif state.AllowEntryContraction() and new_size < self.contents_size: size_ok = False # If not allowed to change, try to deal with it or give up if size_ok: if new_size > self.contents_size: self.Raise('Cannot update entry size from %d to %d' % (self.contents_size, new_size)) # Don't let the data shrink. Pad it if necessary if size_ok and new_size < self.contents_size: data += tools.get_bytes(0, self.contents_size - new_size) if not size_ok: tout.debug("Entry '%s' size change from %s to %s" % (self._node.path, to_hex( self.contents_size), to_hex(new_size))) self.SetContents(data) return size_ok