blob: 10d45727e35b51611df9c840b1a6495f56d99f70 [file] [log] [blame]
Yilin Yang19da6932019-12-10 13:39:28 +08001#!/usr/bin/env python3
Hung-Te Lin1990b742017-08-09 17:34:57 +08002# Copyright 2011 The Chromium OS Authors. All rights reserved.
Hung-Te Lind0447d02011-05-19 19:06:00 +08003# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""
7 Chrome OS bitmap block parser.
8
9 This module helps parsing firmware bitmap blocks so that we can
10 retrieve the version and other information from a blob.
11
12 See help(unpack_bmpblock) for more information.
13
14 ref: src/platform/vboot_reference/firmware/include/bmpblk_header.h
15"""
16
17import struct
18import sys
19
20# Constant Definition
Hung-Te Lin56b18402015-01-16 14:52:30 +080021BMPBLOCK_SIGNATURE = '$BMP'
Hung-Te Lind0447d02011-05-19 19:06:00 +080022BMPBLOCK_SIGNATURE_SIZE = 4
23MAX_IMAGE_IN_LAYOUT = 8
24
25# Blob Structure
26
27# typedef struct BmpBlockHeader {
28# uint8_t signature[BMPBLOCK_SIGNATURE_SIZE];
29# uint16_t major_version;
30# uint16_t minor_version;
31# uint32_t number_of_localizations;
32# uint32_t number_of_screenlayouts;
33# uint32_t number_of_imageinfos;
34# uint32_t locale_string_offset;
35# uint32_t reserved[2];
36# };
37FORMAT_BMPBLOCK_HEADER = '<4shhIIII2I'
38NAMES_BMPBLOCK_HEADER = ('signature',
39 'major_version',
40 'minor_version',
41 'number_of_localizations',
42 'number_of_screenlayouts',
43 'number_of_imageinfos',
44 'locale_string_offset',
45 'reserved')
46
47# typedef struct ScreenLayout {
48# struct {
49# uint32_t x;
50# uint32_t y;
51# uint32_t image_info_offset;
52# } images[MAX_IMAGE_IN_LAYOUT];
53# };
54FORMAT_SCREEN_LAYOUT_IMAGE = '<III'
55NAMES_SCREEN_LAYOUT_IMAGE = ('x', 'y', 'image_info_offset')
56
57# typedef struct ImageInfo {
58# uint32_t tag;
59# uint32_t width;
60# uint32_t height;
61# uint32_t format;
62# uint32_t compression;
63# uint32_t original_size;
64# uint32_t compressed_size;
65# uint32_t reserved;
66# };
67FORMAT_IMAGE_INFO = '<IIIIIIII'
68NAMES_IMAGE_INFO = (
69 'tag',
70 'width',
71 'height',
72 'format',
73 'compression',
74 'original_size',
75 'compressed_size',
76 'reserved')
77
78
79def unpack_BmpBlockHeader(blob, offset=0):
80 """ Unpacks a BmpBlockHeader from a blob, starting from offset. """
81 fields = struct.unpack_from(FORMAT_BMPBLOCK_HEADER, blob, offset)
82 header = dict(zip(NAMES_BMPBLOCK_HEADER, fields))
83 # check signature
84 if header['signature'] != BMPBLOCK_SIGNATURE:
Hung-Te Lineec4e332017-06-01 23:16:40 +080085 raise ValueError('unknown bmpblock signature: %s' % header['signature'])
Hung-Te Lind0447d02011-05-19 19:06:00 +080086 return header
87
88
89def unpack_ImageInfo(blob, offset=0):
90 """ Unpacks a ImageInfo from a blob, starting from offset. """
91 fields = struct.unpack_from(FORMAT_IMAGE_INFO, blob, offset)
92 info = dict(zip(NAMES_IMAGE_INFO, fields))
93 return info
94
95
96def unpack_ScreenLayout(blob, base=0, offset=0):
97 """ Unpacks a ScreenLayout from a blob, starting from offset. """
98 layout = []
Tammo Spalink01e11722012-07-24 10:17:54 -070099 for _ in range(MAX_IMAGE_IN_LAYOUT):
Hung-Te Lind0447d02011-05-19 19:06:00 +0800100 fields = struct.unpack_from(FORMAT_SCREEN_LAYOUT_IMAGE, blob, offset)
101 offset += struct.calcsize(FORMAT_SCREEN_LAYOUT_IMAGE)
102 image = dict(zip(NAMES_SCREEN_LAYOUT_IMAGE, fields))
103 info_offset = image['image_info_offset']
104 if info_offset > 0:
105 image.update(unpack_ImageInfo(blob, base + info_offset))
106 layout.append(image)
107 return layout
108
109
110def unpack_LocaleString(blob, base=0, offset=0):
111 """ Unpacks a double NUL-terminated locale string, starting from offset. """
112 end = blob.find('\x00\x00', base + offset)
113 if end < 0:
114 return []
115 locale_string = blob[base + offset:end]
116 return locale_string.split('\x00')
117
118
119def unpack_bmpblock(blob, offset=0):
Hung-Te Lin56b18402015-01-16 14:52:30 +0800120 """Unpacks a Chrome OS Bitmap Block.
Hung-Te Lind0447d02011-05-19 19:06:00 +0800121
122 Returns a dictionary of unpacked data
123 """
124 data = unpack_BmpBlockHeader(blob, offset)
125 layout_offset = offset + struct.calcsize(FORMAT_BMPBLOCK_HEADER)
126 localizations = []
Tammo Spalink01e11722012-07-24 10:17:54 -0700127 for _ in range(data['number_of_localizations']):
Hung-Te Lind0447d02011-05-19 19:06:00 +0800128 layouts = []
Tammo Spalink01e11722012-07-24 10:17:54 -0700129 for _ in range(data['number_of_screenlayouts']):
Hung-Te Lind0447d02011-05-19 19:06:00 +0800130 layouts.append(unpack_ScreenLayout(blob, offset, layout_offset))
131 layout_offset += (struct.calcsize(FORMAT_SCREEN_LAYOUT_IMAGE) *
132 MAX_IMAGE_IN_LAYOUT)
133 localizations.append(layouts)
134 data['localizations'] = localizations
135 # locale string is optional.
136 locale_string_offset = data['locale_string_offset']
137 data['locales'] = (unpack_LocaleString(blob, offset, locale_string_offset)
138 if locale_string_offset else [])
139 return data
140
141
142# -----------------------------------------------------------------------------
143
144
Peter Shih533566a2018-09-05 17:48:03 +0800145def main():
Hung-Te Lind0447d02011-05-19 19:06:00 +0800146 # Only load pprint if we are in console (debug / test) mode
147 import pprint
148 for filename in sys.argv[1:]:
Hung-Te Lin56b18402015-01-16 14:52:30 +0800149 bmpblk = unpack_bmpblock(open(filename, 'rb').read(), 0)
Yilin Yang71e39412019-09-24 09:26:46 +0800150 print(pprint.pformat(bmpblk))
Peter Shih533566a2018-09-05 17:48:03 +0800151
152
153# When running in command line, try to report blob in the parameters
154if __name__ == '__main__':
155 main()