intelhex-2.1/0000755000175200017530000000000013147241054013732 5ustar builddbuildd00000000000000intelhex-2.1/LICENSE.txt0000644000175200017530000000277013147236475015576 0ustar builddbuildd00000000000000Copyright (c) 2005-2016, Alexander Belchenko All rights reserved. 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 the author 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. intelhex-2.1/AUTHORS.txt0000644000175200017530000000064313147236475015636 0ustar builddbuildd00000000000000Author: Alexander Belchenko Copyright (C) Alexander Belchenko, 2005-2016 Special thanks to Bernhard Leiner for huge help in porting IntelHex library to Python 3. Contributors: * Alexander Belchenko * Alex Mueller * Andrew Fernandes * Bernhard Leiner * Enoch H. Wexler * Heiko Henkelmann * Henrik Maier * Morgan McClure * Nathan P. Stien * Stefan Schmitt * Zachary Clifford * "durexyl" @ GitHub intelhex-2.1/setup.py0000755000175200017530000001067013147236475015466 0ustar builddbuildd00000000000000#!/usr/bin/python # Copyright (c) 2008-2016, Alexander Belchenko # All rights reserved. # # 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 the author 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. """Setup script for IntelHex.""" import sys, glob from distutils.core import Command, setup import intelhex, intelhex.__version__ METADATA = dict( name='intelhex', version=intelhex.__version__.version_str, scripts=glob.glob('scripts/*'), packages=['intelhex'], author='Alexander Belchenko', author_email='alexander.belchenko@gmail.com', url='https://pypi.python.org/pypi/IntelHex', description='Python Intel Hex library', long_description='Python Intel Hex library', keywords='Intel HEX hex2bin HEX8', license='BSD', classifiers = [ 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', 'Classifier: Development Status :: 5 - Production/Stable', 'Classifier: Environment :: Console', 'Classifier: Intended Audience :: Developers', 'Classifier: Intended Audience :: Telecommunications Industry', 'Classifier: License :: OSI Approved :: BSD License', 'Classifier: Operating System :: OS Independent', 'Classifier: Programming Language :: Python', 'Classifier: Topic :: Scientific/Engineering', 'Classifier: Topic :: Software Development :: Embedded Systems', 'Classifier: Topic :: Utilities', ], ) class test(Command): description = "unittest for intelhex" user_options = [] boolean_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): import unittest import intelhex.test verbosity = 1 if self.verbose: verbosity = 2 suite = unittest.TestSuite() loader = unittest.TestLoader() suite.addTest(loader.loadTestsFromModule(intelhex.test)) runner = unittest.TextTestRunner(stream=sys.stdout, verbosity=verbosity) result = runner.run(suite) if result.errors or result.failures: sys.exit(1) class bench(Command): description = "benchmarks for read/write HEX" user_options = [ ('repeat', 'n', 'repeat tests N times'), ('read', 'r', 'run only tests for read operation'), ('write', 'w', 'run only tests for write operation'), ] boolean_options = ['read', 'write'] def initialize_options(self): self.repeat = 3 self.read = None self.write = None def finalize_options(self): if not self.read and not self.write: self.read = self.write = True def run(self): from intelhex.bench import Measure m = Measure(self.repeat, self.read, self.write) m.measure_all() m.print_report() def main(): metadata = METADATA.copy() metadata['cmdclass'] = { 'test': test, #'bench': bench, # bench is out of date } return setup(**metadata) if __name__ == '__main__': main() intelhex-2.1/setup.cfg0000644000175200017530000000003013147236475015557 0ustar builddbuildd00000000000000[wheel] universal = 1 intelhex-2.1/intelhex/0000755000175200017530000000000013147241054015552 5ustar builddbuildd00000000000000intelhex-2.1/intelhex/__version__.py0000644000175200017530000000017013147236475020416 0ustar builddbuildd00000000000000# IntelHex library version information version_info = (2, 1) version_str = '.'.join([str(i) for i in version_info]) intelhex-2.1/intelhex/getsizeof.py0000644000175200017530000000417713147236475020147 0ustar builddbuildd00000000000000# Recursive version sys.getsizeof(). Extendable with custom handlers. # Code from http://code.activestate.com/recipes/577504/ # Created by Raymond Hettinger on Fri, 17 Dec 2010 (MIT) import sys from itertools import chain from collections import deque try: from reprlib import repr except ImportError: pass def total_size(o, handlers={}, verbose=False): """ Returns the approximate memory footprint an object and all of its contents. Automatically finds the contents of the following builtin containers and their subclasses: tuple, list, deque, dict, set and frozenset. To search other containers, add handlers to iterate over their contents: handlers = {SomeContainerClass: iter, OtherContainerClass: OtherContainerClass.get_elements} """ dict_handler = lambda d: chain.from_iterable(d.items()) all_handlers = {tuple: iter, list: iter, deque: iter, dict: dict_handler, set: iter, frozenset: iter, } all_handlers.update(handlers) # user handlers take precedence seen = set() # track which object id's have already been seen default_size = sys.getsizeof(0) # estimate sizeof object without __sizeof__ def sizeof(o): if id(o) in seen: # do not double count the same object return 0 seen.add(id(o)) s = sys.getsizeof(o, default_size) if verbose: print(s, type(o), repr(o))#, file=stderr) for typ, handler in all_handlers.items(): if isinstance(o, typ): s += sum(map(sizeof, handler(o))) break return s return sizeof(o) ##### Example call ##### if __name__ == '__main__': #d = dict(a=1, b=2, c=3, d=[4,5,6,7], e='a string of chars') print("dict 3 elements") d = {0:0xFF, 1:0xEE, 2:0xCC} print(total_size(d, verbose=True)) #print("array 3 elements") #import array #print(total_size(array.array('B', b'\x01\x02\x03'))) intelhex-2.1/intelhex/test.py0000755000175200017530000017566013147236475017140 0ustar builddbuildd00000000000000# Copyright (c) 2005-2016, Alexander Belchenko # All rights reserved. # # 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 the author 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. """Test suite for IntelHex library.""" import array import os import shlex import subprocess import sys import tempfile import unittest import intelhex from intelhex import ( IntelHex, IntelHexError, HexReaderError, AddressOverlapError, HexRecordError, RecordLengthError, RecordTypeError, RecordChecksumError, EOFRecordError, ExtendedSegmentAddressRecordError, ExtendedLinearAddressRecordError, StartSegmentAddressRecordError, StartLinearAddressRecordError, DuplicateStartAddressRecordError, InvalidStartAddressValueError, _EndOfFile, BadAccess16bit, hex2bin, Record, ) from intelhex import compat from intelhex.compat import ( BytesIO, StringIO, UnicodeType, array_tobytes, asbytes, asstr, dict_items_g, range_g, range_l, ) from intelhex.__version__ import version_str __docformat__ = 'restructuredtext' ## # Data for tests hex8 = '''\ :1004E300CFF0FBE2FDF220FF20F2E120E2FBE6F396 :1004F3000A00FDE0E1E2E3B4E4E5BAE6E7B3BFE80E :10050300E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8E0 :10051300F9FCFEFF00C0C1C2C3A5C4C5AAC6C7B2C9 :10052300AFC8C9CACBCCCDCECFD0D1D2D3D4D5D6F8 :07053300D7D8D9DCDEDF00A0 :10053A0078227C007D007BFF7A0479F57E007F2398 :10054A0012042F78457C007D007BFF7A0579187E9E :10055A00007F2212042F759850438920758DDDD2B1 :10056A008ED2996390017BFF7A0479E31200658049 :01057A00FE82 :030000000205A254 :0C05A200787FE4F6D8FD75817A02053AF6 :10035F00E709F608DFFA8046E709F208DFFA803E80 :10036F0088828C83E709F0A3DFFA8032E309F6086D :10037F00DFFA8078E309F208DFFA807088828C83D5 :10038F00E309F0A3DFFA806489828A83E0A3F60889 :10039F00DFFA805889828A83E0A3F208DFFA804C63 :1003AF0080D280FA80C680D4806980F2803380103A :1003BF0080A680EA809A80A880DA80E280CA8033A3 :1003CF0089828A83ECFAE493A3C8C582C8CCC5831B :1003DF00CCF0A3C8C582C8CCC583CCDFE9DEE780EB :1003EF000D89828A83E493A3F608DFF9ECFAA9F06A :1003FF00EDFB2289828A83ECFAE0A3C8C582C8CCC0 :10040F00C583CCF0A3C8C582C8CCC583CCDFEADED8 :10041F00E880DB89828A83E493A3F208DFF980CC3A :10042F0088F0EF60010E4E60C388F0ED2402B40433 :10043F000050B9F582EB2402B4040050AF232345DA :06044F0082239003AF734D :10000300E576246AF8E60576227867300702786A8F :10001300E475F0011204AD0204552000EB7F2ED2EB :10002300008018EF540F2490D43440D4FF30040BD5 :10003300EF24BFB41A0050032461FFE57760021573 :1000430077057AE57A7002057930070D7867E475EC :10005300F0011204ADEF02049B02057B7403D20787 :100063008003E4C207F5768B678A688969E4F577CC :10007300F579F57AE57760077F2012003E80F57504 :1000830078FFC201C200C202C203C205C206C2088F :1000930012000CFF700D3007057F0012004FAF7A7E :1000A300AE7922B4255FC2D5C20412000CFF24D05E :1000B300B40A00501A75F00A787730D50508B6FFF0 :1000C3000106C6A426F620D5047002D20380D924E3 :1000D300CFB41A00EF5004C2E5D20402024FD2019A :1000E30080C6D20080C0D20280BCD2D580BAD205ED :1000F30080B47F2012003E2002077401B5770040D0 :10010300F1120003FF12003E020077D208D20680EC :1001130095120003FB120003FA120003F94A4B7015 :100123000679207A037BFF20022EE577602A7E0082 :100133008E8275830012046E60060EEE657870F091 :10014300C2D5EBC0E0EAC0E0E9C0E0EE120296D00F :10015300E0F9D0E0FAD0E0FB120455FF60AAEBC04F :10016300E0EAC0E0E9C0E012003ED0E02401F9D0AB :10017300E03400FAD0E0FBE5780460DCD578D98080 :10018300877BFF7A027992D202809C791080027970 :1001930008C206C2088008D2D5790A8004790AC247 :1001A300D5E578047002F578E4FAFDFEFF1200034A :1001B300FC7B08200113120003FD7B1030000A12A0 :1001C3000003FE120003FF7B20EC3382D592D5504F :1001D30013C3E43000069FFFE49EFEE42001039D69 :1001E300FDE49CFCE4CBF8C201EC700CCFCECDCC8B :1001F300E824F8F870F38017C3EF33FFEE33FEED16 :1002030033FDEC33FCEB33FB994002FB0FD8E9EBF6 :10021300300105F8D0E0C448B201C0E00AEC4D4E0D :100223004F78207B0070C2EAB5780040BCC0E01272 :100233000298D0F0D0E0200104C4C0E0C4B201C0F1 :10024300F0120027D0F0D5F0EB0200771204BD01C5 :100253001453018E5800E54C00E14201924F019A7C :0F02630044019A4900FA4301A0550184460184E1 :100272004501844703405000E92D00ED2E01102B6B :1002820000F123010E2003292A00A94800000108D9 :100292003F3F3F00790AA2D5200314300509B91067 :1002A200020404B9080104A2D52006025001042068 :1002B20002689202B577005034C0E07F2030031903 :1002C2007F30A20272067205500F1202EFC202C202 :1002D20006C205C2087F30800F300503E9C0E01274 :1002E200003E300503D0E0F9D0E0B577CC300517F9 :1002F2007F30B9100C12003E7F583004077F78809F :1003020003B9080312003E3002057F2D02003E7F32 :10031200202008F87F2B2006F322920280CF286E3D :10032200756C6C2900D2011200033001F8C2017809 :100332007730D50108F60200A92D50434958120022 :10034200032403B405004001E490033B9312002F01 :0D035200743A12002FD20375770402018E59 :10045500BB010689828A83E0225002E722BBFE02A5 :09046500E32289828A83E49322D8 :10046E00BB010CE58229F582E5833AF583E0225043 :10047E0006E92582F8E622BBFE06E92582F8E2228D :0D048E00E58229F582E5833AF583E49322A7 :10049B00BB010689828A83F0225002F722BBFE0140 :0204AB00F3223A :1004AD00FAE6FB0808E6F925F0F618E6CA3AF62250 :1004BD00D083D082F8E4937012740193700DA3A3CE :1004CD0093F8740193F5828883E4737402936860E2 :0604DD00EFA3A3A380DFE2 :10057B00EFB40A07740D120586740A309811A89906 :10058B00B8130CC2983098FDA899C298B811F630E0 :07059B0099FDC299F59922B8 :00000001FF ''' bin8 = array.array('B',[2, 5, 162, 229, 118, 36, 106, 248, 230, 5, 118, 34, 120, 103, 48, 7, 2, 120, 106, 228, 117, 240, 1, 18, 4, 173, 2, 4, 85, 32, 0, 235, 127, 46, 210, 0, 128, 24, 239, 84, 15, 36, 144, 212, 52, 64, 212, 255, 48, 4, 11, 239, 36, 191, 180, 26, 0, 80, 3, 36, 97, 255, 229, 119, 96, 2, 21, 119, 5, 122, 229, 122, 112, 2, 5, 121, 48, 7, 13, 120, 103, 228, 117, 240, 1, 18, 4, 173, 239, 2, 4, 155, 2, 5, 123, 116, 3, 210, 7, 128, 3, 228, 194, 7, 245, 118, 139, 103, 138, 104, 137, 105, 228, 245, 119, 245, 121, 245, 122, 229, 119, 96, 7, 127, 32, 18, 0, 62, 128, 245, 117, 120, 255, 194, 1, 194, 0, 194, 2, 194, 3, 194, 5, 194, 6, 194, 8, 18, 0, 12, 255, 112, 13, 48, 7, 5, 127, 0, 18, 0, 79, 175, 122, 174, 121, 34, 180, 37, 95, 194, 213, 194, 4, 18, 0, 12, 255, 36, 208, 180, 10, 0, 80, 26, 117, 240, 10, 120, 119, 48, 213, 5, 8, 182, 255, 1, 6, 198, 164, 38, 246, 32, 213, 4, 112, 2, 210, 3, 128, 217, 36, 207, 180, 26, 0, 239, 80, 4, 194, 229, 210, 4, 2, 2, 79, 210, 1, 128, 198, 210, 0, 128, 192, 210, 2, 128, 188, 210, 213, 128, 186, 210, 5, 128, 180, 127, 32, 18, 0, 62, 32, 2, 7, 116, 1, 181, 119, 0, 64, 241, 18, 0, 3, 255, 18, 0, 62, 2, 0, 119, 210, 8, 210, 6, 128, 149, 18, 0, 3, 251, 18, 0, 3, 250, 18, 0, 3, 249, 74, 75, 112, 6, 121, 32, 122, 3, 123, 255, 32, 2, 46, 229, 119, 96, 42, 126, 0, 142, 130, 117, 131, 0, 18, 4, 110, 96, 6, 14, 238, 101, 120, 112, 240, 194, 213, 235, 192, 224, 234, 192, 224, 233, 192, 224, 238, 18, 2, 150, 208, 224, 249, 208, 224, 250, 208, 224, 251, 18, 4, 85, 255, 96, 170, 235, 192, 224, 234, 192, 224, 233, 192, 224, 18, 0, 62, 208, 224, 36, 1, 249, 208, 224, 52, 0, 250, 208, 224, 251, 229, 120, 4, 96, 220, 213, 120, 217, 128, 135, 123, 255, 122, 2, 121, 146, 210, 2, 128, 156, 121, 16, 128, 2, 121, 8, 194, 6, 194, 8, 128, 8, 210, 213, 121, 10, 128, 4, 121, 10, 194, 213, 229, 120, 4, 112, 2, 245, 120, 228, 250, 253, 254, 255, 18, 0, 3, 252, 123, 8, 32, 1, 19, 18, 0, 3, 253, 123, 16, 48, 0, 10, 18, 0, 3, 254, 18, 0, 3, 255, 123, 32, 236, 51, 130, 213, 146, 213, 80, 19, 195, 228, 48, 0, 6, 159, 255, 228, 158, 254, 228, 32, 1, 3, 157, 253, 228, 156, 252, 228, 203, 248, 194, 1, 236, 112, 12, 207, 206, 205, 204, 232, 36, 248, 248, 112, 243, 128, 23, 195, 239, 51, 255, 238, 51, 254, 237, 51, 253, 236, 51, 252, 235, 51, 251, 153, 64, 2, 251, 15, 216, 233, 235, 48, 1, 5, 248, 208, 224, 196, 72, 178, 1, 192, 224, 10, 236, 77, 78, 79, 120, 32, 123, 0, 112, 194, 234, 181, 120, 0, 64, 188, 192, 224, 18, 2, 152, 208, 240, 208, 224, 32, 1, 4, 196, 192, 224, 196, 178, 1, 192, 240, 18, 0, 39, 208, 240, 213, 240, 235, 2, 0, 119, 18, 4, 189, 1, 20, 83, 1, 142, 88, 0, 229, 76, 0, 225, 66, 1, 146, 79, 1, 154, 68, 1, 154, 73, 0, 250, 67, 1, 160, 85, 1, 132, 70, 1, 132, 69, 1, 132, 71, 3, 64, 80, 0, 233, 45, 0, 237, 46, 1, 16, 43, 0, 241, 35, 1, 14, 32, 3, 41, 42, 0, 169, 72, 0, 0, 1, 8, 63, 63, 63, 0, 121, 10, 162, 213, 32, 3, 20, 48, 5, 9, 185, 16, 2, 4, 4, 185, 8, 1, 4, 162, 213, 32, 6, 2, 80, 1, 4, 32, 2, 104, 146, 2, 181, 119, 0, 80, 52, 192, 224, 127, 32, 48, 3, 25, 127, 48, 162, 2, 114, 6, 114, 5, 80, 15, 18, 2, 239, 194, 2, 194, 6, 194, 5, 194, 8, 127, 48, 128, 15, 48, 5, 3, 233, 192, 224, 18, 0, 62, 48, 5, 3, 208, 224, 249, 208, 224, 181, 119, 204, 48, 5, 23, 127, 48, 185, 16, 12, 18, 0, 62, 127, 88, 48, 4, 7, 127, 120, 128, 3, 185, 8, 3, 18, 0, 62, 48, 2, 5, 127, 45, 2, 0, 62, 127, 32, 32, 8, 248, 127, 43, 32, 6, 243, 34, 146, 2, 128, 207, 40, 110, 117, 108, 108, 41, 0, 210, 1, 18, 0, 3, 48, 1, 248, 194, 1, 120, 119, 48, 213, 1, 8, 246, 2, 0, 169, 45, 80, 67, 73, 88, 18, 0, 3, 36, 3, 180, 5, 0, 64, 1, 228, 144, 3, 59, 147, 18, 0, 47, 116, 58, 18, 0, 47, 210, 3, 117, 119, 4, 2, 1, 142, 231, 9, 246, 8, 223, 250, 128, 70, 231, 9, 242, 8, 223, 250, 128, 62, 136, 130, 140, 131, 231, 9, 240, 163, 223, 250, 128, 50, 227, 9, 246, 8, 223, 250, 128, 120, 227, 9, 242, 8, 223, 250, 128, 112, 136, 130, 140, 131, 227, 9, 240, 163, 223, 250, 128, 100, 137, 130, 138, 131, 224, 163, 246, 8, 223, 250, 128, 88, 137, 130, 138, 131, 224, 163, 242, 8, 223, 250, 128, 76, 128, 210, 128, 250, 128, 198, 128, 212, 128, 105, 128, 242, 128, 51, 128, 16, 128, 166, 128, 234, 128, 154, 128, 168, 128, 218, 128, 226, 128, 202, 128, 51, 137, 130, 138, 131, 236, 250, 228, 147, 163, 200, 197, 130, 200, 204, 197, 131, 204, 240, 163, 200, 197, 130, 200, 204, 197, 131, 204, 223, 233, 222, 231, 128, 13, 137, 130, 138, 131, 228, 147, 163, 246, 8, 223, 249, 236, 250, 169, 240, 237, 251, 34, 137, 130, 138, 131, 236, 250, 224, 163, 200, 197, 130, 200, 204, 197, 131, 204, 240, 163, 200, 197, 130, 200, 204, 197, 131, 204, 223, 234, 222, 232, 128, 219, 137, 130, 138, 131, 228, 147, 163, 242, 8, 223, 249, 128, 204, 136, 240, 239, 96, 1, 14, 78, 96, 195, 136, 240, 237, 36, 2, 180, 4, 0, 80, 185, 245, 130, 235, 36, 2, 180, 4, 0, 80, 175, 35, 35, 69, 130, 35, 144, 3, 175, 115, 187, 1, 6, 137, 130, 138, 131, 224, 34, 80, 2, 231, 34, 187, 254, 2, 227, 34, 137, 130, 138, 131, 228, 147, 34, 187, 1, 12, 229, 130, 41, 245, 130, 229, 131, 58, 245, 131, 224, 34, 80, 6, 233, 37, 130, 248, 230, 34, 187, 254, 6, 233, 37, 130, 248, 226, 34, 229, 130, 41, 245, 130, 229, 131, 58, 245, 131, 228, 147, 34, 187, 1, 6, 137, 130, 138, 131, 240, 34, 80, 2, 247, 34, 187, 254, 1, 243, 34, 250, 230, 251, 8, 8, 230, 249, 37, 240, 246, 24, 230, 202, 58, 246, 34, 208, 131, 208, 130, 248, 228, 147, 112, 18, 116, 1, 147, 112, 13, 163, 163, 147, 248, 116, 1, 147, 245, 130, 136, 131, 228, 115, 116, 2, 147, 104, 96, 239, 163, 163, 163, 128, 223, 207, 240, 251, 226, 253, 242, 32, 255, 32, 242, 225, 32, 226, 251, 230, 243, 10, 0, 253, 224, 225, 226, 227, 180, 228, 229, 186, 230, 231, 179, 191, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 252, 254, 255, 0, 192, 193, 194, 195, 165, 196, 197, 170, 198, 199, 178, 175, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 220, 222, 223, 0, 120, 34, 124, 0, 125, 0, 123, 255, 122, 4, 121, 245, 126, 0, 127, 35, 18, 4, 47, 120, 69, 124, 0, 125, 0, 123, 255, 122, 5, 121, 24, 126, 0, 127, 34, 18, 4, 47, 117, 152, 80, 67, 137, 32, 117, 141, 221, 210, 142, 210, 153, 99, 144, 1, 123, 255, 122, 4, 121, 227, 18, 0, 101, 128, 254, 239, 180, 10, 7, 116, 13, 18, 5, 134, 116, 10, 48, 152, 17, 168, 153, 184, 19, 12, 194, 152, 48, 152, 253, 168, 153, 194, 152, 184, 17, 246, 48, 153, 253, 194, 153, 245, 153, 34, 120, 127, 228, 246, 216, 253, 117, 129, 122, 2, 5, 58]) hex16 = """:020000040000FA :10000000000083120313072055301820042883169C :10001000031340309900181598168312031318160D :1000200098170800831203138C1E14281A0808005E :0C003000831203130C1E1A28990008000C :00000001FF """ bin16 = array.array('H', [0x0000, 0x1283, 0x1303, 0x2007, 0x3055, 0x2018, 0x2804, 0x1683, 0x1303, 0x3040, 0x0099, 0x1518, 0x1698, 0x1283, 0x1303, 0x1618, 0x1798, 0x0008, 0x1283, 0x1303, 0x1E8C, 0x2814, 0x081A, 0x0008, 0x1283, 0x1303, 0x1E0C, 0x281A, 0x0099, 0x0008, 0x3FFF, 0x3FFF]) hex64k = """:020000040000FA :0100000001FE :020000040001F9 :0100000002FD :00000001FF """ data64k = {0: 1, 0x10000: 2} hex_rectype3 = """:0400000312345678E5 :0100000001FE :00000001FF """ data_rectype3 = {0: 1} start_addr_rectype3 = {'CS': 0x1234, 'IP': 0x5678} hex_rectype5 = """:0400000512345678E3 :0100000002FD :00000001FF """ data_rectype5 = {0: 2} start_addr_rectype5 = {'EIP': 0x12345678} hex_empty_file = ':00000001FF\n' hex_simple = """\ :10000000000083120313072055301820042883169C :10001000031340309900181598168312031318160D :1000200098170800831203138C1E14281A0808005E :0C003000831203130C1E1A28990008000C :00000001FF """ hex_bug_lp_341051 = """\ :020FEC00E4E738 :040FF00022E122E1F7 :00000001FF """ ## # Test cases class TestIntelHexBase(unittest.TestCase): """Base class for all tests. Provide additional functionality for testing. """ def assertRaisesMsg(self, excClass, msg, callableObj, *args, **kwargs): """Just like unittest.TestCase.assertRaises, but checks that the message is right too. Borrowed from Ned Batchelder Blog. See: http://www.nedbatchelder.com/blog/200609.html#e20060905T064418 Typical usage:: self.assertRaisesMsg(MyException, "Exception message", my_function, (arg1, arg2)) """ try: callableObj(*args, **kwargs) except excClass: exc = sys.exc_info()[1] # current exception excMsg = str(exc) if not msg: # No message provided: any message is fine. return elif excMsg == msg: # Message provided, and we got the right message: it passes. return else: # Message provided, and it didn't match: fail! raise self.failureException( "Right exception, wrong message: got '%s' expected '%s'" % (excMsg, msg) ) else: if hasattr(excClass, '__name__'): excName = excClass.__name__ else: excName = str(excClass) raise self.failureException( "Expected to raise %s, didn't get an exception at all" % excName ) def assertEqualWrittenData(self, a, b): return self.assertEqual(a, b, """Written data is incorrect Should be: %s Written: %s """ % (a, b)) #/class TestIntelHexBase class TestIntelHex(TestIntelHexBase): def setUp(self): self.f = StringIO(hex8) def tearDown(self): self.f.close() del self.f def test_init_from_file(self): ih = IntelHex(self.f) for addr in range_g(len(bin8)): expected = bin8[addr] actual = ih[addr] self.assertEqual(expected, actual, "Data different at address " "%x (%x != %x)" % (addr, expected, actual)) def test_hex_fromfile(self): ih = IntelHex() ih.fromfile(self.f, format='hex') for addr in range_g(len(bin8)): expected = bin8[addr] actual = ih[addr] self.assertEqual(expected, actual, "Data different at address " "%x (%x != %x)" % (addr, expected, actual)) def test_unicode_filename(self): handle, fname = tempfile.mkstemp(UnicodeType('')) os.close(handle) try: self.assertTrue(isinstance(fname, UnicodeType)) f = open(fname, 'w') try: f.write(hex8) finally: f.close() ih = IntelHex(fname) self.assertEqual(0, ih.minaddr()) self.assertEqual(len(bin8)-1, ih.maxaddr()) finally: os.remove(fname) def test_tobinarray_empty(self): ih = IntelHex() ih.padding = 0xFF # set-up explicit padding value and don't use pad parameter self.assertEqual(array.array('B', []), ih.tobinarray()) self.assertEqual(array.array('B', []), ih.tobinarray(start=0)) self.assertEqual(array.array('B', []), ih.tobinarray(end=2)) self.assertEqual(array.array('B', [255,255,255]), ih.tobinarray(0,2)) def test_tobinarray_with_size(self): ih = IntelHex(self.f) self.assertEqual(array.array('B', [2, 5, 162, 229, 118, 36, 106, 248]), ih.tobinarray(size=8)) # from addr 0 self.assertEqual(array.array('B', [120, 103, 48, 7, 2, 120, 106, 228]), ih.tobinarray(start=12, size=8)) self.assertEqual(array.array('B', [2, 5, 162, 229, 118, 36, 106, 248]), ih.tobinarray(end=7, size=8)) # addr: 0..7, 8 bytes self.assertEqual(array.array('B', [120, 103, 48, 7, 2, 120, 106, 228]), ih.tobinarray(end=19, size=8)) # addr: 12..19, 8 bytes self.assertRaises(ValueError, ih.tobinarray, start=0, end=7, size=8) self.assertRaises(ValueError, ih.tobinarray, end=3, size=8) self.assertRaises(ValueError, ih.tobinarray, size=0) self.assertRaises(ValueError, ih.tobinarray, size=-1) def test_tobinstr(self): ih = IntelHex(self.f) s1 = ih.tobinstr() s2 = array_tobytes(bin8) self.assertEqual(s2, s1, "data not equal\n%s\n\n%s" % (s1, s2)) def test_tobinfile(self): ih = IntelHex(self.f) sio = BytesIO() ih.tobinfile(sio) s1 = sio.getvalue() sio.close() s2 = array_tobytes(bin8) self.assertEqual(s2, s1, "data not equal\n%s\n\n%s" % (s1, s2)) # new API: .tofile universal method sio = BytesIO() ih.tofile(sio, format='bin') s1 = sio.getvalue() sio.close() s2 = array_tobytes(bin8) self.assertEqual(s2, s1, "data not equal\n%s\n\n%s" % (s1, s2)) def test_tobinfile_realfile(self): ih = IntelHex(self.f) tf = tempfile.TemporaryFile(mode='wb') try: ih.tobinfile(tf) finally: tf.close() def test__get_eol_textfile(self): self.assertEqual('\n', IntelHex._get_eol_textfile('native', 'win32')) self.assertEqual('\n', IntelHex._get_eol_textfile('native', 'linux')) self.assertEqual('\n', IntelHex._get_eol_textfile('CRLF', 'win32')) self.assertEqual('\r\n', IntelHex._get_eol_textfile('CRLF', 'linux')) self.assertRaisesMsg(ValueError, "wrong eolstyle 'LF'", IntelHex._get_eol_textfile, 'LF', 'win32') def test_write_empty_hexfile(self): ih = intelhex.IntelHex() sio = StringIO() ih.write_hex_file(sio) s = sio.getvalue() sio.close() self.assertEqualWrittenData(hex_empty_file, s) def test_write_hexfile(self): ih = intelhex.IntelHex(StringIO(hex_simple)) sio = StringIO() ih.write_hex_file(sio) s = sio.getvalue() sio.close() self.assertEqualWrittenData(hex_simple, s) # new API: .tofile universal method sio = StringIO() ih.tofile(sio, format='hex') s = sio.getvalue() sio.close() self.assertEqualWrittenData(hex_simple, s) def test_write_hex_bug_341051(self): ih = intelhex.IntelHex(StringIO(hex_bug_lp_341051)) sio = StringIO() ih.tofile(sio, format='hex') s = sio.getvalue() sio.close() self.assertEqualWrittenData(hex_bug_lp_341051, s) def test_write_hex_first_extended_linear_address(self): ih = IntelHex({0x20000: 0x01}) sio = StringIO() ih.write_hex_file(sio) s = sio.getvalue() sio.close() # should be r = [Record.extended_linear_address(2), Record.data(0x0000, [0x01]), Record.eof()] h = '\n'.join(r) + '\n' # compare self.assertEqual(h, s) def test_tofile_wrong_format(self): ih = IntelHex() sio = StringIO() self.assertRaises(ValueError, ih.tofile, sio, {'format': 'bad'}) def test_todict(self): ih = IntelHex() self.assertEqual({}, ih.todict()) ih = IntelHex(StringIO(hex64k)) self.assertEqual(data64k, ih.todict()) ih = IntelHex() ih[1] = 2 ih.start_addr = {'EIP': 1234} self.assertEqual({1: 2, 'start_addr': {'EIP': 1234}}, ih.todict()) def test_fromdict(self): ih = IntelHex() ih.fromdict({1:2, 3:4}) self.assertEqual({1:2, 3:4}, ih.todict()) ih.fromdict({1:5, 6:7}) self.assertEqual({1:5, 3:4, 6:7}, ih.todict()) ih = IntelHex() ih.fromdict({1: 2, 'start_addr': {'EIP': 1234}}) self.assertEqual({1: 2, 'start_addr': {'EIP': 1234}}, ih.todict()) # bad dict self.assertRaises(ValueError, ih.fromdict, {'EIP': 1234}) self.assertRaises(ValueError, ih.fromdict, {-1: 1234}) def test_init_from_obj(self): ih = IntelHex({1:2, 3:4}) self.assertEqual({1:2, 3:4}, ih.todict()) ih.start_addr = {'EIP': 1234} ih2 = IntelHex(ih) ih[1] = 5 ih.start_addr = {'EIP': 5678} self.assertEqual({1:2, 3:4, 'start_addr': {'EIP': 1234}}, ih2.todict()) self.assertNotEqual(id(ih), id(ih2)) def test_dict_interface(self): ih = IntelHex() self.assertEqual(0xFF, ih[0]) # padding byte substitution ih[0] = 1 self.assertEqual(1, ih[0]) del ih[0] self.assertEqual({}, ih.todict()) # padding byte substitution def test_len(self): ih = IntelHex() self.assertEqual(0, len(ih)) ih[2] = 1 self.assertEqual(1, len(ih)) ih[1000] = 2 self.assertEqual(2, len(ih)) def test__getitem__(self): ih = IntelHex() # simple cases self.assertEqual(0xFF, ih[0]) ih[0] = 1 self.assertEqual(1, ih[0]) # big address self.assertEqual(0xFF, ih[2**32-1]) # wrong addr type/value for indexing operations def getitem(index): return ih[index] self.assertRaisesMsg(TypeError, 'Address should be >= 0.', getitem, -1) self.assertRaisesMsg(TypeError, "Address has unsupported type: %s" % type('foo'), getitem, 'foo') # new object with some data ih = IntelHex() ih[0] = 1 ih[1] = 2 ih[2] = 3 ih[10] = 4 # full copy via slicing ih2 = ih[:] self.assertTrue(isinstance(ih2, IntelHex)) self.assertEqual({0:1, 1:2, 2:3, 10:4}, ih2.todict()) # other slice operations self.assertEqual({}, ih[3:8].todict()) self.assertEqual({0:1, 1:2}, ih[0:2].todict()) self.assertEqual({0:1, 1:2}, ih[:2].todict()) self.assertEqual({2:3, 10:4}, ih[2:].todict()) self.assertEqual({0:1, 2:3, 10:4}, ih[::2].todict()) self.assertEqual({10:4}, ih[3:11].todict()) def test__setitem__(self): ih = IntelHex() # simple indexing operation ih[0] = 1 self.assertEqual({0:1}, ih.todict()) # errors def setitem(a,b): ih[a] = b self.assertRaisesMsg(TypeError, 'Address should be >= 0.', setitem, -1, 0) self.assertRaisesMsg(TypeError, "Address has unsupported type: %s" % type('foo'), setitem, 'foo', 0) # slice operations ih[0:4] = range_l(4) self.assertEqual({0:0, 1:1, 2:2, 3:3}, ih.todict()) ih[0:] = range_l(5,9) self.assertEqual({0:5, 1:6, 2:7, 3:8}, ih.todict()) ih[:4] = range_l(9,13) self.assertEqual({0:9, 1:10, 2:11, 3:12}, ih.todict()) # with step ih = IntelHex() ih[0:8:2] = range_l(4) self.assertEqual({0:0, 2:1, 4:2, 6:3}, ih.todict()) # errors in slice operations # ih[1:2] = 'a' self.assertRaisesMsg(ValueError, 'Slice operation expects sequence of bytes', setitem, slice(1,2,None), 'a') # ih[0:1] = [1,2,3] self.assertRaisesMsg(ValueError, 'Length of bytes sequence does not match address range', setitem, slice(0,1,None), [1,2,3]) # ih[:] = [1,2,3] self.assertRaisesMsg(TypeError, 'Unsupported address range', setitem, slice(None,None,None), [1,2,3]) # ih[:2] = [1,2,3] self.assertRaisesMsg(TypeError, 'start address cannot be negative', setitem, slice(None,2,None), [1,2,3]) # ih[0:-3:-1] = [1,2,3] self.assertRaisesMsg(TypeError, 'stop address cannot be negative', setitem, slice(0,-3,-1), [1,2,3]) def test__delitem__(self): ih = IntelHex() ih[0] = 1 del ih[0] self.assertEqual({}, ih.todict()) # errors def delitem(addr): del ih[addr] self.assertRaises(KeyError, delitem, 1) self.assertRaisesMsg(TypeError, 'Address should be >= 0.', delitem, -1) self.assertRaisesMsg(TypeError, "Address has unsupported type: %s" % type('foo'), delitem, 'foo') # deleting slice del ih[0:1] # no error here because of slicing # def ihex(size=8): ih = IntelHex() for i in range_g(size): ih[i] = i return ih ih = ihex(8) del ih[:] # delete all data self.assertEqual({}, ih.todict()) ih = ihex(8) del ih[2:6] self.assertEqual({0:0, 1:1, 6:6, 7:7}, ih.todict()) ih = ihex(8) del ih[::2] self.assertEqual({1:1, 3:3, 5:5, 7:7}, ih.todict()) def test_addresses(self): # empty object ih = IntelHex() self.assertEqual([], ih.addresses()) self.assertEqual(None, ih.minaddr()) self.assertEqual(None, ih.maxaddr()) # normal object ih = IntelHex({1:2, 7:8, 10:0}) self.assertEqual([1,7,10], ih.addresses()) self.assertEqual(1, ih.minaddr()) self.assertEqual(10, ih.maxaddr()) def test__get_start_end(self): # test for private method _get_start_end # for empty object ih = IntelHex() self.assertRaises(intelhex.EmptyIntelHexError, ih._get_start_end) self.assertRaises(intelhex.EmptyIntelHexError, ih._get_start_end, size=10) self.assertEqual((0,9), ih._get_start_end(start=0, size=10)) self.assertEqual((1,10), ih._get_start_end(end=10, size=10)) # normal object ih = IntelHex({1:2, 7:8, 10:0}) self.assertEqual((1,10), ih._get_start_end()) self.assertEqual((1,10), ih._get_start_end(size=10)) self.assertEqual((0,9), ih._get_start_end(start=0, size=10)) self.assertEqual((1,10), ih._get_start_end(end=10, size=10)) def test_segments(self): # test that address segments are correctly summarized ih = IntelHex() sg = ih.segments() self.assertTrue(isinstance(sg, list)) self.assertEqual(len(sg), 0) ih[0x100] = 0 sg = ih.segments() self.assertTrue(isinstance(sg, list)) self.assertEqual(len(sg), 1) self.assertTrue(isinstance(sg[0], tuple)) self.assertTrue(len(sg[0]) == 2) self.assertTrue(sg[0][0] < sg[0][1]) self.assertEqual(min(sg[0]), 0x100) self.assertEqual(max(sg[0]), 0x101) ih[0x101] = 1 sg = ih.segments() self.assertTrue(isinstance(sg, list)) self.assertEqual(len(sg), 1) self.assertTrue(isinstance(sg[0], tuple)) self.assertTrue(len(sg[0]) == 2) self.assertTrue(sg[0][0] < sg[0][1]) self.assertEqual(min(sg[0]), 0x100) self.assertEqual(max(sg[0]), 0x102) ih[0x200] = 2 ih[0x201] = 3 ih[0x202] = 4 sg = ih.segments() self.assertTrue(isinstance(sg, list)) self.assertEqual(len(sg), 2) self.assertTrue(isinstance(sg[0], tuple)) self.assertTrue(len(sg[0]) == 2) self.assertTrue(sg[0][0] < sg[0][1]) self.assertTrue(isinstance(sg[1], tuple)) self.assertTrue(len(sg[1]) == 2) self.assertTrue(sg[1][0] < sg[1][1]) self.assertEqual(min(sg[0]), 0x100) self.assertEqual(max(sg[0]), 0x102) self.assertEqual(min(sg[1]), 0x200) self.assertEqual(max(sg[1]), 0x203) pass class TestIntelHexLoadBin(TestIntelHexBase): def setUp(self): self.bytes = asbytes('0123456789') self.f = BytesIO(self.bytes) def tearDown(self): self.f.close() def test_loadbin(self): ih = IntelHex() ih.loadbin(self.f) self.assertEqual(0, ih.minaddr()) self.assertEqual(9, ih.maxaddr()) self.assertEqual(self.bytes, ih.tobinstr()) def test_bin_fromfile(self): ih = IntelHex() ih.fromfile(self.f, format='bin') self.assertEqual(0, ih.minaddr()) self.assertEqual(9, ih.maxaddr()) self.assertEqual(self.bytes, ih.tobinstr()) def test_loadbin_w_offset(self): ih = IntelHex() ih.loadbin(self.f, offset=100) self.assertEqual(100, ih.minaddr()) self.assertEqual(109, ih.maxaddr()) self.assertEqual(self.bytes, ih.tobinstr()) def test_loadfile_format_bin(self): ih = IntelHex() ih.loadfile(self.f, format='bin') self.assertEqual(0, ih.minaddr()) self.assertEqual(9, ih.maxaddr()) self.assertEqual(self.bytes, ih.tobinstr()) class TestIntelHexStartingAddressRecords(TestIntelHexBase): def _test_read(self, hexstr, data, start_addr): sio = StringIO(hexstr) ih = IntelHex(sio) sio.close() # test data self.assertEqual(data, ih._buf, "Internal buffer: %r != %r" % (data, ih._buf)) self.assertEqual(start_addr, ih.start_addr, "Start address: %r != %r" % (start_addr, ih.start_addr)) def test_read_rectype3(self): self._test_read(hex_rectype3, data_rectype3, start_addr_rectype3) def test_read_rectype5(self): self._test_read(hex_rectype5, data_rectype5, start_addr_rectype5) def _test_write(self, hexstr, data, start_addr, write_start_addr=True): # prepare ih = IntelHex(None) ih._buf = data ih.start_addr = start_addr # write sio = StringIO() ih.write_hex_file(sio, write_start_addr) s = sio.getvalue() sio.close() # check self.assertEqualWrittenData(hexstr, s) def _test_dont_write(self, hexstr, data, start_addr): expected = ''.join(hexstr.splitlines(True)[1:]) self._test_write(expected, data, start_addr, False) def test_write_rectype3(self): self._test_write(hex_rectype3, data_rectype3, start_addr_rectype3) def test_dont_write_rectype3(self): self._test_dont_write(hex_rectype3, data_rectype3, start_addr_rectype3) def test_write_rectype5(self): self._test_write(hex_rectype5, data_rectype5, start_addr_rectype5) def test_dont_write_rectype5(self): self._test_dont_write(hex_rectype5, data_rectype5, start_addr_rectype5) def test_write_invalid_start_addr_value(self): ih = IntelHex() ih.start_addr = {'foo': 1} sio = StringIO() self.assertRaises(InvalidStartAddressValueError, ih.write_hex_file, sio) class TestIntelHex_big_files(TestIntelHexBase): """Test that data bigger than 64K read/write correctly""" def setUp(self): self.f = StringIO(hex64k) def tearDown(self): self.f.close() del self.f def test_readfile(self): ih = intelhex.IntelHex(self.f) for addr, byte in dict_items_g(data64k): readed = ih[addr] self.assertEqual(byte, readed, "data not equal at addr %X " "(%X != %X)" % (addr, byte, readed)) def test_write_hex_file(self): ih = intelhex.IntelHex(self.f) sio = StringIO() ih.write_hex_file(sio) s = sio.getvalue() sio.close() self.assertEqualWrittenData(hex64k, s) class TestIntelHexGetPutString(TestIntelHexBase): def setUp(self): self.ih = IntelHex() for i in range_g(10): self.ih[i] = i def test_gets(self): self.assertEqual(asbytes('\x00\x01\x02\x03\x04\x05\x06\x07'), self.ih.gets(0, 8)) self.assertEqual(asbytes('\x07\x08\x09'), self.ih.gets(7, 3)) self.assertRaisesMsg(intelhex.NotEnoughDataError, 'Bad access at 0x1: ' 'not enough data to read 10 contiguous bytes', self.ih.gets, 1, 10) def test_puts(self): self.ih.puts(0x03, asbytes('hello')) self.assertEqual(asbytes('\x00\x01\x02hello\x08\x09'), self.ih.gets(0, 10)) def test_getsz(self): self.assertEqual(asbytes(''), self.ih.getsz(0)) self.assertRaisesMsg(intelhex.NotEnoughDataError, 'Bad access at 0x1: ' 'not enough data to read zero-terminated string', self.ih.getsz, 1) self.ih[4] = 0 self.assertEqual(asbytes('\x01\x02\x03'), self.ih.getsz(1)) def test_putsz(self): self.ih.putsz(0x03, asbytes('hello')) self.assertEqual(asbytes('\x00\x01\x02hello\x00\x09'), self.ih.gets(0, 10)) class TestIntelHexDump(TestIntelHexBase): def test_empty(self): ih = IntelHex() sio = StringIO() ih.dump(sio) self.assertEqual('', sio.getvalue()) def test_simple(self): ih = IntelHex() ih[0] = 0x12 ih[1] = 0x34 sio = StringIO() ih.dump(sio) self.assertEqual( '0000 12 34 -- -- -- -- -- -- -- -- -- -- -- -- -- -- |.4 |\n', sio.getvalue()) ih[16] = 0x56 ih[30] = 0x98 sio = StringIO() ih.dump(sio) self.assertEqual( '0000 12 34 -- -- -- -- -- -- -- -- -- -- -- -- -- -- |.4 |\n' '0010 56 -- -- -- -- -- -- -- -- -- -- -- -- -- 98 -- |V . |\n', sio.getvalue()) def test_minaddr_not_zero(self): ih = IntelHex() ih[16] = 0x56 ih[30] = 0x98 sio = StringIO() ih.dump(sio) self.assertEqual( '0010 56 -- -- -- -- -- -- -- -- -- -- -- -- -- 98 -- |V . |\n', sio.getvalue()) def test_start_addr(self): ih = IntelHex() ih[0] = 0x12 ih[1] = 0x34 ih.start_addr = {'CS': 0x1234, 'IP': 0x5678} sio = StringIO() ih.dump(sio) self.assertEqual( 'CS = 0x1234, IP = 0x5678\n' '0000 12 34 -- -- -- -- -- -- -- -- -- -- -- -- -- -- |.4 |\n', sio.getvalue()) ih.start_addr = {'EIP': 0x12345678} sio = StringIO() ih.dump(sio) self.assertEqual( 'EIP = 0x12345678\n' '0000 12 34 -- -- -- -- -- -- -- -- -- -- -- -- -- -- |.4 |\n', sio.getvalue()) def test_bad_width(self): ih = IntelHex() sio = StringIO() badwidths = [0, -1, -10.5, 2.5] for bw in badwidths: self.assertRaisesMsg(ValueError, "width must be a positive integer.", ih.dump, sio, bw) badwidthtypes = ['', {}, [], sio] for bwt in badwidthtypes: self.assertRaisesMsg(ValueError, "width must be a positive integer.", ih.dump, sio, bwt) def test_simple_width3(self): ih = IntelHex() ih[0] = 0x12 ih[1] = 0x34 sio = StringIO() ih.dump(tofile=sio, width=3) self.assertEqual( '0000 12 34 -- |.4 |\n', sio.getvalue()) ih[16] = 0x56 ih[30] = 0x98 sio = StringIO() ih.dump(tofile=sio, width=3) self.assertEqual( '0000 12 34 -- |.4 |\n' '0003 -- -- -- | |\n' '0006 -- -- -- | |\n' '0009 -- -- -- | |\n' '000C -- -- -- | |\n' '000F -- 56 -- | V |\n' '0012 -- -- -- | |\n' '0015 -- -- -- | |\n' '0018 -- -- -- | |\n' '001B -- -- -- | |\n' '001E 98 -- -- |. |\n', sio.getvalue()) def test_minaddr_not_zero_width3_padding(self): ih = IntelHex() ih[17] = 0x56 ih[30] = 0x98 sio = StringIO() ih.dump(tofile=sio, width=3, withpadding=True) self.assertEqual( '000F FF FF 56 |..V|\n' '0012 FF FF FF |...|\n' '0015 FF FF FF |...|\n' '0018 FF FF FF |...|\n' '001B FF FF FF |...|\n' '001E 98 FF FF |...|\n', sio.getvalue()) class TestIntelHexMerge(TestIntelHexBase): def test_merge_empty(self): ih1 = IntelHex() ih2 = IntelHex() ih1.merge(ih2) self.assertEqual({}, ih1.todict()) def test_merge_simple(self): ih1 = IntelHex({0:1, 1:2, 2:3}) ih2 = IntelHex({3:4, 4:5, 5:6}) ih1.merge(ih2) self.assertEqual({0:1, 1:2, 2:3, 3:4, 4:5, 5:6}, ih1.todict()) def test_merge_wrong_args(self): ih1 = IntelHex() self.assertRaisesMsg(TypeError, 'other should be IntelHex object', ih1.merge, {0:1}) self.assertRaisesMsg(ValueError, "Can't merge itself", ih1.merge, ih1) ih2 = IntelHex() self.assertRaisesMsg(ValueError, "overlap argument should be either " "'error', 'ignore' or 'replace'", ih1.merge, ih2, overlap='spam') def test_merge_overlap(self): # error ih1 = IntelHex({0:1}) ih2 = IntelHex({0:2}) self.assertRaisesMsg(intelhex.AddressOverlapError, 'Data overlapped at address 0x0', ih1.merge, ih2, overlap='error') # ignore ih1 = IntelHex({0:1}) ih2 = IntelHex({0:2}) ih1.merge(ih2, overlap='ignore') self.assertEqual({0:1}, ih1.todict()) # replace ih1 = IntelHex({0:1}) ih2 = IntelHex({0:2}) ih1.merge(ih2, overlap='replace') self.assertEqual({0:2}, ih1.todict()) def test_merge_start_addr(self): # this, None ih1 = IntelHex({'start_addr': {'EIP': 0x12345678}}) ih2 = IntelHex() ih1.merge(ih2) self.assertEqual({'start_addr': {'EIP': 0x12345678}}, ih1.todict()) # None, other ih1 = IntelHex() ih2 = IntelHex({'start_addr': {'EIP': 0x12345678}}) ih1.merge(ih2) self.assertEqual({'start_addr': {'EIP': 0x12345678}}, ih1.todict()) # this == other: no conflict ih1 = IntelHex({'start_addr': {'EIP': 0x12345678}}) ih2 = IntelHex({'start_addr': {'EIP': 0x12345678}}) ih1.merge(ih2) self.assertEqual({'start_addr': {'EIP': 0x12345678}}, ih1.todict()) # this != other: conflict ## overlap=error ih1 = IntelHex({'start_addr': {'EIP': 0x12345678}}) ih2 = IntelHex({'start_addr': {'EIP': 0x87654321}}) self.assertRaisesMsg(AddressOverlapError, 'Starting addresses are different', ih1.merge, ih2, overlap='error') ## overlap=ignore ih1 = IntelHex({'start_addr': {'EIP': 0x12345678}}) ih2 = IntelHex({'start_addr': {'EIP': 0x87654321}}) ih1.merge(ih2, overlap='ignore') self.assertEqual({'start_addr': {'EIP': 0x12345678}}, ih1.todict()) ## overlap=replace ih1 = IntelHex({'start_addr': {'EIP': 0x12345678}}) ih2 = IntelHex({'start_addr': {'EIP': 0x87654321}}) ih1.merge(ih2, overlap='replace') self.assertEqual({'start_addr': {'EIP': 0x87654321}}, ih1.todict()) class TestIntelHex16bit(TestIntelHexBase): def setUp(self): self.f = StringIO(hex16) def tearDown(self): self.f.close() del self.f def test_init_from_file(self): ih = intelhex.IntelHex16bit(self.f) def test_init_from_ih(self): ih = intelhex.IntelHex(self.f) ih16 = intelhex.IntelHex16bit(ih) def test_default_padding(self): ih16 = intelhex.IntelHex16bit() self.assertEqual(0x0FFFF, ih16.padding) self.assertEqual(0x0FFFF, ih16[0]) def test_minaddr(self): ih = intelhex.IntelHex16bit(self.f) addr = ih.minaddr() self.assertEqual(0, addr, 'Error in detection of minaddr (0 != 0x%x)' % addr) def test_maxaddr(self): ih = intelhex.IntelHex16bit(self.f) addr = ih.maxaddr() self.assertEqual(0x001D, addr, 'Error in detection of maxaddr ' '(0x001D != 0x%x)' % addr) def test_getitem(self): ih = intelhex.IntelHex16bit(self.f) ih.padding = 0x3FFF for addr, word in enumerate(bin16): self.assertEqual(word, ih[addr], 'Data mismatch at address ' '0x%x (0x%x != 0x%x)' % (addr, word, ih[addr])) def test_not_enough_data(self): ih = intelhex.IntelHex() ih[0] = 1 ih16 = intelhex.IntelHex16bit(ih) self.assertRaisesMsg(BadAccess16bit, 'Bad access at 0x0: ' 'not enough data to read 16 bit value', lambda x: ih16[x], 0) def test_write_hex_file(self): ih = intelhex.IntelHex16bit(self.f) sio = StringIO() ih.write_hex_file(sio) s = sio.getvalue() sio.close() fin = StringIO(s) ih2 = intelhex.IntelHex16bit(fin) self.assertEqual(ih.tobinstr(), ih2.tobinstr(), "Written hex file does not equal with original") def test_bug_988148(self): # see https://bugs.launchpad.net/intelhex/+bug/988148 ih = intelhex.IntelHex16bit(intelhex.IntelHex()) ih[0] = 25 sio = StringIO() ih.write_hex_file(sio) def test_setitem(self): ih = intelhex.IntelHex16bit(self.f) old = ih[0] ih[0] = old ^ 0xFFFF self.assertNotEqual(old, ih[0], "Setting new value to internal buffer failed") def test_tobinarray(self): ih = intelhex.IntelHex16bit() ih[0] = 0x1234 ih[1] = 0x5678 self.assertEqual(array.array('H', [0x1234,0x5678,0xFFFF]), ih.tobinarray(start=0, end=2)) # change padding ih.padding = 0x3FFF self.assertEqual(array.array('H', [0x1234,0x5678,0x3FFF]), ih.tobinarray(start=0, end=2)) #/class TestIntelHex16bit class TestIntelHexErrors(TestIntelHexBase): """Tests for custom errors classes""" def assertEqualExc(self, message, exception): return self.assertEqual(message, str(exception)) def test_IntelHexError(self): self.assertEqualExc('IntelHex base error', IntelHexError()) def test_IntelHexError_message(self): self.assertEqualExc('IntelHex custom error message', IntelHexError(msg='IntelHex custom error message')) self.assertEqualExc('IntelHex base error', IntelHexError(msg='')) def test_HexReaderError(self): self.assertEqualExc('Hex reader base error', HexReaderError()) def test_HexRecordError(self): self.assertEqualExc('Hex file contains invalid record at line 1', HexRecordError(line=1)) def test_RecordLengthError(self): self.assertEqualExc('Record at line 1 has invalid length', RecordLengthError(line=1)) def test_RecordTypeError(self): self.assertEqualExc('Record at line 1 has invalid record type', RecordTypeError(line=1)) def test_RecordChecksumError(self): self.assertEqualExc('Record at line 1 has invalid checksum', RecordChecksumError(line=1)) def test_EOFRecordError(self): self.assertEqualExc('File has invalid End-of-File record', EOFRecordError()) def test_ExtendedSegmentAddressRecordError(self): self.assertEqualExc( 'Invalid Extended Segment Address Record at line 1', ExtendedSegmentAddressRecordError(line=1)) def test_ExtendedLinearAddressRecordError(self): self.assertEqualExc('Invalid Extended Linear Address Record at line 1', ExtendedLinearAddressRecordError(line=1)) def test_StartSegmentAddressRecordError(self): self.assertEqualExc('Invalid Start Segment Address Record at line 1', StartSegmentAddressRecordError(line=1)) def test_StartLinearAddressRecordError(self): self.assertEqualExc('Invalid Start Linear Address Record at line 1', StartLinearAddressRecordError(line=1)) def test_DuplicateStartAddressRecord(self): self.assertEqualExc('Start Address Record appears twice at line 1', DuplicateStartAddressRecordError(line=1)) def test_InvalidStartAddressValue(self): self.assertEqualExc("Invalid start address value: {'foo': 1}", InvalidStartAddressValueError(start_addr={'foo': 1})) def test_AddressOverlapError(self): self.assertEqualExc('Hex file has data overlap at address 0x1234 ' 'on line 1', AddressOverlapError(address=0x1234, line=1)) def test_NotEnoughDataError(self): self.assertEqualExc('Bad access at 0x1234: ' 'not enough data to read 10 contiguous bytes', intelhex.NotEnoughDataError(address=0x1234, length=10)) def test_BadAccess16bit(self): self.assertEqualExc('Bad access at 0x1234: ' 'not enough data to read 16 bit value', BadAccess16bit(address=0x1234)) #/class TestIntelHexErrors class TestDecodeHexRecords(TestIntelHexBase): """Testing that decoding of records is correct and all errors raised when needed """ def setUp(self): self.ih = IntelHex() self.decode_record = self.ih._decode_record def tearDown(self): del self.ih def test_empty_line(self): # do we could to accept empty lines in hex files? # standard don't say anything about this self.decode_record('') def test_non_empty_line(self): self.assertRaisesMsg(HexRecordError, 'Hex file contains invalid record at line 1', self.decode_record, ' ', 1) def test_short_record(self): # if record too short it's not a hex record self.assertRaisesMsg(HexRecordError, 'Hex file contains invalid record at line 1', self.decode_record, ':', 1) def test_odd_hexascii_digits(self): self.assertRaisesMsg(HexRecordError, 'Hex file contains invalid record at line 1', self.decode_record, ':0100000100F', 1) def test_invalid_length(self): self.assertRaisesMsg(RecordLengthError, 'Record at line 1 has invalid length', self.decode_record, ':FF00000100', 1) def test_invalid_record_type(self): self.assertRaisesMsg(RecordTypeError, 'Record at line 1 has invalid record type', self.decode_record, ':000000FF01', 1) def test_invalid_checksum(self): self.assertRaisesMsg(RecordChecksumError, 'Record at line 1 has invalid checksum', self.decode_record, ':0000000100', 1) def test_invalid_eof(self): self.assertRaisesMsg(EOFRecordError, 'File has invalid End-of-File record', self.decode_record, ':0100000100FE', 1) def test_invalid_extended_segment(self): # length self.assertRaisesMsg(ExtendedSegmentAddressRecordError, 'Invalid Extended Segment Address Record at line 1', self.decode_record, ':00000002FE', 1) # addr field self.assertRaisesMsg(ExtendedSegmentAddressRecordError, 'Invalid Extended Segment Address Record at line 1', self.decode_record, ':020001020000FB', 1) def test_invalid_linear_address(self): # length self.assertRaisesMsg(ExtendedLinearAddressRecordError, 'Invalid Extended Linear Address Record ' 'at line 1', self.decode_record, ':00000004FC', 1) # addr field self.assertRaisesMsg(ExtendedLinearAddressRecordError, 'Invalid Extended Linear Address Record ' 'at line 1', self.decode_record, ':020001040000F9', 1) def test_invalid_start_segment_addr(self): # length self.assertRaisesMsg(StartSegmentAddressRecordError, 'Invalid Start Segment Address Record at line 1', self.decode_record, ':00000003FD', 1) # addr field self.assertRaisesMsg(StartSegmentAddressRecordError, 'Invalid Start Segment Address Record at line 1', self.decode_record, ':0400010300000000F8', 1) def test_duplicate_start_segment_addr(self): self.decode_record(':0400000312345678E5') self.assertRaisesMsg(DuplicateStartAddressRecordError, 'Start Address Record appears twice at line 2', self.decode_record, ':0400000300000000F9', 2) def test_invalid_start_linear_addr(self): # length self.assertRaisesMsg(StartLinearAddressRecordError, 'Invalid Start Linear Address Record at line 1', self.decode_record, ':00000005FB', 1) # addr field self.assertRaisesMsg(StartLinearAddressRecordError, 'Invalid Start Linear Address Record at line 1', self.decode_record, ':0400010500000000F6', 1) def test_duplicate_start_linear_addr(self): self.decode_record(':0400000512345678E3') self.assertRaisesMsg(DuplicateStartAddressRecordError, 'Start Address Record appears twice at line 2', self.decode_record, ':0400000500000000F7', 2) def test_addr_overlap(self): self.decode_record(':0100000000FF') self.assertRaisesMsg(AddressOverlapError, 'Hex file has data overlap at address 0x0 ' 'on line 1', self.decode_record, ':0100000000FF', 1) def test_data_record(self): # should be no exceptions self.decode_record(':0100000000FF\n') self.decode_record(':03000100000102F9\r\n') self.decode_record(':1004E300CFF0FBE2FDF220FF20F2E120E2FBE6F396') def test_eof(self): # EOF should raise special exception self.assertRaises(_EndOfFile, self.decode_record, ':00000001FF') #/class TestDecodeHexRecords class TestHex2Bin(unittest.TestCase): def setUp(self): self.fin = StringIO(hex8) self.fout = BytesIO() def tearDown(self): self.fin.close() self.fout.close() def test_hex2bin(self): ih = hex2bin(self.fin, self.fout) data = array.array('B', asbytes(self.fout.getvalue())) for addr in range_g(len(bin8)): expected = bin8[addr] actual = data[addr] self.assertEqual(expected, actual, "Data different at address " "%x (%x != %x)" % (addr, expected, actual)) class TestDiffDumps(unittest.TestCase): def test_simple(self): ih1 = IntelHex({1:0x30, 20:0x31, 40:0x33}) ih2 = IntelHex({1:0x30, 20:0x32, 40:0x33}) sio = StringIO() intelhex.diff_dumps(ih1, ih2, sio) result = sio.getvalue() extra = ' ' if sys.version_info[0] >= 3 or sys.version >= '2.7': extra = '' shouldbe = ( "--- a%(extra)s\n" "+++ b%(extra)s\n" "@@ -1,3 +1,3 @@\n" " 0000 -- 30 -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 0 |\n" "-0010 -- -- -- -- 31 -- -- -- -- -- -- -- -- -- -- -- | 1 |\n" "+0010 -- -- -- -- 32 -- -- -- -- -- -- -- -- -- -- -- | 2 |\n" " 0020 -- -- -- -- -- -- -- -- 33 -- -- -- -- -- -- -- | 3 |\n" ) % dict(extra=extra) self.assertEqual(shouldbe, result) class TestBuildRecords(TestIntelHexBase): def test__from_bytes(self): self.assertEqual(':00000001FF', intelhex.Record._from_bytes([0,0,0,1])) def test_data(self): self.assertEqual(':011234005663', intelhex.Record.data(0x1234, [0x56])) self.assertEqual(':0312340056789059', intelhex.Record.data(0x1234, [0x56, 0x78, 0x90])) def test_eof(self): self.assertEqual(':00000001FF', intelhex.Record.eof()) def test_extended_segment_address(self): self.assertEqual(':020000021234B6', intelhex.Record.extended_segment_address(0x1234)) def test_start_segment_address(self): self.assertEqual(':0400000312345678E5', intelhex.Record.start_segment_address(0x1234, 0x5678)) def test_extended_linear_address(self): self.assertEqual(':020000041234B4', intelhex.Record.extended_linear_address(0x1234)) def test_start_linear_address(self): self.assertEqual(':0400000512345678E3', intelhex.Record.start_linear_address(0x12345678)) class Test_GetFileAndAddrRange(TestIntelHexBase): def test_simple(self): self.assertEqual(('filename.hex', None, None), intelhex._get_file_and_addr_range('filename.hex')) self.assertEqual(('f', None, None), intelhex._get_file_and_addr_range('f')) self.assertEqual(('filename.hex', 1, None), intelhex._get_file_and_addr_range('filename.hex:1:')) self.assertEqual(('filename.hex', None, 10), intelhex._get_file_and_addr_range('filename.hex::A')) self.assertEqual(('filename.hex', 1, 10), intelhex._get_file_and_addr_range('filename.hex:1:A')) self.assertEqual(('filename.hex', 1, 10), intelhex._get_file_and_addr_range('filename.hex:0001:000A')) def test_bad_notation(self): self.assertRaises(intelhex._BadFileNotation, intelhex._get_file_and_addr_range, 'filename.hex:') self.assertRaises(intelhex._BadFileNotation, intelhex._get_file_and_addr_range, 'filename.hex:::') self.assertRaises(intelhex._BadFileNotation, intelhex._get_file_and_addr_range, 'C:\\filename.hex:', True) def test_drive_letter(self): self.assertEqual(('C:\\filename.hex', None, None), intelhex._get_file_and_addr_range('C:\\filename.hex', True)) self.assertEqual(('C:\\filename.hex', 1, None), intelhex._get_file_and_addr_range('C:\\filename.hex:1:', True)) self.assertEqual(('C:\\filename.hex', None, 10), intelhex._get_file_and_addr_range('C:\\filename.hex::A', True)) self.assertEqual(('C:\\filename.hex', 1, 10), intelhex._get_file_and_addr_range('C:\\filename.hex:1:A', True)) self.assertEqual(('C:\\filename.hex', 1, 10), intelhex._get_file_and_addr_range('C:\\filename.hex:0001:000A', True)) class TestXrangeLongInt(unittest.TestCase): def test_xrange_longint(self): # Bug #1408934: xrange(longint) blows with OverflowError: if compat.Python == 2: self.assertRaises(OverflowError, xrange, sys.maxint, sys.maxint+3) # upr = compat.range_g(2684625744, 2684625747) self.assertEqual([2684625744, 2684625745, 2684625746], list(upr)) upr = compat.range_g(2684625744, 2684625747, 2) self.assertEqual([2684625744, 2684625746], list(upr)) # dnr = compat.range_g(2684625746, 2684625743, -1) self.assertEqual([2684625746, 2684625745, 2684625744], list(dnr)) dnr = compat.range_g(2684625746, 2684625743, -2) self.assertEqual([2684625746, 2684625744], list(dnr)) class TestInSubprocess(unittest.TestCase): def runProcessAndGetAsciiStdoutOrStderr(self, cmdline): if sys.platform != 'win32': cmdline = shlex.split(cmdline) p = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() retcode = p.poll() if stdout: output = stdout.decode('ascii', 'replace') elif stderr: output = stderr.decode('ascii', 'replace') output = output.replace('\r', '') return retcode, output def versionChecker(self, cmdline_template): cmdline = cmdline_template % sys.executable retcode, output = self.runProcessAndGetAsciiStdoutOrStderr(cmdline) self.assertEqual(version_str, output.rstrip()) self.assertEqual(0, retcode) def test_setup_version(self): self.versionChecker('%s setup.py --version') def test_sripts_bin2hex_version(self): self.versionChecker('%s scripts/bin2hex.py --version') def test_sripts_hex2bin_version(self): self.versionChecker('%s scripts/hex2bin.py --version') def test_sripts_hex2dump_version(self): self.versionChecker('%s scripts/hex2dump.py --version') def test_sripts_hexdiff_version(self): self.versionChecker('%s scripts/hexdiff.py --version') def test_sripts_hexmerge_version(self): self.versionChecker('%s scripts/hexmerge.py --version') ## # MAIN if __name__ == '__main__': unittest.main() intelhex-2.1/intelhex/__init__.py0000644000175200017530000014353613147236475017712 0ustar builddbuildd00000000000000# Copyright (c) 2005-2016, Alexander Belchenko # All rights reserved. # # 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 the author 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. '''Intel HEX format manipulation library.''' __docformat__ = "javadoc" from array import array from binascii import hexlify, unhexlify from bisect import bisect_right import os import sys from intelhex.compat import ( IntTypes, StrType, StringIO, array_tobytes, asbytes, asstr, dict_items_g, dict_keys, dict_keys_g, range_g, range_l, ) from intelhex.getsizeof import total_size class _DeprecatedParam(object): pass _DEPRECATED = _DeprecatedParam() class IntelHex(object): ''' Intel HEX file reader. ''' def __init__(self, source=None): ''' Constructor. If source specified, object will be initialized with the contents of source. Otherwise the object will be empty. @param source source for initialization (file name of HEX file, file object, addr dict or other IntelHex object) ''' # public members self.padding = 0x0FF # Start Address self.start_addr = None # private members self._buf = {} self._offset = 0 if source is not None: if isinstance(source, StrType) or getattr(source, "read", None): # load hex file self.loadhex(source) elif isinstance(source, dict): self.fromdict(source) elif isinstance(source, IntelHex): self.padding = source.padding if source.start_addr: self.start_addr = source.start_addr.copy() self._buf = source._buf.copy() else: raise ValueError("source: bad initializer type") def _decode_record(self, s, line=0): '''Decode one record of HEX file. @param s line with HEX record. @param line line number (for error messages). @raise EndOfFile if EOF record encountered. ''' s = s.rstrip('\r\n') if not s: return # empty line if s[0] == ':': try: bin = array('B', unhexlify(asbytes(s[1:]))) except (TypeError, ValueError): # this might be raised by unhexlify when odd hexascii digits raise HexRecordError(line=line) length = len(bin) if length < 5: raise HexRecordError(line=line) else: raise HexRecordError(line=line) record_length = bin[0] if length != (5 + record_length): raise RecordLengthError(line=line) addr = bin[1]*256 + bin[2] record_type = bin[3] if not (0 <= record_type <= 5): raise RecordTypeError(line=line) crc = sum(bin) crc &= 0x0FF if crc != 0: raise RecordChecksumError(line=line) if record_type == 0: # data record addr += self._offset for i in range_g(4, 4+record_length): if not self._buf.get(addr, None) is None: raise AddressOverlapError(address=addr, line=line) self._buf[addr] = bin[i] addr += 1 # FIXME: addr should be wrapped # BUT after 02 record (at 64K boundary) # and after 04 record (at 4G boundary) elif record_type == 1: # end of file record if record_length != 0: raise EOFRecordError(line=line) raise _EndOfFile elif record_type == 2: # Extended 8086 Segment Record if record_length != 2 or addr != 0: raise ExtendedSegmentAddressRecordError(line=line) self._offset = (bin[4]*256 + bin[5]) * 16 elif record_type == 4: # Extended Linear Address Record if record_length != 2 or addr != 0: raise ExtendedLinearAddressRecordError(line=line) self._offset = (bin[4]*256 + bin[5]) * 65536 elif record_type == 3: # Start Segment Address Record if record_length != 4 or addr != 0: raise StartSegmentAddressRecordError(line=line) if self.start_addr: raise DuplicateStartAddressRecordError(line=line) self.start_addr = {'CS': bin[4]*256 + bin[5], 'IP': bin[6]*256 + bin[7], } elif record_type == 5: # Start Linear Address Record if record_length != 4 or addr != 0: raise StartLinearAddressRecordError(line=line) if self.start_addr: raise DuplicateStartAddressRecordError(line=line) self.start_addr = {'EIP': (bin[4]*16777216 + bin[5]*65536 + bin[6]*256 + bin[7]), } def loadhex(self, fobj): """Load hex file into internal buffer. This is not necessary if object was initialized with source set. This will overwrite addresses if object was already initialized. @param fobj file name or file-like object """ if getattr(fobj, "read", None) is None: fobj = open(fobj, "r") fclose = fobj.close else: fclose = None self._offset = 0 line = 0 try: decode = self._decode_record try: for s in fobj: line += 1 decode(s, line) except _EndOfFile: pass finally: if fclose: fclose() def loadbin(self, fobj, offset=0): """Load bin file into internal buffer. Not needed if source set in constructor. This will overwrite addresses without warning if object was already initialized. @param fobj file name or file-like object @param offset starting address offset """ fread = getattr(fobj, "read", None) if fread is None: f = open(fobj, "rb") fread = f.read fclose = f.close else: fclose = None try: self.frombytes(array('B', asbytes(fread())), offset=offset) finally: if fclose: fclose() def loadfile(self, fobj, format): """Load data file into internal buffer. Preferred wrapper over loadbin or loadhex. @param fobj file name or file-like object @param format file format ("hex" or "bin") """ if format == "hex": self.loadhex(fobj) elif format == "bin": self.loadbin(fobj) else: raise ValueError('format should be either "hex" or "bin";' ' got %r instead' % format) # alias (to be consistent with method tofile) fromfile = loadfile def fromdict(self, dikt): """Load data from dictionary. Dictionary should contain int keys representing addresses. Values should be the data to be stored in those addresses in unsigned char form (i.e. not strings). The dictionary may contain the key, ``start_addr`` to indicate the starting address of the data as described in README. The contents of the dict will be merged with this object and will overwrite any conflicts. This function is not necessary if the object was initialized with source specified. """ s = dikt.copy() start_addr = s.get('start_addr') if start_addr is not None: del s['start_addr'] for k in dict_keys_g(s): if type(k) not in IntTypes or k < 0: raise ValueError('Source dictionary should have only int keys') self._buf.update(s) if start_addr is not None: self.start_addr = start_addr def frombytes(self, bytes, offset=0): """Load data from array or list of bytes. Similar to loadbin() method but works directly with iterable bytes. """ for b in bytes: self._buf[offset] = b offset += 1 def _get_start_end(self, start=None, end=None, size=None): """Return default values for start and end if they are None. If this IntelHex object is empty then it's error to invoke this method with both start and end as None. """ if (start,end) == (None,None) and self._buf == {}: raise EmptyIntelHexError if size is not None: if None not in (start, end): raise ValueError("tobinarray: you can't use start,end and size" " arguments in the same time") if (start, end) == (None, None): start = self.minaddr() if start is not None: end = start + size - 1 else: start = end - size + 1 if start < 0: raise ValueError("tobinarray: invalid size (%d) " "for given end address (%d)" % (size,end)) else: if start is None: start = self.minaddr() if end is None: end = self.maxaddr() if start > end: start, end = end, start return start, end def tobinarray(self, start=None, end=None, pad=_DEPRECATED, size=None): ''' Convert this object to binary form as array. If start and end unspecified, they will be inferred from the data. @param start start address of output bytes. @param end end address of output bytes (inclusive). @param pad [DEPRECATED PARAMETER, please use self.padding instead] fill empty spaces with this value (if pad is None then this method uses self.padding). @param size size of the block, used with start or end parameter. @return array of unsigned char data. ''' if not isinstance(pad, _DeprecatedParam): print ("IntelHex.tobinarray: 'pad' parameter is deprecated.") if pad is not None: print ("Please, use IntelHex.padding attribute instead.") else: print ("Please, don't pass it explicitly.") print ("Use syntax like this: ih.tobinarray(start=xxx, end=yyy, size=zzz)") else: pad = None return self._tobinarray_really(start, end, pad, size) def _tobinarray_really(self, start, end, pad, size): """Return binary array.""" if pad is None: pad = self.padding bin = array('B') if self._buf == {} and None in (start, end): return bin if size is not None and size <= 0: raise ValueError("tobinarray: wrong value for size") start, end = self._get_start_end(start, end, size) for i in range_g(start, end+1): bin.append(self._buf.get(i, pad)) return bin def tobinstr(self, start=None, end=None, pad=_DEPRECATED, size=None): ''' Convert to binary form and return as binary string. @param start start address of output bytes. @param end end address of output bytes (inclusive). @param pad [DEPRECATED PARAMETER, please use self.padding instead] fill empty spaces with this value (if pad is None then this method uses self.padding). @param size size of the block, used with start or end parameter. @return bytes string of binary data. ''' if not isinstance(pad, _DeprecatedParam): print ("IntelHex.tobinstr: 'pad' parameter is deprecated.") if pad is not None: print ("Please, use IntelHex.padding attribute instead.") else: print ("Please, don't pass it explicitly.") print ("Use syntax like this: ih.tobinstr(start=xxx, end=yyy, size=zzz)") else: pad = None return self._tobinstr_really(start, end, pad, size) def _tobinstr_really(self, start, end, pad, size): return array_tobytes(self._tobinarray_really(start, end, pad, size)) def tobinfile(self, fobj, start=None, end=None, pad=_DEPRECATED, size=None): '''Convert to binary and write to file. @param fobj file name or file object for writing output bytes. @param start start address of output bytes. @param end end address of output bytes (inclusive). @param pad [DEPRECATED PARAMETER, please use self.padding instead] fill empty spaces with this value (if pad is None then this method uses self.padding). @param size size of the block, used with start or end parameter. ''' if not isinstance(pad, _DeprecatedParam): print ("IntelHex.tobinfile: 'pad' parameter is deprecated.") if pad is not None: print ("Please, use IntelHex.padding attribute instead.") else: print ("Please, don't pass it explicitly.") print ("Use syntax like this: ih.tobinfile(start=xxx, end=yyy, size=zzz)") else: pad = None if getattr(fobj, "write", None) is None: fobj = open(fobj, "wb") close_fd = True else: close_fd = False fobj.write(self._tobinstr_really(start, end, pad, size)) if close_fd: fobj.close() def todict(self): '''Convert to python dictionary. @return dict suitable for initializing another IntelHex object. ''' r = {} r.update(self._buf) if self.start_addr: r['start_addr'] = self.start_addr return r def addresses(self): '''Returns all used addresses in sorted order. @return list of occupied data addresses in sorted order. ''' aa = dict_keys(self._buf) aa.sort() return aa def minaddr(self): '''Get minimal address of HEX content. @return minimal address or None if no data ''' aa = dict_keys(self._buf) if aa == []: return None else: return min(aa) def maxaddr(self): '''Get maximal address of HEX content. @return maximal address or None if no data ''' aa = dict_keys(self._buf) if aa == []: return None else: return max(aa) def __getitem__(self, addr): ''' Get requested byte from address. @param addr address of byte. @return byte if address exists in HEX file, or self.padding if no data found. ''' t = type(addr) if t in IntTypes: if addr < 0: raise TypeError('Address should be >= 0.') return self._buf.get(addr, self.padding) elif t == slice: addresses = dict_keys(self._buf) ih = IntelHex() if addresses: addresses.sort() start = addr.start or addresses[0] stop = addr.stop or (addresses[-1]+1) step = addr.step or 1 for i in range_g(start, stop, step): x = self._buf.get(i) if x is not None: ih[i] = x return ih else: raise TypeError('Address has unsupported type: %s' % t) def __setitem__(self, addr, byte): """Set byte at address.""" t = type(addr) if t in IntTypes: if addr < 0: raise TypeError('Address should be >= 0.') self._buf[addr] = byte elif t == slice: if not isinstance(byte, (list, tuple)): raise ValueError('Slice operation expects sequence of bytes') start = addr.start stop = addr.stop step = addr.step or 1 if None not in (start, stop): ra = range_l(start, stop, step) if len(ra) != len(byte): raise ValueError('Length of bytes sequence does not match ' 'address range') elif (start, stop) == (None, None): raise TypeError('Unsupported address range') elif start is None: start = stop - len(byte) elif stop is None: stop = start + len(byte) if start < 0: raise TypeError('start address cannot be negative') if stop < 0: raise TypeError('stop address cannot be negative') j = 0 for i in range_g(start, stop, step): self._buf[i] = byte[j] j += 1 else: raise TypeError('Address has unsupported type: %s' % t) def __delitem__(self, addr): """Delete byte at address.""" t = type(addr) if t in IntTypes: if addr < 0: raise TypeError('Address should be >= 0.') del self._buf[addr] elif t == slice: addresses = dict_keys(self._buf) if addresses: addresses.sort() start = addr.start or addresses[0] stop = addr.stop or (addresses[-1]+1) step = addr.step or 1 for i in range_g(start, stop, step): x = self._buf.get(i) if x is not None: del self._buf[i] else: raise TypeError('Address has unsupported type: %s' % t) def __len__(self): """Return count of bytes with real values.""" return len(dict_keys(self._buf)) def _get_eol_textfile(eolstyle, platform): if eolstyle == 'native': return '\n' elif eolstyle == 'CRLF': if platform != 'win32': return '\r\n' else: return '\n' else: raise ValueError("wrong eolstyle %s" % repr(eolstyle)) _get_eol_textfile = staticmethod(_get_eol_textfile) def write_hex_file(self, f, write_start_addr=True, eolstyle='native'): """Write data to file f in HEX format. @param f filename or file-like object for writing @param write_start_addr enable or disable writing start address record to file (enabled by default). If there is no start address in obj, nothing will be written regardless of this setting. @param eolstyle can be used to force CRLF line-endings for output file on different platforms. Supported eol styles: 'native', 'CRLF'. """ fwrite = getattr(f, "write", None) if fwrite: fobj = f fclose = None else: fobj = open(f, 'w') fwrite = fobj.write fclose = fobj.close eol = IntelHex._get_eol_textfile(eolstyle, sys.platform) # Translation table for uppercasing hex ascii string. # timeit shows that using hexstr.translate(table) # is faster than hexstr.upper(): # 0.452ms vs. 0.652ms (translate vs. upper) if sys.version_info[0] >= 3: # Python 3 table = bytes(range_l(256)).upper() else: # Python 2 table = ''.join(chr(i).upper() for i in range_g(256)) # start address record if any if self.start_addr and write_start_addr: keys = dict_keys(self.start_addr) keys.sort() bin = array('B', asbytes('\0'*9)) if keys == ['CS','IP']: # Start Segment Address Record bin[0] = 4 # reclen bin[1] = 0 # offset msb bin[2] = 0 # offset lsb bin[3] = 3 # rectyp cs = self.start_addr['CS'] bin[4] = (cs >> 8) & 0x0FF bin[5] = cs & 0x0FF ip = self.start_addr['IP'] bin[6] = (ip >> 8) & 0x0FF bin[7] = ip & 0x0FF bin[8] = (-sum(bin)) & 0x0FF # chksum fwrite(':' + asstr(hexlify(array_tobytes(bin)).translate(table)) + eol) elif keys == ['EIP']: # Start Linear Address Record bin[0] = 4 # reclen bin[1] = 0 # offset msb bin[2] = 0 # offset lsb bin[3] = 5 # rectyp eip = self.start_addr['EIP'] bin[4] = (eip >> 24) & 0x0FF bin[5] = (eip >> 16) & 0x0FF bin[6] = (eip >> 8) & 0x0FF bin[7] = eip & 0x0FF bin[8] = (-sum(bin)) & 0x0FF # chksum fwrite(':' + asstr(hexlify(array_tobytes(bin)).translate(table)) + eol) else: if fclose: fclose() raise InvalidStartAddressValueError(start_addr=self.start_addr) # data addresses = dict_keys(self._buf) addresses.sort() addr_len = len(addresses) if addr_len: minaddr = addresses[0] maxaddr = addresses[-1] if maxaddr > 65535: need_offset_record = True else: need_offset_record = False high_ofs = 0 cur_addr = minaddr cur_ix = 0 while cur_addr <= maxaddr: if need_offset_record: bin = array('B', asbytes('\0'*7)) bin[0] = 2 # reclen bin[1] = 0 # offset msb bin[2] = 0 # offset lsb bin[3] = 4 # rectyp high_ofs = int(cur_addr>>16) b = divmod(high_ofs, 256) bin[4] = b[0] # msb of high_ofs bin[5] = b[1] # lsb of high_ofs bin[6] = (-sum(bin)) & 0x0FF # chksum fwrite(':' + asstr(hexlify(array_tobytes(bin)).translate(table)) + eol) while True: # produce one record low_addr = cur_addr & 0x0FFFF # chain_len off by 1 chain_len = min(15, 65535-low_addr, maxaddr-cur_addr) # search continuous chain stop_addr = cur_addr + chain_len if chain_len: ix = bisect_right(addresses, stop_addr, cur_ix, min(cur_ix+chain_len+1, addr_len)) chain_len = ix - cur_ix # real chain_len # there could be small holes in the chain # but we will catch them by try-except later # so for big continuous files we will work # at maximum possible speed else: chain_len = 1 # real chain_len bin = array('B', asbytes('\0'*(5+chain_len))) b = divmod(low_addr, 256) bin[1] = b[0] # msb of low_addr bin[2] = b[1] # lsb of low_addr bin[3] = 0 # rectype try: # if there is small holes we'll catch them for i in range_g(chain_len): bin[4+i] = self._buf[cur_addr+i] except KeyError: # we catch a hole so we should shrink the chain chain_len = i bin = bin[:5+i] bin[0] = chain_len bin[4+chain_len] = (-sum(bin)) & 0x0FF # chksum fwrite(':' + asstr(hexlify(array_tobytes(bin)).translate(table)) + eol) # adjust cur_addr/cur_ix cur_ix += chain_len if cur_ix < addr_len: cur_addr = addresses[cur_ix] else: cur_addr = maxaddr + 1 break high_addr = int(cur_addr>>16) if high_addr > high_ofs: break # end-of-file record fwrite(":00000001FF"+eol) if fclose: fclose() def tofile(self, fobj, format): """Write data to hex or bin file. Preferred method over tobin or tohex. @param fobj file name or file-like object @param format file format ("hex" or "bin") """ if format == 'hex': self.write_hex_file(fobj) elif format == 'bin': self.tobinfile(fobj) else: raise ValueError('format should be either "hex" or "bin";' ' got %r instead' % format) def gets(self, addr, length): """Get string of bytes from given address. If any entries are blank from addr through addr+length, a NotEnoughDataError exception will be raised. Padding is not used. """ a = array('B', asbytes('\0'*length)) try: for i in range_g(length): a[i] = self._buf[addr+i] except KeyError: raise NotEnoughDataError(address=addr, length=length) return array_tobytes(a) def puts(self, addr, s): """Put string of bytes at given address. Will overwrite any previous entries. """ a = array('B', asbytes(s)) for i in range_g(len(a)): self._buf[addr+i] = a[i] def getsz(self, addr): """Get zero-terminated bytes string from given address. Will raise NotEnoughDataError exception if a hole is encountered before a 0. """ i = 0 try: while True: if self._buf[addr+i] == 0: break i += 1 except KeyError: raise NotEnoughDataError(msg=('Bad access at 0x%X: ' 'not enough data to read zero-terminated string') % addr) return self.gets(addr, i) def putsz(self, addr, s): """Put bytes string in object at addr and append terminating zero at end.""" self.puts(addr, s) self._buf[addr+len(s)] = 0 def dump(self, tofile=None, width=16, withpadding=False): """Dump object content to specified file object or to stdout if None. Format is a hexdump with some header information at the beginning, addresses on the left, and data on right. @param tofile file-like object to dump to @param width number of bytes per line (i.e. columns) @param withpadding print padding character instead of '--' @raise ValueError if width is not a positive integer """ if not isinstance(width,int) or width < 1: raise ValueError('width must be a positive integer.') # The integer can be of float type - does not work with bit operations width = int(width) if tofile is None: tofile = sys.stdout # start addr possibly if self.start_addr is not None: cs = self.start_addr.get('CS') ip = self.start_addr.get('IP') eip = self.start_addr.get('EIP') if eip is not None and cs is None and ip is None: tofile.write('EIP = 0x%08X\n' % eip) elif eip is None and cs is not None and ip is not None: tofile.write('CS = 0x%04X, IP = 0x%04X\n' % (cs, ip)) else: tofile.write('start_addr = %r\n' % start_addr) # actual data addresses = dict_keys(self._buf) if addresses: addresses.sort() minaddr = addresses[0] maxaddr = addresses[-1] startaddr = (minaddr // width) * width endaddr = ((maxaddr // width) + 1) * width maxdigits = max(len(hex(endaddr)) - 2, 4) # Less 2 to exclude '0x' templa = '%%0%dX' % maxdigits rangewidth = range_l(width) if withpadding: pad = self.padding else: pad = None for i in range_g(startaddr, endaddr, width): tofile.write(templa % i) tofile.write(' ') s = [] for j in rangewidth: x = self._buf.get(i+j, pad) if x is not None: tofile.write(' %02X' % x) if 32 <= x < 127: # GNU less does not like 0x7F (128 decimal) so we'd better show it as dot s.append(chr(x)) else: s.append('.') else: tofile.write(' --') s.append(' ') tofile.write(' |' + ''.join(s) + '|\n') def merge(self, other, overlap='error'): """Merge content of other IntelHex object into current object (self). @param other other IntelHex object. @param overlap action on overlap of data or starting addr: - error: raising OverlapError; - ignore: ignore other data and keep current data in overlapping region; - replace: replace data with other data in overlapping region. @raise TypeError if other is not instance of IntelHex @raise ValueError if other is the same object as self (it can't merge itself) @raise ValueError if overlap argument has incorrect value @raise AddressOverlapError on overlapped data """ # check args if not isinstance(other, IntelHex): raise TypeError('other should be IntelHex object') if other is self: raise ValueError("Can't merge itself") if overlap not in ('error', 'ignore', 'replace'): raise ValueError("overlap argument should be either " "'error', 'ignore' or 'replace'") # merge data this_buf = self._buf other_buf = other._buf for i in other_buf: if i in this_buf: if overlap == 'error': raise AddressOverlapError( 'Data overlapped at address 0x%X' % i) elif overlap == 'ignore': continue this_buf[i] = other_buf[i] # merge start_addr if self.start_addr != other.start_addr: if self.start_addr is None: # set start addr from other self.start_addr = other.start_addr elif other.start_addr is None: # keep existing start addr pass else: # conflict if overlap == 'error': raise AddressOverlapError( 'Starting addresses are different') elif overlap == 'replace': self.start_addr = other.start_addr def segments(self): """Return a list of ordered tuple objects, representing contiguous occupied data addresses. Each tuple has a length of two and follows the semantics of the range and xrange objects. The second entry of the tuple is always an integer greater than the first entry. """ addresses = self.addresses() if not addresses: return [] elif len(addresses) == 1: return([(addresses[0], addresses[0]+1)]) adjacent_differences = [(b - a) for (a, b) in zip(addresses[:-1], addresses[1:])] breaks = [i for (i, x) in enumerate(adjacent_differences) if x > 1] endings = [addresses[b] for b in breaks] endings.append(addresses[-1]) beginings = [addresses[b+1] for b in breaks] beginings.insert(0, addresses[0]) return [(a, b+1) for (a, b) in zip(beginings, endings)] def get_memory_size(self): """Returns the approximate memory footprint for data.""" n = sys.getsizeof(self) n += sys.getsizeof(self.padding) n += total_size(self.start_addr) n += total_size(self._buf) n += sys.getsizeof(self._offset) return n #/IntelHex class IntelHex16bit(IntelHex): """Access to data as 16-bit words. Intended to use with Microchip HEX files.""" def __init__(self, source=None): """Construct class from HEX file or from instance of ordinary IntelHex class. If IntelHex object is passed as source, the original IntelHex object should not be used again because this class will alter it. This class leaves padding alone unless it was precisely 0xFF. In that instance it is sign extended to 0xFFFF. @param source file name of HEX file or file object or instance of ordinary IntelHex class. Will also accept dictionary from todict method. """ if isinstance(source, IntelHex): # from ihex8 self.padding = source.padding self.start_addr = source.start_addr # private members self._buf = source._buf self._offset = source._offset elif isinstance(source, dict): raise IntelHexError("IntelHex16bit does not support initialization from dictionary yet.\n" "Patches are welcome.") else: IntelHex.__init__(self, source) if self.padding == 0x0FF: self.padding = 0x0FFFF def __getitem__(self, addr16): """Get 16-bit word from address. Raise error if only one byte from the pair is set. We assume a Little Endian interpretation of the hex file. @param addr16 address of word (addr8 = 2 * addr16). @return word if bytes exists in HEX file, or self.padding if no data found. """ addr1 = addr16 * 2 addr2 = addr1 + 1 byte1 = self._buf.get(addr1, None) byte2 = self._buf.get(addr2, None) if byte1 != None and byte2 != None: return byte1 | (byte2 << 8) # low endian if byte1 == None and byte2 == None: return self.padding raise BadAccess16bit(address=addr16) def __setitem__(self, addr16, word): """Sets the address at addr16 to word assuming Little Endian mode. """ addr_byte = addr16 * 2 b = divmod(word, 256) self._buf[addr_byte] = b[1] self._buf[addr_byte+1] = b[0] def minaddr(self): '''Get minimal address of HEX content in 16-bit mode. @return minimal address used in this object ''' aa = dict_keys(self._buf) if aa == []: return 0 else: return min(aa)>>1 def maxaddr(self): '''Get maximal address of HEX content in 16-bit mode. @return maximal address used in this object ''' aa = dict_keys(self._buf) if aa == []: return 0 else: return max(aa)>>1 def tobinarray(self, start=None, end=None, size=None): '''Convert this object to binary form as array (of 2-bytes word data). If start and end unspecified, they will be inferred from the data. @param start start address of output data. @param end end address of output data (inclusive). @param size size of the block (number of words), used with start or end parameter. @return array of unsigned short (uint16_t) data. ''' bin = array('H') if self._buf == {} and None in (start, end): return bin if size is not None and size <= 0: raise ValueError("tobinarray: wrong value for size") start, end = self._get_start_end(start, end, size) for addr in range_g(start, end+1): bin.append(self[addr]) return bin #/class IntelHex16bit def hex2bin(fin, fout, start=None, end=None, size=None, pad=None): """Hex-to-Bin convertor engine. @return 0 if all OK @param fin input hex file (filename or file-like object) @param fout output bin file (filename or file-like object) @param start start of address range (optional) @param end end of address range (inclusive; optional) @param size size of resulting file (in bytes) (optional) @param pad padding byte (optional) """ try: h = IntelHex(fin) except HexReaderError: e = sys.exc_info()[1] # current exception txt = "ERROR: bad HEX file: %s" % str(e) print(txt) return 1 # start, end, size if size != None and size != 0: if end == None: if start == None: start = h.minaddr() end = start + size - 1 else: if (end+1) >= size: start = end + 1 - size else: start = 0 try: if pad is not None: # using .padding attribute rather than pad argument to function call h.padding = pad h.tobinfile(fout, start, end) except IOError: e = sys.exc_info()[1] # current exception txt = "ERROR: Could not write to file: %s: %s" % (fout, str(e)) print(txt) return 1 return 0 #/def hex2bin def bin2hex(fin, fout, offset=0): """Simple bin-to-hex convertor. @return 0 if all OK @param fin input bin file (filename or file-like object) @param fout output hex file (filename or file-like object) @param offset starting address offset for loading bin """ h = IntelHex() try: h.loadbin(fin, offset) except IOError: e = sys.exc_info()[1] # current exception txt = 'ERROR: unable to load bin file:', str(e) print(txt) return 1 try: h.tofile(fout, format='hex') except IOError: e = sys.exc_info()[1] # current exception txt = "ERROR: Could not write to file: %s: %s" % (fout, str(e)) print(txt) return 1 return 0 #/def bin2hex def diff_dumps(ih1, ih2, tofile=None, name1="a", name2="b", n_context=3): """Diff 2 IntelHex objects and produce unified diff output for their hex dumps. @param ih1 first IntelHex object to compare @param ih2 second IntelHex object to compare @param tofile file-like object to write output @param name1 name of the first hex file to show in the diff header @param name2 name of the first hex file to show in the diff header @param n_context number of context lines in the unidiff output """ def prepare_lines(ih): sio = StringIO() ih.dump(sio) dump = sio.getvalue() lines = dump.splitlines() return lines a = prepare_lines(ih1) b = prepare_lines(ih2) import difflib result = list(difflib.unified_diff(a, b, fromfile=name1, tofile=name2, n=n_context, lineterm='')) if tofile is None: tofile = sys.stdout output = '\n'.join(result)+'\n' tofile.write(output) class Record(object): """Helper methods to build valid ihex records.""" def _from_bytes(bytes): """Takes a list of bytes, computes the checksum, and outputs the entire record as a string. bytes should be the hex record without the colon or final checksum. @param bytes list of byte values so far to pack into record. @return String representation of one HEX record """ assert len(bytes) >= 4 # calculate checksum s = (-sum(bytes)) & 0x0FF bin = array('B', bytes + [s]) return ':' + asstr(hexlify(array_tobytes(bin))).upper() _from_bytes = staticmethod(_from_bytes) def data(offset, bytes): """Return Data record. This constructs the full record, including the length information, the record type (0x00), the checksum, and the offset. @param offset load offset of first byte. @param bytes list of byte values to pack into record. @return String representation of one HEX record """ assert 0 <= offset < 65536 assert 0 < len(bytes) < 256 b = [len(bytes), (offset>>8)&0x0FF, offset&0x0FF, 0x00] + bytes return Record._from_bytes(b) data = staticmethod(data) def eof(): """Return End of File record as a string. @return String representation of Intel Hex EOF record """ return ':00000001FF' eof = staticmethod(eof) def extended_segment_address(usba): """Return Extended Segment Address Record. @param usba Upper Segment Base Address. @return String representation of Intel Hex USBA record. """ b = [2, 0, 0, 0x02, (usba>>8)&0x0FF, usba&0x0FF] return Record._from_bytes(b) extended_segment_address = staticmethod(extended_segment_address) def start_segment_address(cs, ip): """Return Start Segment Address Record. @param cs 16-bit value for CS register. @param ip 16-bit value for IP register. @return String representation of Intel Hex SSA record. """ b = [4, 0, 0, 0x03, (cs>>8)&0x0FF, cs&0x0FF, (ip>>8)&0x0FF, ip&0x0FF] return Record._from_bytes(b) start_segment_address = staticmethod(start_segment_address) def extended_linear_address(ulba): """Return Extended Linear Address Record. @param ulba Upper Linear Base Address. @return String representation of Intel Hex ELA record. """ b = [2, 0, 0, 0x04, (ulba>>8)&0x0FF, ulba&0x0FF] return Record._from_bytes(b) extended_linear_address = staticmethod(extended_linear_address) def start_linear_address(eip): """Return Start Linear Address Record. @param eip 32-bit linear address for the EIP register. @return String representation of Intel Hex SLA record. """ b = [4, 0, 0, 0x05, (eip>>24)&0x0FF, (eip>>16)&0x0FF, (eip>>8)&0x0FF, eip&0x0FF] return Record._from_bytes(b) start_linear_address = staticmethod(start_linear_address) class _BadFileNotation(Exception): """Special error class to use with _get_file_and_addr_range.""" pass def _get_file_and_addr_range(s, _support_drive_letter=None): """Special method for hexmerge.py script to split file notation into 3 parts: (filename, start, end) @raise _BadFileNotation when string cannot be safely split. """ if _support_drive_letter is None: _support_drive_letter = (os.name == 'nt') drive = '' if _support_drive_letter: if s[1:2] == ':' and s[0].upper() in ''.join([chr(i) for i in range_g(ord('A'), ord('Z')+1)]): drive = s[:2] s = s[2:] parts = s.split(':') n = len(parts) if n == 1: fname = parts[0] fstart = None fend = None elif n != 3: raise _BadFileNotation else: fname = parts[0] def ascii_hex_to_int(ascii): if ascii is not None: try: return int(ascii, 16) except ValueError: raise _BadFileNotation return ascii fstart = ascii_hex_to_int(parts[1] or None) fend = ascii_hex_to_int(parts[2] or None) return drive+fname, fstart, fend ## # IntelHex Errors Hierarchy: # # IntelHexError - basic error # HexReaderError - general hex reader error # AddressOverlapError - data for the same address overlap # HexRecordError - hex record decoder base error # RecordLengthError - record has invalid length # RecordTypeError - record has invalid type (RECTYP) # RecordChecksumError - record checksum mismatch # EOFRecordError - invalid EOF record (type 01) # ExtendedAddressRecordError - extended address record base error # ExtendedSegmentAddressRecordError - invalid extended segment address record (type 02) # ExtendedLinearAddressRecordError - invalid extended linear address record (type 04) # StartAddressRecordError - start address record base error # StartSegmentAddressRecordError - invalid start segment address record (type 03) # StartLinearAddressRecordError - invalid start linear address record (type 05) # DuplicateStartAddressRecordError - start address record appears twice # InvalidStartAddressValueError - invalid value of start addr record # _EndOfFile - it's not real error, used internally by hex reader as signal that EOF record found # BadAccess16bit - not enough data to read 16 bit value (deprecated, see NotEnoughDataError) # NotEnoughDataError - not enough data to read N contiguous bytes # EmptyIntelHexError - requested operation cannot be performed with empty object class IntelHexError(Exception): '''Base Exception class for IntelHex module''' _fmt = 'IntelHex base error' #: format string def __init__(self, msg=None, **kw): """Initialize the Exception with the given message. """ self.msg = msg for key, value in dict_items_g(kw): setattr(self, key, value) def __str__(self): """Return the message in this Exception.""" if self.msg: return self.msg try: return self._fmt % self.__dict__ except (NameError, ValueError, KeyError): e = sys.exc_info()[1] # current exception return 'Unprintable exception %s: %s' \ % (repr(e), str(e)) class _EndOfFile(IntelHexError): """Used for internal needs only.""" _fmt = 'EOF record reached -- signal to stop read file' class HexReaderError(IntelHexError): _fmt = 'Hex reader base error' class AddressOverlapError(HexReaderError): _fmt = 'Hex file has data overlap at address 0x%(address)X on line %(line)d' # class NotAHexFileError was removed in trunk.revno.54 because it's not used class HexRecordError(HexReaderError): _fmt = 'Hex file contains invalid record at line %(line)d' class RecordLengthError(HexRecordError): _fmt = 'Record at line %(line)d has invalid length' class RecordTypeError(HexRecordError): _fmt = 'Record at line %(line)d has invalid record type' class RecordChecksumError(HexRecordError): _fmt = 'Record at line %(line)d has invalid checksum' class EOFRecordError(HexRecordError): _fmt = 'File has invalid End-of-File record' class ExtendedAddressRecordError(HexRecordError): _fmt = 'Base class for extended address exceptions' class ExtendedSegmentAddressRecordError(ExtendedAddressRecordError): _fmt = 'Invalid Extended Segment Address Record at line %(line)d' class ExtendedLinearAddressRecordError(ExtendedAddressRecordError): _fmt = 'Invalid Extended Linear Address Record at line %(line)d' class StartAddressRecordError(HexRecordError): _fmt = 'Base class for start address exceptions' class StartSegmentAddressRecordError(StartAddressRecordError): _fmt = 'Invalid Start Segment Address Record at line %(line)d' class StartLinearAddressRecordError(StartAddressRecordError): _fmt = 'Invalid Start Linear Address Record at line %(line)d' class DuplicateStartAddressRecordError(StartAddressRecordError): _fmt = 'Start Address Record appears twice at line %(line)d' class InvalidStartAddressValueError(StartAddressRecordError): _fmt = 'Invalid start address value: %(start_addr)s' class NotEnoughDataError(IntelHexError): _fmt = ('Bad access at 0x%(address)X: ' 'not enough data to read %(length)d contiguous bytes') class BadAccess16bit(NotEnoughDataError): _fmt = 'Bad access at 0x%(address)X: not enough data to read 16 bit value' class EmptyIntelHexError(IntelHexError): _fmt = "Requested operation cannot be executed with empty object" intelhex-2.1/intelhex/__main__.py0000644000175200017530000000351713147236475017665 0ustar builddbuildd00000000000000# Copyright (c) 2016, Alexander Belchenko # All rights reserved. # # 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 the author 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. if __name__ == '__main__': print("Welcome to IntelHex Python library.") print() print("The intelhex package has some executable points:") print(" python -m intelhex.test -- easy way to run unit tests.") print(" python -m intelhex.bench -- run benchmarks.") intelhex-2.1/intelhex/compat.py0000644000175200017530000001153313147236475017425 0ustar builddbuildd00000000000000# Copyright (c) 2011, Bernhard Leiner # Copyright (c) 2013-2016 Alexander Belchenko # All rights reserved. # # 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 the author 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. '''Compatibility functions for python 2 and 3. @author Bernhard Leiner (bleiner AT gmail com) @author Alexander Belchenko (alexander belchenko AT gmail com) ''' __docformat__ = "javadoc" import sys, array if sys.version_info[0] >= 3: # Python 3 Python = 3 def asbytes(s): if isinstance(s, bytes): return s return s.encode('latin1') def asstr(s): if isinstance(s, str): return s return s.decode('latin1') array_tobytes = getattr(array.array, "tobytes", array.array.tostring) IntTypes = (int,) StrType = str UnicodeType = str range_g = range # range generator def range_l(*args): # range list return list(range(*args)) def dict_keys(dikt): # dict keys list return list(dikt.keys()) def dict_keys_g(dikt): # dict keys generator return dikt.keys() def dict_items_g(dikt): # dict items generator return dikt.items() from io import StringIO, BytesIO def get_binary_stdout(): return sys.stdout.buffer def get_binary_stdin(): return sys.stdin.buffer else: # Python 2 Python = 2 asbytes = str asstr = str array_tobytes = array.array.tostring IntTypes = (int, long) StrType = basestring UnicodeType = unicode #range_g = xrange # range generator def range_g(*args): # we want to use xrange here but on python 2 it does not work with long ints try: return xrange(*args) except OverflowError: start = 0 stop = 0 step = 1 n = len(args) if n == 1: stop = args[0] elif n == 2: start, stop = args elif n == 3: start, stop, step = args else: raise TypeError('wrong number of arguments in range_g call!') if step == 0: raise ValueError('step cannot be zero') if step > 0: def up(start, stop, step): while start < stop: yield start start += step return up(start, stop, step) else: def down(start, stop, step): while start > stop: yield start start += step return down(start, stop, step) range_l = range # range list def dict_keys(dikt): # dict keys list return dikt.keys() def dict_keys_g(dikt): # dict keys generator return dikt.keys() def dict_items_g(dikt): # dict items generator return dikt.items() from cStringIO import StringIO BytesIO = StringIO import os def _force_stream_binary(stream): """Force binary mode for stream on Windows.""" if os.name == 'nt': f_fileno = getattr(stream, 'fileno', None) if f_fileno: fileno = f_fileno() if fileno >= 0: import msvcrt msvcrt.setmode(fileno, os.O_BINARY) return stream def get_binary_stdout(): return _force_stream_binary(sys.stdout) def get_binary_stdin(): return _force_stream_binary(sys.stdin) intelhex-2.1/intelhex/bench.py0000644000175200017530000002211213147236475017214 0ustar builddbuildd00000000000000#!/usr/bin/python # (c) Alexander Belchenko, 2007, 2009 # [2013/08] NOTE: This file is keeping for historical reasons. # It may or may not work actually with current version of intelhex, # and most likely it requires some fixes here and there. """Benchmarking. Run each test 3 times and get median value. Using 10K array as base test time. Each other test compared with base with next formula:: Tc * Nb q = --------- Tb * Nc Here: * Tc - execution time of current test * Tb - execution time of base * Nb - array size of base (10K) * Nc - array size of current test If resulting value is ``q <= 1.0`` it's the best possible result, i.e. time increase proportionally to array size. """ import gc import sys import time import intelhex from intelhex.compat import StringIO, range_g def median(values): """Return median value for the list of values. @param values: list of values for processing. @return: median value. """ values.sort() n = int(len(values) / 2) return values[n] def run_test(func, fobj): """Run func with argument fobj and measure execution time. @param func: function for test @param fobj: data for test @return: execution time """ gc.disable() try: begin = time.time() func(fobj) end = time.time() finally: gc.enable() return end - begin def run_readtest_N_times(func, hexstr, n): """Run each test N times. @param func: function for test @param hexstr: string with content of hex file to read @param n: times to repeat. @return: (median time, times list) """ assert n > 0 times = [] for i in range_g(n): sio = StringIO(hexstr) times.append(run_test(func, sio)) sio.close() t = median(times) return t, times def run_writetest_N_times(func, n): """Run each test N times. @param func: function for test @param n: times to repeat. @return: (median time, times list) """ assert n > 0 times = [] for i in range_g(n): sio = StringIO() times.append(run_test(func, sio)) sio.close() t = median(times) return t, times def time_coef(tc, nc, tb, nb): """Return time coefficient relative to base numbers. @param tc: current test time @param nc: current test data size @param tb: base test time @param nb: base test data size @return: time coef. """ tc = float(tc) nc = float(nc) tb = float(tb) nb = float(nb) q = (tc * nb) / (tb * nc) return q def get_test_data(n1, offset, n2): """Create test data on given pattern. @param n1: size of first part of array at base address 0. @param offset: offset for second part of array. @param n2: size of second part of array at given offset. @return: (overall size, hex file, IntelHex object) """ # make IntelHex object ih = intelhex.IntelHex() addr = 0 for i in range_g(n1): ih[addr] = addr % 256 addr += 1 addr += offset for i in range_g(n2): ih[addr] = addr % 256 addr += 1 # make hex file sio = StringIO() ih.write_hex_file(sio) hexstr = sio.getvalue() sio.close() # return n1+n2, hexstr, ih def get_base_50K(): return get_test_data(50000, 0, 0) def get_250K(): return get_test_data(250000, 0, 0) def get_100K_100K(): return get_test_data(100000, 1000000, 100000) def get_0_100K(): return get_test_data(0, 1000000, 100000) def get_1M(): return get_test_data(1000000, 0, 0) class Measure(object): """Measure execution time helper.""" data_set = [ # (data name, getter) ('base 50K', get_base_50K), # first should be base numbers ('250K', get_250K), ('1M', get_1M), ('100K+100K', get_100K_100K), ('0+100K', get_0_100K), ] def __init__(self, n=3, read=True, write=True): self.n = n self.read = read self.write = write self.results = [] def measure_one(self, data): """Do measuring of read and write operations. @param data: 3-tuple from get_test_data @return: (time readhex, time writehex) """ _unused, hexstr, ih = data tread, twrite = 0.0, 0.0 if self.read: tread = run_readtest_N_times(intelhex.IntelHex, hexstr, self.n)[0] if self.write: twrite = run_writetest_N_times(ih.write_hex_file, self.n)[0] return tread, twrite def measure_all(self): for name, getter in self.data_set: data = getter() times = self.measure_one(data) self.results.append((name, times, data[0])) def print_report(self, to_file=None): if to_file is None: to_file = sys.stdout base_title, base_times, base_n = self.results[0] base_read, base_write = base_times read_report = ['%-10s\t%7.3f' % (base_title, base_read)] write_report = ['%-10s\t%7.3f' % (base_title, base_write)] for item in self.results[1:]: cur_title, cur_times, cur_n = item cur_read, cur_write = cur_times if self.read: qread = time_coef(cur_read, cur_n, base_read, base_n) read_report.append('%-10s\t%7.3f\t%7.3f' % (cur_title, cur_read, qread)) if self.write: qwrite = time_coef(cur_write, cur_n, base_write, base_n) write_report.append('%-10s\t%7.3f\t%7.3f' % (cur_title, cur_write, qwrite)) if self.read: to_file.write('Read operation:\n') to_file.write('\n'.join(read_report)) to_file.write('\n\n') if self.write: to_file.write('Write operation:\n') to_file.write('\n'.join(write_report)) to_file.write('\n\n') HELP = """\ Usage: python _bench.py [OPTIONS] Options: -h this help -n N repeat tests N times -r run only tests for read operation -w run only tests for write operation If option -r or -w is not specified then all tests will be run. """ def main(argv=None): """Main function to run benchmarks. @param argv: command-line arguments. @return: exit code (0 is OK). """ import getopt # default values test_read = None test_write = None n = 3 # number of repeat if argv is None: argv = sys.argv[1:] try: opts, args = getopt.getopt(argv, 'hn:rw', []) for o,a in opts: if o == '-h': print(HELP) return 0 elif o == '-n': n = int(a) elif o == '-r': test_read = True elif o == '-w': test_write = True if args: raise getopt.GetoptError('Arguments are not used.') except getopt.GetoptError: msg = sys.exc_info()[1] # current exception txt = str(msg) print(txt) return 1 if (test_read, test_write) == (None, None): test_read = test_write = True m = Measure(n, test_read, test_write) m.measure_all() m.print_report() return 0 if __name__ == '__main__': sys.exit(main(sys.argv[1:])) """ Some Results ************ 21/04/2007 revno.40 Python 2.5 @ Windows XP, Intel Celeron M CPU 430 @ 1.73GHz Read operation: base 10K 0.031 100K 0.360 1.161 1M 3.500 1.129 100K+100K 0.719 1.160 0+100K 0.360 1.161 Write operation: base 10K 0.031 100K 0.297 0.958 1M 2.953 0.953 100K+100K 1.328 2.142 0+100K 0.312 1.006 21/04/2007 revno.46 Python 2.5 @ Windows XP, Intel Celeron M CPU 430 @ 1.73GHz Read operation: base 10K 0.016 100K 0.203 1.269 1M 2.000 1.250 100K+100K 0.422 1.319 0+100K 0.203 1.269 Write operation: base 10K 0.031 100K 0.297 0.958 1M 2.969 0.958 100K+100K 1.328 2.142 0+100K 0.312 1.006 22/04/2007 revno.48 Python 2.5 @ Windows XP, Intel Celeron M CPU 430 @ 1.73GHz Read operation: base 10K 0.016 100K 0.187 1.169 1M 1.891 1.182 100K+100K 0.406 1.269 0+100K 0.188 1.175 Write operation: base 10K 0.031 100K 0.296 0.955 1M 2.969 0.958 100K+100K 1.328 2.142 0+100K 0.312 1.006 19/08/2008 revno.72 Python 2.5.2 @ Windows XP, Intel Celeron M CPU 430 @ 1.73GHz Read operation: base 10K 0.016 100K 0.171 1.069 1M 1.734 1.084 100K+100K 0.375 1.172 0+100K 0.172 1.075 Write operation: base 10K 0.016 100K 0.156 0.975 1M 1.532 0.957 100K+100K 0.344 1.075 0+100K 0.156 0.975 """ intelhex-2.1/PKG-INFO0000644000175200017530000000202013147241054015021 0ustar builddbuildd00000000000000Metadata-Version: 1.1 Name: intelhex Version: 2.1 Summary: Python Intel Hex library Home-page: https://pypi.python.org/pypi/IntelHex Author: Alexander Belchenko Author-email: alexander.belchenko@gmail.com License: BSD Description: Python Intel Hex library Keywords: Intel HEX hex2bin HEX8 Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 Classifier: Classifier: Development Status :: 5 - Production/Stable Classifier: Classifier: Environment :: Console Classifier: Classifier: Intended Audience :: Developers Classifier: Classifier: Intended Audience :: Telecommunications Industry Classifier: Classifier: License :: OSI Approved :: BSD License Classifier: Classifier: Operating System :: OS Independent Classifier: Classifier: Programming Language :: Python Classifier: Classifier: Topic :: Scientific/Engineering Classifier: Classifier: Topic :: Software Development :: Embedded Systems Classifier: Classifier: Topic :: Utilities intelhex-2.1/scripts/0000755000175200017530000000000013147241054015421 5ustar builddbuildd00000000000000intelhex-2.1/scripts/hexdiff.py0000755000175200017530000000544113147236475017432 0ustar builddbuildd00000000000000#!/usr/bin/python # Copyright (c) 2011-2016 Alexander Belchenko # All rights reserved. # # 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 the author 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. """Produce diff for 2 hex files using hex dump as string representation of compared data. """ VERSION = '2.1' USAGE = '''hexdiff: diff dumps of 2 hex files. Usage: python hexdiff.py [options] FILE1 FILE2 Options: -h, --help this help message. -v, --version version info. ''' import sys def main(argv=None): import getopt if argv is None: argv = sys.argv[1:] try: opts, args = getopt.gnu_getopt(argv, 'hv', ['help', 'version']) for o,a in opts: if o in ('-h', '--help'): print(USAGE) return 0 elif o in ('-v', '--version'): print(VERSION) return 0 except getopt.GetoptError: e = sys.exc_info()[1] # current exception sys.stderr.write(str(e)+"\n") sys.stderr.write(USAGE+"\n") return 1 if len(args) != 2: sys.stderr.write("ERROR: You should specify 2 files to diff.\n") sys.stderr.write(USAGE+"\n") return 1 fname1, fname2 = args from intelhex import IntelHex, diff_dumps ih1 = IntelHex(fname1) ih2 = IntelHex(fname2) diff_dumps(ih1, ih2, name1=fname1, name2=fname2) if __name__ == '__main__': sys.exit(main()) intelhex-2.1/scripts/bin2hex.py0000755000175200017530000000735113147236475017356 0ustar builddbuildd00000000000000#!/usr/bin/python # Copyright (c) 2008-2016 Alexander Belchenko # All rights reserved. # # 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 the author 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. '''Intel HEX file format bin2hex convertor utility.''' VERSION = '2.1' if __name__ == '__main__': import getopt import os import sys usage = '''Bin2Hex convertor utility. Usage: python bin2hex.py [options] INFILE [OUTFILE] Arguments: INFILE name of bin file for processing. Use '-' for reading from stdin. OUTFILE name of output file. If omitted then output will be writing to stdout. Options: -h, --help this help message. -v, --version version info. --offset=N offset for loading bin file (default: 0). ''' offset = 0 try: opts, args = getopt.getopt(sys.argv[1:], "hv", ["help", "version", "offset="]) for o, a in opts: if o in ("-h", "--help"): print(usage) sys.exit(0) elif o in ("-v", "--version"): print(VERSION) sys.exit(0) elif o in ("--offset"): base = 10 if a[:2].lower() == '0x': base = 16 try: offset = int(a, base) except: raise getopt.GetoptError('Bad offset value') if not args: raise getopt.GetoptError('Input file is not specified') if len(args) > 2: raise getopt.GetoptError('Too many arguments') except getopt.GetoptError: msg = sys.exc_info()[1] # current exception txt = 'ERROR: '+str(msg) # that's required to get not-so-dumb result from 2to3 tool print(txt) print(usage) sys.exit(2) from intelhex import compat fin = args[0] if fin == '-': # read from stdin fin = compat.get_binary_stdin() elif not os.path.isfile(fin): txt = "ERROR: File not found: %s" % fin # that's required to get not-so-dumb result from 2to3 tool print(txt) sys.exit(1) if len(args) == 2: fout = args[1] else: # write to stdout fout = sys.stdout # compat.get_binary_stdout() from intelhex import bin2hex sys.exit(bin2hex(fin, fout, offset)) intelhex-2.1/scripts/hex2bin.py0000755000175200017530000001110413147236475017345 0ustar builddbuildd00000000000000#!/usr/bin/python # Copyright (c) 2005-2016 Alexander Belchenko # All rights reserved. # # 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 the author 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. '''Intel HEX file format hex2bin convertor utility.''' VERSION = '2.1' if __name__ == '__main__': import getopt import os import sys usage = '''Hex2Bin convertor utility. Usage: python hex2bin.py [options] INFILE [OUTFILE] Arguments: INFILE name of hex file for processing. OUTFILE name of output file. If omitted then output will be writing to stdout. Options: -h, --help this help message. -v, --version version info. -p, --pad=FF pad byte for empty spaces (ascii hex value). -r, --range=START:END specify address range for writing output (ascii hex value). Range can be in form 'START:' or ':END'. -l, --length=NNNN, -s, --size=NNNN size of output (decimal value). ''' pad = None start = None end = None size = None try: opts, args = getopt.getopt(sys.argv[1:], "hvp:r:l:s:", ["help", "version", "pad=", "range=", "length=", "size="]) for o, a in opts: if o in ("-h", "--help"): print(usage) sys.exit(0) elif o in ("-v", "--version"): print(VERSION) sys.exit(0) elif o in ("-p", "--pad"): try: pad = int(a, 16) & 0x0FF except: raise getopt.GetoptError('Bad pad value') elif o in ("-r", "--range"): try: l = a.split(":") if l[0] != '': start = int(l[0], 16) if l[1] != '': end = int(l[1], 16) except: raise getopt.GetoptError('Bad range value(s)') elif o in ("-l", "--lenght", "-s", "--size"): try: size = int(a, 10) except: raise getopt.GetoptError('Bad size value') if start != None and end != None and size != None: raise getopt.GetoptError('Cannot specify START:END and SIZE simultaneously') if not args: raise getopt.GetoptError('Hex file is not specified') if len(args) > 2: raise getopt.GetoptError('Too many arguments') except getopt.GetoptError: msg = sys.exc_info()[1] # current exception txt = 'ERROR: '+str(msg) # that's required to get not-so-dumb result from 2to3 tool print(txt) print(usage) sys.exit(2) fin = args[0] if not os.path.isfile(fin): txt = "ERROR: File not found: %s" % fin # that's required to get not-so-dumb result from 2to3 tool print(txt) sys.exit(1) if len(args) == 2: fout = args[1] else: # write to stdout from intelhex import compat fout = compat.get_binary_stdout() from intelhex import hex2bin sys.exit(hex2bin(fin, fout, start, end, size, pad)) intelhex-2.1/scripts/hex2dump.py0000755000175200017530000001067513147236475017556 0ustar builddbuildd00000000000000#!/usr/bin/python # Copyright (c) 2008-2016 Alexander Belchenko # All rights reserved. # # 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 the author 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. """Show content of hex file as hexdump.""" VERSION = '2.1' USAGE = '''hex2dump: show content of hex file as hexdump. Usage: python hex2dump.py [options] HEXFILE Options: -h, --help this help message. -v, --version version info. -r, --range=START:END specify address range for dumping (ascii hex value). Range can be in form 'START:' or ':END'. --width=N dump N data bytes per line (default: 16). Arguments: HEXFILE name of hex file for processing (use '-' to read from stdin) ''' import sys DEFAULT_WIDTH = 16 def hex2dump(hexfile, start=None, end=None, width=DEFAULT_WIDTH): import intelhex if hexfile == '-': hexfile = sys.stdin try: ih = intelhex.IntelHex(hexfile) except (IOError, intelhex.IntelHexError): e = sys.exc_info()[1] # current exception sys.stderr.write('Error reading file: %s\n' % e) return 1 if not (start is None and end is None): ih = ih[slice(start,end)] ih.dump(tofile=sys.stdout, width=width) return 0 def main(argv=None): import getopt if argv is None: argv = sys.argv[1:] start = None end = None width = DEFAULT_WIDTH try: opts, args = getopt.getopt(sys.argv[1:], "hvp:r:", ["help", "version", "range=", "width="]) for o, a in opts: if o in ("-h", "--help"): print(USAGE) return 0 elif o in ("-v", "--version"): print(VERSION) return 0 elif o in ("-r", "--range"): try: l = a.split(":") if l[0] != '': start = int(l[0], 16) if l[1] != '': end = int(l[1], 16) except: raise getopt.GetoptError('Bad range value(s)') elif o == "--width": try: width = int(a) if width < 1: raise ValueError except: raise getopt.GetoptError('Bad width value (%s)' % a) if not args: raise getopt.GetoptError('Hex file is not specified') if len(args) > 1: raise getopt.GetoptError('Too many arguments') except getopt.GetoptError: msg = sys.exc_info()[1] # current exception txt = 'ERROR: '+str(msg) # that's required to get not-so-dumb result from 2to3 tool print(txt) print(USAGE) return 2 try: return hex2dump(args[0], start, end, width) except IOError: e = sys.exc_info()[1] # current exception import errno if e.errno not in (0, errno.EPIPE): raise if __name__ == '__main__': import sys sys.exit(main()) intelhex-2.1/scripts/hexmerge.py0000755000175200017530000001407613147236475017625 0ustar builddbuildd00000000000000#!/usr/bin/python # Copyright (c) 2008-2016 Alexander Belchenko # All rights reserved. # # 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 the author 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. """Merge content of several hex files into one file.""" VERSION = '2.1' USAGE = '''hexmerge: merge content of hex files. Usage: python hexmerge.py [options] FILES... Options: -h, --help this help message. -v, --version version info. -o, --output=FILENAME output file name (emit output to stdout if option is not specified) -r, --range=START:END specify address range for output (ascii hex value). Both values are inclusive. Range can be in form 'START:' or ':END'. --no-start-addr Don't write start addr to output file. --overlap=METHOD What to do when data in files overlapped. Supported variants: * error -- stop and show error message (default) * ignore -- keep data from first file that contains data at overlapped address * replace -- use data from last file that contains data at overlapped address Arguments: FILES list of hex files for merging (use '-' to read content from stdin) You can specify address range for each file in the form: filename:START:END See description of range option above. You can omit START or END, so supported variants are: filename:START: read filename and use data starting from START addr filename::END read filename and use data till END addr Use entire file content: filename or filename:: ''' import sys def main(args=None): import getopt output = None start = None end = None write_start_addr = True overlap = 'error' if args is None: args = sys.argv[1:] try: opts, args = getopt.gnu_getopt(args, 'hvo:r:', ['help', 'version', 'output=', 'range=', 'no-start-addr', 'overlap=', ]) for o,a in opts: if o in ('-h', '--help'): print(USAGE) return 0 elif o in ('-v', '--version'): print(VERSION) return 0 elif o in ('-o', '--output'): output = a elif o in ("-r", "--range"): try: l = a.split(":") if l[0] != '': start = int(l[0], 16) if l[1] != '': end = int(l[1], 16) except (ValueError, IndexError): raise getopt.GetoptError('Bad range value(s)') elif o == '--no-start-addr': write_start_addr = False elif o == '--overlap': if a in ('error', 'ignore', 'replace'): overlap = a else: raise getopt.GetoptError('Bad overlap value') if len(args) == 0: raise getopt.GetoptError('You should specify file list') except getopt.GetoptError: e = sys.exc_info()[1] # current exception sys.stderr.write(str(e)+"\n") sys.stderr.write(USAGE+"\n") return 1 import intelhex # TODO: move actual merge code into intelhex package as helper function # and write couple of tests for it. res = intelhex.IntelHex() def end_addr_inclusive(addr): if addr is not None: return addr + 1 return addr for f in args: try: fname, fstart, fend = intelhex._get_file_and_addr_range(f) except intelhex._BadFileNotation: sys.stderr.write('Bad argument: "%s"\n' % f) sys.stderr.write(USAGE+"\n") return 1 if fname == '-': fname = sys.stdin ih = intelhex.IntelHex(fname) if (fstart, fend) != (None, None): ih = ih[fstart:end_addr_inclusive(fend)] try: res.merge(ih, overlap) except intelhex.AddressOverlapError: e = sys.exc_info()[1] # current exception sys.stderr.write('Merging: '+fname+"\n") sys.stderr.write(str(e)+"\n") return 1 if (start, end) != (None, None): res = res[start:end_addr_inclusive(end)] if output is None: output = sys.stdout res.write_hex_file(output, write_start_addr) return 0 if __name__ == '__main__': sys.exit(main()) intelhex-2.1/scripts/hexinfo.py0000755000175200017530000000711513147236475017455 0ustar builddbuildd00000000000000#!/usr/bin/python # Copyright (c) 2015 Andrew Fernandes # All rights reserved. # # 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 the author 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. """Summarize the information in a hex file by printing the execution start address (if any), and the address ranges covered by the data (if any), in YAML format. """ VERSION = '2.1' USAGE = '''hexinfo: summarize a hex file's contents. Usage: python hexinfo.py [options] FILE [ FILE ... ] Options: -h, --help this help message. -v, --version version info. ''' import sys INDENT = ' ' INLIST = '- ' def summarize_yaml(fname): print("{:s}file: '{:s}'".format(INLIST, fname)) from intelhex import IntelHex ih = IntelHex(fname) if ih.start_addr: keys = sorted(ih.start_addr.keys()) if keys == ['CS','IP']: entry = ih.start_addr['CS'] * 65536 + ih.start_addr['IP'] elif keys == ['EIP']: entry = ih.start_addr['EIP'] else: raise RuntimeError("unknown 'IntelHex.start_addr' found") print("{:s}entry: 0x{:08X}".format(INDENT, entry)) segments = ih.segments() if segments: print("{:s}data:".format(INDENT)) for s in segments: print("{:s}{:s}{{ first: 0x{:08X}, last: 0x{:08X}, length: 0x{:08X} }}".format(INDENT, INLIST, s[0], s[1]-1, s[1]-s[0])) print("") def main(argv=None): import getopt if argv is None: argv = sys.argv[1:] try: opts, args = getopt.gnu_getopt(argv, 'hv', ['help', 'version']) for o,a in opts: if o in ('-h', '--help'): print(USAGE) return 0 elif o in ('-v', '--version'): print(VERSION) return 0 except getopt.GetoptError: e = sys.exc_info()[1] # current exception sys.stderr.write(str(e)+"\n") sys.stderr.write(USAGE+"\n") return 1 if len(args) < 1: sys.stderr.write("ERROR: You should specify one or more files to summarize.\n") sys.stderr.write(USAGE+"\n") return 1 for fname in args: summarize_yaml(fname) if __name__ == '__main__': sys.exit(main())