Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(253)

Side by Side Diff: grit/format/data_pack.py

Issue 1442863002: Remove contents of grit's SVN repository. (Closed) Base URL: http://grit-i18n.googlecode.com/svn/trunk/
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « grit/format/chrome_messages_json_unittest.py ('k') | grit/format/data_pack_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Support for formatting a data pack file used for platform agnostic resource
7 files.
8 """
9
10 import collections
11 import exceptions
12 import os
13 import struct
14 import sys
15 if __name__ == '__main__':
16 sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
17
18 from grit import util
19 from grit.node import include
20 from grit.node import message
21 from grit.node import structure
22
23
24 PACK_FILE_VERSION = 4
25 HEADER_LENGTH = 2 * 4 + 1 # Two uint32s. (file version, number of entries) and
26 # one uint8 (encoding of text resources)
27 BINARY, UTF8, UTF16 = range(3)
28
29
30 class WrongFileVersion(Exception):
31 pass
32
33
34 DataPackContents = collections.namedtuple(
35 'DataPackContents', 'resources encoding')
36
37
38 def Format(root, lang='en', output_dir='.'):
39 """Writes out the data pack file format (platform agnostic resource file)."""
40 data = {}
41 for node in root.ActiveDescendants():
42 with node:
43 if isinstance(node, (include.IncludeNode, message.MessageNode,
44 structure.StructureNode)):
45 id, value = node.GetDataPackPair(lang, UTF8)
46 if value is not None:
47 data[id] = value
48 return WriteDataPackToString(data, UTF8)
49
50
51 def ReadDataPack(input_file):
52 """Reads a data pack file and returns a dictionary."""
53 data = util.ReadFile(input_file, util.BINARY)
54 original_data = data
55
56 # Read the header.
57 version, num_entries, encoding = struct.unpack('<IIB', data[:HEADER_LENGTH])
58 if version != PACK_FILE_VERSION:
59 print 'Wrong file version in ', input_file
60 raise WrongFileVersion
61
62 resources = {}
63 if num_entries == 0:
64 return DataPackContents(resources, encoding)
65
66 # Read the index and data.
67 data = data[HEADER_LENGTH:]
68 kIndexEntrySize = 2 + 4 # Each entry is a uint16 and a uint32.
69 for _ in range(num_entries):
70 id, offset = struct.unpack('<HI', data[:kIndexEntrySize])
71 data = data[kIndexEntrySize:]
72 next_id, next_offset = struct.unpack('<HI', data[:kIndexEntrySize])
73 resources[id] = original_data[offset:next_offset]
74
75 return DataPackContents(resources, encoding)
76
77
78 def WriteDataPackToString(resources, encoding):
79 """Returns a string with a map of id=>data in the data pack format."""
80 ids = sorted(resources.keys())
81 ret = []
82
83 # Write file header.
84 ret.append(struct.pack('<IIB', PACK_FILE_VERSION, len(ids), encoding))
85 HEADER_LENGTH = 2 * 4 + 1 # Two uint32s and one uint8.
86
87 # Each entry is a uint16 + a uint32s. We have one extra entry for the last
88 # item.
89 index_length = (len(ids) + 1) * (2 + 4)
90
91 # Write index.
92 data_offset = HEADER_LENGTH + index_length
93 for id in ids:
94 ret.append(struct.pack('<HI', id, data_offset))
95 data_offset += len(resources[id])
96
97 ret.append(struct.pack('<HI', 0, data_offset))
98
99 # Write data.
100 for id in ids:
101 ret.append(resources[id])
102 return ''.join(ret)
103
104
105 def WriteDataPack(resources, output_file, encoding):
106 """Writes a map of id=>data into output_file as a data pack."""
107 content = WriteDataPackToString(resources, encoding)
108 with open(output_file, 'wb') as file:
109 file.write(content)
110
111
112 def RePack(output_file, input_files, whitelist_file=None):
113 """Write a new data pack file by combining input pack files.
114
115 Args:
116 output_file: path to the new data pack file.
117 input_files: a list of paths to the data pack files to combine.
118 whitelist_file: path to the file that contains the list of resource IDs
119 that should be kept in the output file or None to include
120 all resources.
121
122 Raises:
123 KeyError: if there are duplicate keys or resource encoding is
124 inconsistent.
125 """
126 input_data_packs = [ReadDataPack(filename) for filename in input_files]
127 whitelist = None
128 if whitelist_file:
129 whitelist = util.ReadFile(whitelist_file, util.RAW_TEXT).strip().split('\n')
130 whitelist = set(map(int, whitelist))
131 resources, encoding = RePackFromDataPackStrings(input_data_packs, whitelist)
132 WriteDataPack(resources, output_file, encoding)
133
134
135 def RePackFromDataPackStrings(inputs, whitelist):
136 """Returns a data pack string that combines the resources from inputs.
137
138 Args:
139 inputs: a list of data pack strings that need to be combined.
140 whitelist: a list of resource IDs that should be kept in the output string
141 or None to include all resources.
142
143 Returns:
144 DataPackContents: a tuple containing the new combined data pack and its
145 encoding.
146
147 Raises:
148 KeyError: if there are duplicate keys or resource encoding is
149 inconsistent.
150 """
151 resources = {}
152 encoding = None
153 for content in inputs:
154 # Make sure we have no dups.
155 duplicate_keys = set(content.resources.keys()) & set(resources.keys())
156 if duplicate_keys:
157 raise exceptions.KeyError('Duplicate keys: ' + str(list(duplicate_keys)))
158
159 # Make sure encoding is consistent.
160 if encoding in (None, BINARY):
161 encoding = content.encoding
162 elif content.encoding not in (BINARY, encoding):
163 raise exceptions.KeyError('Inconsistent encodings: ' + str(encoding) +
164 ' vs ' + str(content.encoding))
165
166 if whitelist:
167 whitelisted_resources = dict([(key, content.resources[key])
168 for key in content.resources.keys()
169 if key in whitelist])
170 resources.update(whitelisted_resources)
171 removed_keys = [key for key in content.resources.keys()
172 if key not in whitelist]
173 for key in removed_keys:
174 print 'RePackFromDataPackStrings Removed Key:', key
175 else:
176 resources.update(content.resources)
177
178 # Encoding is 0 for BINARY, 1 for UTF8 and 2 for UTF16
179 if encoding is None:
180 encoding = BINARY
181 return DataPackContents(resources, encoding)
182
183
184 # Temporary hack for external programs that import data_pack.
185 # TODO(benrg): Remove this.
186 class DataPack(object):
187 pass
188 DataPack.ReadDataPack = staticmethod(ReadDataPack)
189 DataPack.WriteDataPackToString = staticmethod(WriteDataPackToString)
190 DataPack.WriteDataPack = staticmethod(WriteDataPack)
191 DataPack.RePack = staticmethod(RePack)
192
193
194 def main():
195 if len(sys.argv) > 1:
196 # When an argument is given, read and explode the file to text
197 # format, for easier diffing.
198 data = ReadDataPack(sys.argv[1])
199 print data.encoding
200 for (resource_id, text) in data.resources.iteritems():
201 print '%s: %s' % (resource_id, text)
202 else:
203 # Just write a simple file.
204 data = {1: '', 4: 'this is id 4', 6: 'this is id 6', 10: ''}
205 WriteDataPack(data, 'datapack1.pak', UTF8)
206 data2 = {1000: 'test', 5: 'five'}
207 WriteDataPack(data2, 'datapack2.pak', UTF8)
208 print 'wrote datapack1 and datapack2 to current directory.'
209
210
211 if __name__ == '__main__':
212 main()
OLDNEW
« no previous file with comments | « grit/format/chrome_messages_json_unittest.py ('k') | grit/format/data_pack_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698