1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2016 Google, Inc
4 # Base class for all entries
7 from collections import namedtuple
12 from dtoc import fdt_util
13 from patman import tools
14 from patman.tools import ToHex, ToHexSize
15 from patman import tout
20 # An argument which can be passed to entries on the command line, in lieu of
21 # device-tree properties.
22 EntryArg = namedtuple('EntryArg', ['name', 'datatype'])
24 # Information about an entry for use when displaying summaries
25 EntryInfo = namedtuple('EntryInfo', ['indent', 'name', 'etype', 'size',
26 'image_pos', 'uncomp_size', 'offset',
30 """An Entry in the section
32 An entry corresponds to a single node in the device-tree description
33 of the section. Each entry ends up being a part of the final section.
34 Entries can be placed either right next to each other, or with padding
35 between them. The type of the entry determines the data that is in it.
37 This class is not used by itself. All entry objects are subclasses of
41 section: Section object containing this entry
42 node: The node that created this entry
43 offset: Offset of entry within the section, None if not known yet (in
44 which case it will be calculated by Pack())
45 size: Entry size in bytes, None if not known
46 pre_reset_size: size as it was before ResetForPack(). This allows us to
47 keep track of the size we started with and detect size changes
48 uncomp_size: Size of uncompressed data in bytes, if the entry is
50 contents_size: Size of contents in bytes, 0 by default
51 align: Entry start offset alignment relative to the start of the
52 containing section, or None
53 align_size: Entry size alignment, or None
54 align_end: Entry end offset alignment relative to the start of the
55 containing section, or None
56 pad_before: Number of pad bytes before the contents when it is placed
57 in the containing section, 0 if none. The pad bytes become part of
59 pad_after: Number of pad bytes after the contents when it is placed in
60 the containing section, 0 if none. The pad bytes become part of
62 data: Contents of entry (string of bytes). This does not include
63 padding created by pad_before or pad_after. If the entry is
64 compressed, this contains the compressed data.
65 uncomp_data: Original uncompressed data, if this entry is compressed,
67 compress: Compression algoithm used (e.g. 'lz4'), 'none' if none
68 orig_offset: Original offset value read from node
69 orig_size: Original size value read from node
70 missing: True if this entry is missing its contents
71 allow_missing: Allow children of this entry to be missing (used by
72 subclasses such as Entry_section)
73 external: True if this entry contains an external binary blob
75 def __init__(self, section, etype, node, name_prefix=''):
76 # Put this here to allow entry-docs and help to work without libfdt
78 from binman import state
80 self.section = section
83 self.name = node and (name_prefix + node.name) or 'none'
86 self.pre_reset_size = None
87 self.uncomp_size = None
89 self.uncomp_data = None
90 self.contents_size = 0
92 self.align_size = None
96 self.offset_unset = False
98 self.expand_size = False
99 self.compress = 'none'
101 self.external = False
102 self.allow_missing = False
105 def FindEntryClass(etype, expanded):
106 """Look up the entry class for a node.
109 node_node: Path name of Node object containing information about
110 the entry to create (used for errors)
111 etype: Entry type to use
112 expanded: Use the expanded version of etype
115 The entry class object if found, else None if not found and expanded
116 is True, else a tuple:
117 module name that could not be found
120 # Convert something like 'u-boot@0' to 'u_boot' since we are only
121 # interested in the type.
122 module_name = etype.replace('-', '_')
124 if '@' in module_name:
125 module_name = module_name.split('@')[0]
127 module_name += '_expanded'
128 module = modules.get(module_name)
130 # Also allow entry-type modules to be brought in from the etype directory.
132 # Import the module if we have not already done so.
135 module = importlib.import_module('binman.etype.' + module_name)
136 except ImportError as e:
139 return module_name, e
140 modules[module_name] = module
142 # Look up the expected class name
143 return getattr(module, 'Entry_%s' % module_name)
146 def Lookup(node_path, etype, expanded, missing_etype=False):
147 """Look up the entry class for a node.
150 node_node (str): Path name of Node object containing information
151 about the entry to create (used for errors)
152 etype (str): Entry type to use
153 expanded (bool): Use the expanded version of etype
154 missing_etype (bool): True to default to a blob etype if the
155 requested etype is not found
158 The entry class object if found, else None if not found and expanded
162 ValueError if expanded is False and the class is not found
164 # Convert something like 'u-boot@0' to 'u_boot' since we are only
165 # interested in the type.
166 cls = Entry.FindEntryClass(etype, expanded)
169 elif isinstance(cls, tuple):
171 cls = Entry.FindEntryClass('blob', False)
172 if isinstance(cls, tuple): # This should not fail
175 "Unknown entry type '%s' in node '%s' (expected etype/%s.py, error '%s'" %
176 (etype, node_path, module_name, e))
180 def Create(section, node, etype=None, expanded=False, missing_etype=False):
181 """Create a new entry for a node.
184 section (entry_Section): Section object containing this node
185 node (Node): Node object containing information about the entry to
187 etype (str): Entry type to use, or None to work it out (used for
189 expanded (bool): Use the expanded version of etype
190 missing_etype (bool): True to default to a blob etype if the
191 requested etype is not found
194 A new Entry object of the correct type (a subclass of Entry)
197 etype = fdt_util.GetString(node, 'type', node.name)
198 obj = Entry.Lookup(node.path, etype, expanded, missing_etype)
200 # Check whether to use the expanded entry
201 new_etype = etype + '-expanded'
202 can_expand = not fdt_util.GetBool(node, 'no-expanded')
203 if can_expand and obj.UseExpanded(node, etype, new_etype):
208 obj = Entry.Lookup(node.path, etype, False, missing_etype)
210 # Call its constructor to get the object we want.
211 return obj(section, etype, node)
214 """Read entry information from the node
216 This must be called as the first thing after the Entry is created.
218 This reads all the fields we recognise from the node, ready for use.
220 if 'pos' in self._node.props:
221 self.Raise("Please use 'offset' instead of 'pos'")
222 self.offset = fdt_util.GetInt(self._node, 'offset')
223 self.size = fdt_util.GetInt(self._node, 'size')
224 self.orig_offset = fdt_util.GetInt(self._node, 'orig-offset')
225 self.orig_size = fdt_util.GetInt(self._node, 'orig-size')
226 if self.GetImage().copy_to_orig:
227 self.orig_offset = self.offset
228 self.orig_size = self.size
230 # These should not be set in input files, but are set in an FDT map,
231 # which is also read by this code.
232 self.image_pos = fdt_util.GetInt(self._node, 'image-pos')
233 self.uncomp_size = fdt_util.GetInt(self._node, 'uncomp-size')
235 self.align = fdt_util.GetInt(self._node, 'align')
236 if tools.NotPowerOfTwo(self.align):
237 raise ValueError("Node '%s': Alignment %s must be a power of two" %
238 (self._node.path, self.align))
239 if self.section and self.align is None:
240 self.align = self.section.align_default
241 self.pad_before = fdt_util.GetInt(self._node, 'pad-before', 0)
242 self.pad_after = fdt_util.GetInt(self._node, 'pad-after', 0)
243 self.align_size = fdt_util.GetInt(self._node, 'align-size')
244 if tools.NotPowerOfTwo(self.align_size):
245 self.Raise("Alignment size %s must be a power of two" %
247 self.align_end = fdt_util.GetInt(self._node, 'align-end')
248 self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
249 self.expand_size = fdt_util.GetBool(self._node, 'expand-size')
250 self.missing_msg = fdt_util.GetString(self._node, 'missing-msg')
252 # This is only supported by blobs and sections at present
253 self.compress = fdt_util.GetString(self._node, 'compress', 'none')
255 def GetDefaultFilename(self):
259 """Get the device trees used by this entry
262 Empty dict, if this entry is not a .dtb, otherwise:
264 key: Filename from this entry (without the path)
266 Entry object for this dtb
267 Filename of file containing this dtb
271 def ExpandEntries(self):
272 """Expand out entries which produce other entries
274 Some entries generate subnodes automatically, from which sub-entries
275 are then created. This method allows those to be added to the binman
276 definition for the current image. An entry which implements this method
277 should call state.AddSubnode() to add a subnode and can add properties
278 with state.AddString(), etc.
280 An example is 'files', which produces a section containing a list of
285 def AddMissingProperties(self, have_image_pos):
286 """Add new properties to the device tree as needed for this entry
289 have_image_pos: True if this entry has an image position. This can
290 be False if its parent section is compressed, since compression
291 groups all entries together into a compressed block of data,
292 obscuring the start of each individual child entry
294 for prop in ['offset', 'size']:
295 if not prop in self._node.props:
296 state.AddZeroProp(self._node, prop)
297 if have_image_pos and 'image-pos' not in self._node.props:
298 state.AddZeroProp(self._node, 'image-pos')
299 if self.GetImage().allow_repack:
300 if self.orig_offset is not None:
301 state.AddZeroProp(self._node, 'orig-offset', True)
302 if self.orig_size is not None:
303 state.AddZeroProp(self._node, 'orig-size', True)
305 if self.compress != 'none':
306 state.AddZeroProp(self._node, 'uncomp-size')
307 err = state.CheckAddHashProp(self._node)
311 def SetCalculatedProperties(self):
312 """Set the value of device-tree properties calculated by binman"""
313 state.SetInt(self._node, 'offset', self.offset)
314 state.SetInt(self._node, 'size', self.size)
315 base = self.section.GetRootSkipAtStart() if self.section else 0
316 if self.image_pos is not None:
317 state.SetInt(self._node, 'image-pos', self.image_pos - base)
318 if self.GetImage().allow_repack:
319 if self.orig_offset is not None:
320 state.SetInt(self._node, 'orig-offset', self.orig_offset, True)
321 if self.orig_size is not None:
322 state.SetInt(self._node, 'orig-size', self.orig_size, True)
323 if self.uncomp_size is not None:
324 state.SetInt(self._node, 'uncomp-size', self.uncomp_size)
325 state.CheckSetHashValue(self._node, self.GetData)
327 def ProcessFdt(self, fdt):
328 """Allow entries to adjust the device tree
330 Some entries need to adjust the device tree for their purposes. This
331 may involve adding or deleting properties.
334 True if processing is complete
335 False if processing could not be completed due to a dependency.
336 This will cause the entry to be retried after others have been
341 def SetPrefix(self, prefix):
342 """Set the name prefix for a node
345 prefix: Prefix to set, or '' to not use a prefix
348 self.name = prefix + self.name
350 def SetContents(self, data):
351 """Set the contents of an entry
353 This sets both the data and content_size properties
356 data: Data to set to the contents (bytes)
359 self.contents_size = len(self.data)
361 def ProcessContentsUpdate(self, data):
362 """Update the contents of an entry, after the size is fixed
364 This checks that the new data is the same size as the old. If the size
365 has changed, this triggers a re-run of the packing algorithm.
368 data: Data to set to the contents (bytes)
371 ValueError if the new data size is not the same as the old
375 if state.AllowEntryExpansion() and new_size > self.contents_size:
376 # self.data will indicate the new size needed
378 elif state.AllowEntryContraction() and new_size < self.contents_size:
381 # If not allowed to change, try to deal with it or give up
383 if new_size > self.contents_size:
384 self.Raise('Cannot update entry size from %d to %d' %
385 (self.contents_size, new_size))
387 # Don't let the data shrink. Pad it if necessary
388 if size_ok and new_size < self.contents_size:
389 data += tools.GetBytes(0, self.contents_size - new_size)
392 tout.Debug("Entry '%s' size change from %s to %s" % (
393 self._node.path, ToHex(self.contents_size),
395 self.SetContents(data)
398 def ObtainContents(self):
399 """Figure out the contents of an entry.
402 True if the contents were found, False if another call is needed
403 after the other entries are processed.
405 # No contents by default: subclasses can implement this
408 def ResetForPack(self):
409 """Reset offset/size fields so that packing can be done again"""
410 self.Detail('ResetForPack: offset %s->%s, size %s->%s' %
411 (ToHex(self.offset), ToHex(self.orig_offset),
412 ToHex(self.size), ToHex(self.orig_size)))
413 self.pre_reset_size = self.size
414 self.offset = self.orig_offset
415 self.size = self.orig_size
417 def Pack(self, offset):
418 """Figure out how to pack the entry into the section
420 Most of the time the entries are not fully specified. There may be
421 an alignment but no size. In that case we take the size from the
422 contents of the entry.
424 If an entry has no hard-coded offset, it will be placed at @offset.
426 Once this function is complete, both the offset and size of the
430 Current section offset pointer
433 New section offset pointer (after this entry)
435 self.Detail('Packing: offset=%s, size=%s, content_size=%x' %
436 (ToHex(self.offset), ToHex(self.size),
438 if self.offset is None:
439 if self.offset_unset:
440 self.Raise('No offset set with offset-unset: should another '
441 'entry provide this correct offset?')
442 self.offset = tools.Align(offset, self.align)
443 needed = self.pad_before + self.contents_size + self.pad_after
444 needed = tools.Align(needed, self.align_size)
448 new_offset = self.offset + size
449 aligned_offset = tools.Align(new_offset, self.align_end)
450 if aligned_offset != new_offset:
451 size = aligned_offset - self.offset
452 new_offset = aligned_offset
457 if self.size < needed:
458 self.Raise("Entry contents size is %#x (%d) but entry size is "
459 "%#x (%d)" % (needed, needed, self.size, self.size))
460 # Check that the alignment is correct. It could be wrong if the
461 # and offset or size values were provided (i.e. not calculated), but
462 # conflict with the provided alignment values
463 if self.size != tools.Align(self.size, self.align_size):
464 self.Raise("Size %#x (%d) does not match align-size %#x (%d)" %
465 (self.size, self.size, self.align_size, self.align_size))
466 if self.offset != tools.Align(self.offset, self.align):
467 self.Raise("Offset %#x (%d) does not match align %#x (%d)" %
468 (self.offset, self.offset, self.align, self.align))
469 self.Detail(' - packed: offset=%#x, size=%#x, content_size=%#x, next_offset=%x' %
470 (self.offset, self.size, self.contents_size, new_offset))
474 def Raise(self, msg):
475 """Convenience function to raise an error referencing a node"""
476 raise ValueError("Node '%s': %s" % (self._node.path, msg))
479 """Convenience function to log info referencing a node"""
480 tag = "Info '%s'" % self._node.path
481 tout.Detail('%30s: %s' % (tag, msg))
483 def Detail(self, msg):
484 """Convenience function to log detail referencing a node"""
485 tag = "Node '%s'" % self._node.path
486 tout.Detail('%30s: %s' % (tag, msg))
488 def GetEntryArgsOrProps(self, props, required=False):
489 """Return the values of a set of properties
492 props: List of EntryArg objects
495 ValueError if a property is not found
500 python_prop = prop.name.replace('-', '_')
501 if hasattr(self, python_prop):
502 value = getattr(self, python_prop)
506 value = self.GetArg(prop.name, prop.datatype)
507 if value is None and required:
508 missing.append(prop.name)
511 self.GetImage().MissingArgs(self, missing)
515 """Get the path of a node
518 Full path of the node for this entry
520 return self._node.path
522 def GetData(self, required=True):
523 """Get the contents of an entry
526 required: True if the data must be present, False if it is OK to
530 bytes content of the entry, excluding any padding. If the entry is
531 compressed, the compressed data is returned
533 self.Detail('GetData: size %s' % ToHexSize(self.data))
536 def GetPaddedData(self, data=None):
537 """Get the data for an entry including any padding
539 Gets the entry data and uses its section's pad-byte value to add padding
540 before and after as defined by the pad-before and pad-after properties.
542 This does not consider alignment.
545 Contents of the entry along with any pad bytes before and
549 data = self.GetData()
550 return self.section.GetPaddedDataForEntry(self, data)
552 def GetOffsets(self):
553 """Get the offsets for siblings
555 Some entry types can contain information about the position or size of
556 other entries. An example of this is the Intel Flash Descriptor, which
557 knows where the Intel Management Engine section should go.
559 If this entry knows about the position of other entries, it can specify
560 this by returning values here
565 value: List containing position and size of the given entry
566 type. Either can be None if not known
570 def SetOffsetSize(self, offset, size):
571 """Set the offset and/or size of an entry
574 offset: New offset, or None to leave alone
575 size: New size, or None to leave alone
577 if offset is not None:
582 def SetImagePos(self, image_pos):
583 """Set the position in the image
586 image_pos: Position of this entry in the image
588 self.image_pos = image_pos + self.offset
590 def ProcessContents(self):
591 """Do any post-packing updates of entry contents
593 This function should call ProcessContentsUpdate() to update the entry
594 contents, if necessary, returning its return value here.
597 data: Data to set to the contents (bytes)
600 True if the new data size is OK, False if expansion is needed
603 ValueError if the new data size is not the same as the old and
604 state.AllowEntryExpansion() is False
608 def WriteSymbols(self, section):
609 """Write symbol values into binary files for access at run time
612 section: Section containing the entry
616 def CheckEntries(self):
617 """Check that the entry offsets are correct
619 This is used for entries which have extra offset requirements (other
620 than having to be fully inside their section). Sub-classes can implement
621 this function and raise if there is a problem.
629 return '%08x' % value
632 def WriteMapLine(fd, indent, name, offset, size, image_pos):
633 print('%s %s%s %s %s' % (Entry.GetStr(image_pos), ' ' * indent,
634 Entry.GetStr(offset), Entry.GetStr(size),
637 def WriteMap(self, fd, indent):
638 """Write a map of the entry to a .map file
641 fd: File to write the map to
642 indent: Curent indent level of map (0=none, 1=one level, etc.)
644 self.WriteMapLine(fd, indent, self.name, self.offset, self.size,
647 def GetEntries(self):
648 """Return a list of entries contained by this entry
651 List of entries, or None if none. A normal entry has no entries
652 within it so will return None
656 def GetArg(self, name, datatype=str):
657 """Get the value of an entry argument or device-tree-node property
659 Some node properties can be provided as arguments to binman. First check
660 the entry arguments, and fall back to the device tree if not found
664 datatype: Data type (str or int)
667 Value of argument as a string or int, or None if no value
670 ValueError if the argument cannot be converted to in
672 value = state.GetEntryArg(name)
673 if value is not None:
678 self.Raise("Cannot convert entry arg '%s' (value '%s') to integer" %
680 elif datatype == str:
683 raise ValueError("GetArg() internal error: Unknown data type '%s'" %
686 value = fdt_util.GetDatatype(self._node, name, datatype)
690 def WriteDocs(modules, test_missing=None):
691 """Write out documentation about the various entry types to stdout
694 modules: List of modules to include
695 test_missing: Used for testing. This is a module to report
698 print('''Binman Entry Documentation
699 ===========================
701 This file describes the entry types supported by binman. These entry types can
702 be placed in an image one by one to build up a final firmware image. It is
703 fairly easy to create new entry types. Just add a new file to the 'etype'
704 directory. You can use the existing entries as examples.
706 Note that some entries are subclasses of others, using and extending their
707 features to produce new behaviours.
711 modules = sorted(modules)
713 # Don't show the test entry
714 if '_testing' in modules:
715 modules.remove('_testing')
718 module = Entry.Lookup('WriteDocs', name, False)
719 docs = getattr(module, '__doc__')
720 if test_missing == name:
723 lines = docs.splitlines()
724 first_line = lines[0]
725 rest = [line[4:] for line in lines[1:]]
726 hdr = 'Entry: %s: %s' % (name.replace('_', '-'), first_line)
728 print('-' * len(hdr))
729 print('\n'.join(rest))
736 raise ValueError('Documentation is missing for modules: %s' %
739 def GetUniqueName(self):
740 """Get a unique name for a node
743 String containing a unique name for a node, consisting of the name
744 of all ancestors (starting from within the 'binman' node) separated
745 by a dot ('.'). This can be useful for generating unique filesnames
746 in the output directory.
752 if node.name == 'binman':
754 name = '%s.%s' % (node.name, name)
757 def ExpandToLimit(self, limit):
758 """Expand an entry so that it ends at the given offset limit"""
759 if self.offset + self.size < limit:
760 self.size = limit - self.offset
761 # Request the contents again, since changing the size requires that
762 # the data grows. This should not fail, but check it to be sure.
763 if not self.ObtainContents():
764 self.Raise('Cannot obtain contents when expanding entry')
766 def HasSibling(self, name):
767 """Check if there is a sibling of a given name
770 True if there is an entry with this name in the the same section,
773 return name in self.section.GetEntries()
775 def GetSiblingImagePos(self, name):
776 """Return the image position of the given sibling
779 Image position of sibling, or None if the sibling has no position,
780 or False if there is no such sibling
782 if not self.HasSibling(name):
784 return self.section.GetEntries()[name].image_pos
787 def AddEntryInfo(entries, indent, name, etype, size, image_pos,
788 uncomp_size, offset, entry):
789 """Add a new entry to the entries list
792 entries: List (of EntryInfo objects) to add to
793 indent: Current indent level to add to list
794 name: Entry name (string)
795 etype: Entry type (string)
796 size: Entry size in bytes (int)
797 image_pos: Position within image in bytes (int)
798 uncomp_size: Uncompressed size if the entry uses compression, else
800 offset: Entry offset within parent in bytes (int)
803 entries.append(EntryInfo(indent, name, etype, size, image_pos,
804 uncomp_size, offset, entry))
806 def ListEntries(self, entries, indent):
807 """Add files in this entry to the list of entries
809 This can be overridden by subclasses which need different behaviour.
812 entries: List (of EntryInfo objects) to add to
813 indent: Current indent level to add to list
815 self.AddEntryInfo(entries, indent, self.name, self.etype, self.size,
816 self.image_pos, self.uncomp_size, self.offset, self)
818 def ReadData(self, decomp=True):
819 """Read the data for an entry from the image
821 This is used when the image has been read in and we want to extract the
822 data for a particular entry from that image.
825 decomp: True to decompress any compressed data before returning it;
826 False to return the raw, uncompressed data
831 # Use True here so that we get an uncompressed section to work from,
832 # although compressed sections are currently not supported
833 tout.Debug("ReadChildData section '%s', entry '%s'" %
834 (self.section.GetPath(), self.GetPath()))
835 data = self.section.ReadChildData(self, decomp)
838 def ReadChildData(self, child, decomp=True):
839 """Read the data for a particular child entry
841 This reads data from the parent and extracts the piece that relates to
845 child: Child entry to read data for (must be valid)
846 decomp: True to decompress any compressed data before returning it;
847 False to return the raw, uncompressed data
850 Data for the child (bytes)
854 def LoadData(self, decomp=True):
855 data = self.ReadData(decomp)
856 self.contents_size = len(data)
857 self.ProcessContentsUpdate(data)
858 self.Detail('Loaded data size %x' % len(data))
861 """Get the image containing this entry
864 Image object containing this entry
866 return self.section.GetImage()
868 def WriteData(self, data, decomp=True):
869 """Write the data to an entry in the image
871 This is used when the image has been read in and we want to replace the
872 data for a particular entry in that image.
874 The image must be re-packed and written out afterwards.
877 data: Data to replace it with
878 decomp: True to compress the data if needed, False if data is
879 already compressed so should be used as is
882 True if the data did not result in a resize of this entry, False if
883 the entry must be resized
885 if self.size is not None:
886 self.contents_size = self.size
888 self.contents_size = self.pre_reset_size
889 ok = self.ProcessContentsUpdate(data)
890 self.Detail('WriteData: size=%x, ok=%s' % (len(data), ok))
891 section_ok = self.section.WriteChildData(self)
892 return ok and section_ok
894 def WriteChildData(self, child):
895 """Handle writing the data in a child entry
897 This should be called on the child's parent section after the child's
898 data has been updated. It should update any data structures needed to
899 validate that the update is successful.
901 This base-class implementation does nothing, since the base Entry object
902 does not have any children.
905 child: Child Entry that was written
908 True if the section could be updated successfully, False if the
909 data is such that the section could not update
913 def GetSiblingOrder(self):
914 """Get the relative order of an entry amoung its siblings
917 'start' if this entry is first among siblings, 'end' if last,
920 entries = list(self.section.GetEntries().values())
922 if self == entries[0]:
924 elif self == entries[-1]:
928 def SetAllowMissing(self, allow_missing):
929 """Set whether a section allows missing external blobs
932 allow_missing: True if allowed, False if not allowed
934 # This is meaningless for anything other than sections
937 def CheckMissing(self, missing_list):
938 """Check if any entries in this section have missing external blobs
940 If there are missing blobs, the entries are added to the list
943 missing_list: List of Entry objects to be added to
946 missing_list.append(self)
948 def GetAllowMissing(self):
949 """Get whether a section allows missing external blobs
952 True if allowed, False if not allowed
954 return self.allow_missing
956 def GetHelpTags(self):
957 """Get the tags use for missing-blob help
960 list of possible tags, most desirable first
962 return list(filter(None, [self.missing_msg, self.name, self.etype]))
964 def CompressData(self, indata):
965 """Compress data according to the entry's compression method
968 indata: Data to compress
971 Compressed data (first word is the compressed size)
973 self.uncomp_data = indata
974 if self.compress != 'none':
975 self.uncomp_size = len(indata)
976 data = tools.Compress(indata, self.compress)
980 def UseExpanded(cls, node, etype, new_etype):
981 """Check whether to use an expanded entry type
983 This is called by Entry.Create() when it finds an expanded version of
984 an entry type (e.g. 'u-boot-expanded'). If this method returns True then
985 it will be used (e.g. in place of 'u-boot'). If it returns False, it is
989 node: Node object containing information about the entry to
991 etype: Original entry type being used
992 new_etype: New entry type proposed
995 True to use this entry type, False to use the original one
997 tout.Info("Node '%s': etype '%s': %s selected" %
998 (node.path, etype, new_etype))