Commit ade347f5 authored by agrieve's avatar agrieve Committed by Commit Bot

Add deduplication logic to .pak files

Now, when multiple entries contain the same content, multiple
table-of-contents entries will be created, but only one data region.

As of now, en-US.pak has ~3200 entries, and 350 of them are duplicates.

For MonochromePublic.apk, shrinks uncompressed .pak size by ~130kb, and
compressed .pak size by 32kb.

BUG=738566

Review-Url: https://codereview.chromium.org/2969123002
Cr-Commit-Position: refs/heads/master@{#488215}
parent a8360926
...@@ -562,12 +562,17 @@ def PrintPakAnalysis(apk_filename, min_pak_resource_size): ...@@ -562,12 +562,17 @@ def PrintPakAnalysis(apk_filename, min_pak_resource_size):
# Calculate aggregate stats about resources across pak files. # Calculate aggregate stats about resources across pak files.
resource_count_map = collections.defaultdict(int) resource_count_map = collections.defaultdict(int)
resource_size_map = collections.defaultdict(int) resource_size_map = collections.defaultdict(int)
seen_data_ids = set()
alias_overhead_bytes = 4
resource_overhead_bytes = 6 resource_overhead_bytes = 6
for pak in paks: for pak in paks:
for r in pak.resources: for k, v in pak.resources.iteritems():
resource_count_map[r] += 1 resource_count_map[k] += 1
resource_size_map[r] += len(pak.resources[r]) + resource_overhead_bytes if id(v) not in seen_data_ids:
seen_data_ids.add(id(v))
resource_size_map[k] += resource_overhead_bytes + len(v)
else:
resource_size_map[k] += alias_overhead_bytes
# Output the overall resource summary. # Output the overall resource summary.
total_resource_size = sum(resource_size_map.values()) total_resource_size = sum(resource_size_map.values())
total_resource_count = len(resource_count_map) total_resource_count = len(resource_count_map)
......
...@@ -21,9 +21,7 @@ from grit.node import message ...@@ -21,9 +21,7 @@ from grit.node import message
from grit.node import structure from grit.node import structure
PACK_FILE_VERSION = 4 PACK_FILE_VERSION = 5
HEADER_LENGTH = 2 * 4 + 1 # Two uint32s. (file version, number of entries) and
# one uint8 (encoding of text resources)
BINARY, UTF8, UTF16 = range(3) BINARY, UTF8, UTF16 = range(3)
...@@ -31,6 +29,10 @@ class WrongFileVersion(Exception): ...@@ -31,6 +29,10 @@ class WrongFileVersion(Exception):
pass pass
class CorruptDataPack(Exception):
pass
DataPackContents = collections.namedtuple( DataPackContents = collections.namedtuple(
'DataPackContents', 'resources encoding') 'DataPackContents', 'resources encoding')
...@@ -49,56 +51,100 @@ def Format(root, lang='en', output_dir='.'): ...@@ -49,56 +51,100 @@ def Format(root, lang='en', output_dir='.'):
def ReadDataPack(input_file): def ReadDataPack(input_file):
return ReadDataPackFromString(util.ReadFile(input_file, util.BINARY))
def ReadDataPackFromString(data):
"""Reads a data pack file and returns a dictionary.""" """Reads a data pack file and returns a dictionary."""
data = util.ReadFile(input_file, util.BINARY)
original_data = data original_data = data
# Read the header. # Read the header.
version, num_entries, encoding = struct.unpack('<IIB', data[:HEADER_LENGTH]) version = struct.unpack('<I', data[:4])[0]
if version != PACK_FILE_VERSION: if version == 4:
print 'Wrong file version in ', input_file resource_count, encoding = struct.unpack('<IB', data[4:9])
raise WrongFileVersion alias_count = 0
data = data[9:]
elif version == 5:
encoding, resource_count, alias_count = struct.unpack('<BxxxHH', data[4:12])
data = data[12:]
else:
raise WrongFileVersion('Found version: ' + str(version))
resources = {} resources = {}
if num_entries == 0:
return DataPackContents(resources, encoding)
# Read the index and data.
data = data[HEADER_LENGTH:]
kIndexEntrySize = 2 + 4 # Each entry is a uint16 and a uint32. kIndexEntrySize = 2 + 4 # Each entry is a uint16 and a uint32.
for _ in range(num_entries): def entry_at_index(idx):
id, offset = struct.unpack('<HI', data[:kIndexEntrySize]) offset = idx * kIndexEntrySize
data = data[kIndexEntrySize:] return struct.unpack('<HI', data[offset:offset + kIndexEntrySize])
next_id, next_offset = struct.unpack('<HI', data[:kIndexEntrySize])
resources[id] = original_data[offset:next_offset] prev_resource_id, prev_offset = entry_at_index(0)
for i in xrange(1, resource_count + 1):
resource_id, offset = entry_at_index(i)
resources[prev_resource_id] = original_data[prev_offset:offset]
prev_resource_id, prev_offset = resource_id, offset
# Read the alias table.
alias_data = data[(resource_count + 1) * kIndexEntrySize:]
kAliasEntrySize = 2 + 2 # uint16, uint16
def alias_at_index(idx):
offset = idx * kAliasEntrySize
return struct.unpack('<HH', alias_data[offset:offset + kAliasEntrySize])
for i in xrange(alias_count):
resource_id, index = alias_at_index(i)
aliased_id = entry_at_index(index)[0]
resources[resource_id] = resources[aliased_id]
return DataPackContents(resources, encoding) return DataPackContents(resources, encoding)
def WriteDataPackToString(resources, encoding): def WriteDataPackToString(resources, encoding):
"""Returns a string with a map of id=>data in the data pack format.""" """Returns a string with a map of id=>data in the data pack format."""
ids = sorted(resources.keys())
ret = [] ret = []
# Write file header. # Compute alias map.
ret.append(struct.pack('<IIB', PACK_FILE_VERSION, len(ids), encoding)) resource_ids = sorted(resources)
HEADER_LENGTH = 2 * 4 + 1 # Two uint32s and one uint8. # Use reversed() so that for duplicates lower IDs clobber higher ones.
id_by_data = {resources[k]: k for k in reversed(resource_ids)}
# Each entry is a uint16 + a uint32s. We have one extra entry for the last # Map of resource_id -> resource_id, where value < key.
# item. alias_map = {k: id_by_data[v] for k, v in resources.iteritems()
index_length = (len(ids) + 1) * (2 + 4) if id_by_data[v] != k}
# Write index.
data_offset = HEADER_LENGTH + index_length
for id in ids:
ret.append(struct.pack('<HI', id, data_offset))
data_offset += len(resources[id])
# Write file header.
resource_count = len(resources) - len(alias_map)
# Padding bytes added for alignment.
ret.append(struct.pack('<IBxxxHH', PACK_FILE_VERSION, encoding,
resource_count, len(alias_map)))
HEADER_LENGTH = 4 + 4 + 2 + 2
# Each main table entry is: uint16 + uint32 (and an extra entry at the end).
# Each alias table entry is: uint16 + uint16.
data_offset = HEADER_LENGTH + (resource_count + 1) * 6 + len(alias_map) * 4
# Write main table.
index_by_id = {}
deduped_data = []
index = 0
for resource_id in resource_ids:
if resource_id in alias_map:
continue
data = resources[resource_id]
index_by_id[resource_id] = index
ret.append(struct.pack('<HI', resource_id, data_offset))
data_offset += len(data)
deduped_data.append(data)
index += 1
assert index == resource_count
# Add an extra entry at the end.
ret.append(struct.pack('<HI', 0, data_offset)) ret.append(struct.pack('<HI', 0, data_offset))
# Write alias table.
for resource_id in sorted(alias_map):
index = index_by_id[alias_map[resource_id]]
ret.append(struct.pack('<HH', resource_id, index))
# Write data. # Write data.
for id in ids: ret.extend(deduped_data)
ret.append(resources[id])
return ''.join(ret) return ''.join(ret)
......
...@@ -17,8 +17,8 @@ from grit.format import data_pack ...@@ -17,8 +17,8 @@ from grit.format import data_pack
class FormatDataPackUnittest(unittest.TestCase): class FormatDataPackUnittest(unittest.TestCase):
def testWriteDataPack(self): def testReadDataPackV4(self):
expected = ( expected_data = (
'\x04\x00\x00\x00' # header(version '\x04\x00\x00\x00' # header(version
'\x04\x00\x00\x00' # no. entries, '\x04\x00\x00\x00' # no. entries,
'\x01' # encoding) '\x01' # encoding)
...@@ -28,9 +28,42 @@ class FormatDataPackUnittest(unittest.TestCase): ...@@ -28,9 +28,42 @@ class FormatDataPackUnittest(unittest.TestCase):
'\x0a\x00\x3f\x00\x00\x00' # index entry 10 '\x0a\x00\x3f\x00\x00\x00' # index entry 10
'\x00\x00\x3f\x00\x00\x00' # extra entry for the size of last '\x00\x00\x3f\x00\x00\x00' # extra entry for the size of last
'this is id 4this is id 6') # data 'this is id 4this is id 6') # data
input = {1: '', 4: 'this is id 4', 6: 'this is id 6', 10: ''} expected_resources = {
output = data_pack.WriteDataPackToString(input, data_pack.UTF8) 1: '',
self.failUnless(output == expected) 4: 'this is id 4',
6: 'this is id 6',
10: '',
}
expected_data_pack = data_pack.DataPackContents(
expected_resources, data_pack.UTF8)
loaded = data_pack.ReadDataPackFromString(expected_data)
self.assertEquals(loaded, expected_data_pack)
def testReadWriteDataPackV5(self):
expected_data = (
'\x05\x00\x00\x00' # version
'\x01\x00\x00\x00' # encoding & padding
'\x03\x00' # resource_count
'\x01\x00' # alias_count
'\x01\x00\x28\x00\x00\x00' # index entry 1
'\x04\x00\x28\x00\x00\x00' # index entry 4
'\x06\x00\x34\x00\x00\x00' # index entry 6
'\x00\x00\x40\x00\x00\x00' # extra entry for the size of last
'\x0a\x00\x01\x00' # alias table
'this is id 4this is id 6') # data
expected_resources = {
1: '',
4: 'this is id 4',
6: 'this is id 6',
10: 'this is id 4',
}
data = data_pack.WriteDataPackToString(expected_resources, data_pack.UTF8)
self.assertEquals(data, expected_data)
expected_data_pack = data_pack.DataPackContents(
expected_resources, data_pack.UTF8)
loaded = data_pack.ReadDataPackFromString(expected_data)
self.assertEquals(loaded, expected_data_pack)
def testRePackUnittest(self): def testRePackUnittest(self):
expected_with_whitelist = { expected_with_whitelist = {
...@@ -50,12 +83,14 @@ class FormatDataPackUnittest(unittest.TestCase): ...@@ -50,12 +83,14 @@ class FormatDataPackUnittest(unittest.TestCase):
in inputs] in inputs]
# RePack using whitelist # RePack using whitelist
output, _ = data_pack.RePackFromDataPackStrings(inputs, whitelist) output, _ = data_pack.RePackFromDataPackStrings(
inputs, whitelist, suppress_removed_key_output=True)
self.assertDictEqual(expected_with_whitelist, output, self.assertDictEqual(expected_with_whitelist, output,
'Incorrect resource output') 'Incorrect resource output')
# RePack a None whitelist # RePack a None whitelist
output, _ = data_pack.RePackFromDataPackStrings(inputs, None) output, _ = data_pack.RePackFromDataPackStrings(
inputs, None, suppress_removed_key_output=True)
self.assertDictEqual(expected_without_whitelist, output, self.assertDictEqual(expected_without_whitelist, output,
'Incorrect resource output') 'Incorrect resource output')
......
...@@ -33,6 +33,7 @@ def _ExtractMain(args): ...@@ -33,6 +33,7 @@ def _ExtractMain(args):
def _PrintMain(args): def _PrintMain(args):
pak = data_pack.ReadDataPack(args.pak_file) pak = data_pack.ReadDataPack(args.pak_file)
id_map = {id(v): k for k, v in sorted(pak.resources.items(), reverse=True)}
encoding = 'binary' encoding = 'binary'
if pak.encoding == 1: if pak.encoding == 1:
encoding = 'utf-8' encoding = 'utf-8'
...@@ -57,8 +58,13 @@ def _PrintMain(args): ...@@ -57,8 +58,13 @@ def _PrintMain(args):
except UnicodeDecodeError: except UnicodeDecodeError:
pass pass
sha1 = hashlib.sha1(data).hexdigest()[:10] sha1 = hashlib.sha1(data).hexdigest()[:10]
line = u'Entry(id={}, len={}, sha1={}): {}'.format( canonical_id = id_map[id(data)]
resource_id, len(data), sha1, desc) if resource_id == canonical_id:
line = u'Entry(id={}, len={}, sha1={}): {}'.format(
resource_id, len(data), sha1, desc)
else:
line = u'Entry(id={}, alias_of={}): {}'.format(
resource_id, canonical_id, desc)
print line.encode('utf-8') print line.encode('utf-8')
......
...@@ -788,6 +788,7 @@ test("ui_base_unittests") { ...@@ -788,6 +788,7 @@ test("ui_base_unittests") {
"material_design/material_design_controller_unittest.cc", "material_design/material_design_controller_unittest.cc",
"models/tree_node_iterator_unittest.cc", "models/tree_node_iterator_unittest.cc",
"resource/data_pack_literal.cc", "resource/data_pack_literal.cc",
"resource/data_pack_literal.h",
"resource/data_pack_unittest.cc", "resource/data_pack_unittest.cc",
"resource/resource_bundle_unittest.cc", "resource/resource_bundle_unittest.cc",
"resource/scale_factor_unittest.cc", "resource/scale_factor_unittest.cc",
......
This diff is collapsed.
...@@ -75,6 +75,8 @@ class UI_DATA_PACK_EXPORT DataPack : public ResourceHandle { ...@@ -75,6 +75,8 @@ class UI_DATA_PACK_EXPORT DataPack : public ResourceHandle {
#endif #endif
private: private:
struct Entry;
struct Alias;
class DataSource; class DataSource;
class BufferDataSource; class BufferDataSource;
class MemoryMappedDataSource; class MemoryMappedDataSource;
...@@ -82,11 +84,14 @@ class UI_DATA_PACK_EXPORT DataPack : public ResourceHandle { ...@@ -82,11 +84,14 @@ class UI_DATA_PACK_EXPORT DataPack : public ResourceHandle {
// Does the actual loading of a pack file. // Does the actual loading of a pack file.
// Called by Load and LoadFromFile and LoadFromBuffer. // Called by Load and LoadFromFile and LoadFromBuffer.
bool LoadImpl(std::unique_ptr<DataSource> data_source); bool LoadImpl(std::unique_ptr<DataSource> data_source);
const Entry* LookupEntryById(uint16_t resource_id) const;
std::unique_ptr<DataSource> data_source_; std::unique_ptr<DataSource> data_source_;
// Number of resources in the data. const Entry* resource_table_;
size_t resource_count_; size_t resource_count_;
const Alias* alias_table_;
size_t alias_count_;
// Type of encoding for text resources. // Type of encoding for text resources.
TextEncodingType text_encoding_type_; TextEncodingType text_encoding_type_;
......
...@@ -4,57 +4,71 @@ ...@@ -4,57 +4,71 @@
#include <stddef.h> #include <stddef.h>
#include "ui/base/resource/data_pack_literal.h"
namespace ui { namespace ui {
extern const char kSamplePakContents[] = { const char kSamplePakContentsV4[] = {
0x04, 0x00, 0x00, 0x00, // header(version 0x04, 0x00, 0x00, 0x00, // header(version
0x04, 0x00, 0x00, 0x00, // no. entries 0x04, 0x00, 0x00, 0x00, // no. entries
0x01, // encoding) 0x01, // encoding)
0x01, 0x00, 0x27, 0x00, 0x00, 0x00, // index entry 1 0x01, 0x00, 0x27, 0x00, 0x00, 0x00, // index entry 1
0x04, 0x00, 0x27, 0x00, 0x00, 0x00, // index entry 4 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, // index entry 4
0x06, 0x00, 0x33, 0x00, 0x00, 0x00, // index entry 6 0x06, 0x00, 0x33, 0x00, 0x00, 0x00, // index entry 6
0x0a, 0x00, 0x3f, 0x00, 0x00, 0x00, // index entry 10 0x0a, 0x00, 0x3f, 0x00, 0x00, 0x00, // index entry 10
0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, // extra entry for the size of last 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, // extra entry for the size of last
't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '4', 't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '4',
't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '6' 't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '6'};
};
extern const size_t kSamplePakSize = sizeof(kSamplePakContents); const size_t kSamplePakSizeV4 = sizeof(kSamplePakContentsV4);
extern const char kSampleCorruptPakContents[] = {
0x04, 0x00, 0x00, 0x00, // header(version
0x04, 0x00, 0x00, 0x00, // no. entries
0x01, // encoding)
0x01, 0x00, 0x27, 0x00, 0x00, 0x00, // index entry 1
0x04, 0x00, 0x27, 0x00, 0x00, 0x00, // index entry 4
0x06, 0x00, 0x33, 0x00, 0x00, 0x00, // index entry 6
0x0a, 0x00, 0x3f, 0x00, 0x00, 0x00, // index entry 10
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // extra entry for the size of last,
// extends past END OF FILE.
't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '4',
't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '6'
};
extern const size_t kSampleCorruptPakSize = sizeof(kSampleCorruptPakContents); const char kSamplePakContentsV5[] = {
0x05, 0x00, 0x00, 0x00, // version
0x01, 0x00, 0x00, 0x00, // encoding + padding
0x03, 0x00, 0x01, 0x00, // num_resources, num_aliases
0x01, 0x00, 0x28, 0x00, 0x00, 0x00, // index entry 1
0x04, 0x00, 0x28, 0x00, 0x00, 0x00, // index entry 4
0x06, 0x00, 0x34, 0x00, 0x00, 0x00, // index entry 6
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // extra entry for the size of last
0x0a, 0x00, 0x01, 0x00, // alias table
't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '4',
't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '6'};
extern const char kSamplePakContents2x[] = { const size_t kSamplePakSizeV5 = sizeof(kSamplePakContentsV5);
0x04, 0x00, 0x00, 0x00, // header(version
0x01, 0x00, 0x00, 0x00, // no. entries const char kSampleCorruptPakContents[] = {
0x01, // encoding) 0x04, 0x00, 0x00, 0x00, // header(version
0x04, 0x00, 0x15, 0x00, 0x00, 0x00, // index entry 4 0x04, 0x00, 0x00, 0x00, // no. entries
0x00, 0x00, 0x24, 0x00, 0x00, 0x00, // extra entry for the size of last 0x01, // encoding)
't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '4', ' ', '2', 'x' 0x01, 0x00, 0x27, 0x00, 0x00, 0x00, // index entry 1
}; 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, // index entry 4
0x06, 0x00, 0x33, 0x00, 0x00, 0x00, // index entry 6
0x0a, 0x00, 0x3f, 0x00, 0x00, 0x00, // index entry 10
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // extra entry for the size of last,
// extends past END OF FILE.
't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '4', 't', 'h', 'i',
's', ' ', 'i', 's', ' ', 'i', 'd', ' ', '6'};
const size_t kSampleCorruptPakSize = sizeof(kSampleCorruptPakContents);
const char kSamplePakContents2x[] = {
0x04, 0x00, 0x00, 0x00, // header(version
0x01, 0x00, 0x00, 0x00, // no. entries
0x01, // encoding)
0x04, 0x00, 0x15, 0x00, 0x00, 0x00, // index entry 4
0x00, 0x00, 0x24, 0x00, 0x00, 0x00, // extra entry for the size of last
't', 'h', 'i', 's', ' ', 'i', 's', ' ',
'i', 'd', ' ', '4', ' ', '2', 'x'};
extern const size_t kSamplePakSize2x = sizeof(kSamplePakContents2x); const size_t kSamplePakSize2x = sizeof(kSamplePakContents2x);
extern const char kEmptyPakContents[] = { const char kEmptyPakContents[] = {
0x04, 0x00, 0x00, 0x00, // header(version 0x04, 0x00, 0x00, 0x00, // header(version
0x00, 0x00, 0x00, 0x00, // no. entries 0x00, 0x00, 0x00, 0x00, // no. entries
0x01, // encoding) 0x01, // encoding)
0x00, 0x00, 0x0f, 0x00, 0x00, 0x00 // extra entry for the size of last 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00 // extra entry for the size of last
}; };
extern const size_t kEmptyPakSize = sizeof(kEmptyPakContents); const size_t kEmptyPakSize = sizeof(kEmptyPakContents);
} // namespace ui } // namespace ui
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_BASE_RESOURCE_DATA_PACK_LITERAL_H_
#define UI_BASE_RESOURCE_DATA_PACK_LITERAL_H_
namespace ui {
extern const char kSamplePakContentsV4[];
extern const size_t kSamplePakSizeV4;
extern const char kSamplePakContentsV5[];
extern const size_t kSamplePakSizeV5;
extern const char kSamplePakContents2x[];
extern const size_t kSamplePakSize2x;
extern const char kEmptyPakContents[];
extern const size_t kEmptyPakSize;
extern const char kSampleCorruptPakContents[];
extern const size_t kSampleCorruptPakSize;
} // namespace ui
#endif // UI_BASE_RESOURCE_DATA_PACK_LITERAL_H_
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/resource/data_pack_literal.h"
#include "ui/base/ui_base_paths.h" #include "ui/base/ui_base_paths.h"
namespace ui { namespace ui {
...@@ -27,11 +28,6 @@ class DataPackTest ...@@ -27,11 +28,6 @@ class DataPackTest
DataPackTest() {} DataPackTest() {}
}; };
extern const char kSamplePakContents[];
extern const char kSampleCorruptPakContents[];
extern const size_t kSamplePakSize;
extern const size_t kSampleCorruptPakSize;
TEST(DataPackTest, LoadFromPath) { TEST(DataPackTest, LoadFromPath) {
base::ScopedTempDir dir; base::ScopedTempDir dir;
ASSERT_TRUE(dir.CreateUniqueTempDir()); ASSERT_TRUE(dir.CreateUniqueTempDir());
...@@ -39,8 +35,8 @@ TEST(DataPackTest, LoadFromPath) { ...@@ -39,8 +35,8 @@ TEST(DataPackTest, LoadFromPath) {
dir.GetPath().Append(FILE_PATH_LITERAL("sample.pak")); dir.GetPath().Append(FILE_PATH_LITERAL("sample.pak"));
// Dump contents into the pak file. // Dump contents into the pak file.
ASSERT_EQ(base::WriteFile(data_path, kSamplePakContents, kSamplePakSize), ASSERT_EQ(base::WriteFile(data_path, kSamplePakContentsV4, kSamplePakSizeV4),
static_cast<int>(kSamplePakSize)); static_cast<int>(kSamplePakSizeV4));
// Load the file through the data pack API. // Load the file through the data pack API.
DataPack pack(SCALE_FACTOR_100P); DataPack pack(SCALE_FACTOR_100P);
...@@ -72,8 +68,8 @@ TEST(DataPackTest, LoadFromFile) { ...@@ -72,8 +68,8 @@ TEST(DataPackTest, LoadFromFile) {
dir.GetPath().Append(FILE_PATH_LITERAL("sample.pak")); dir.GetPath().Append(FILE_PATH_LITERAL("sample.pak"));
// Dump contents into the pak file. // Dump contents into the pak file.
ASSERT_EQ(base::WriteFile(data_path, kSamplePakContents, kSamplePakSize), ASSERT_EQ(base::WriteFile(data_path, kSamplePakContentsV4, kSamplePakSizeV4),
static_cast<int>(kSamplePakSize)); static_cast<int>(kSamplePakSizeV4));
base::File file(data_path, base::File::FLAG_OPEN | base::File::FLAG_READ); base::File file(data_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
ASSERT_TRUE(file.IsValid()); ASSERT_TRUE(file.IsValid());
...@@ -112,15 +108,15 @@ TEST(DataPackTest, LoadFromFileRegion) { ...@@ -112,15 +108,15 @@ TEST(DataPackTest, LoadFromFileRegion) {
const char kPadding[5678] = {0}; const char kPadding[5678] = {0};
ASSERT_EQ(static_cast<int>(sizeof(kPadding)), ASSERT_EQ(static_cast<int>(sizeof(kPadding)),
base::WriteFile(data_path, kPadding, sizeof(kPadding))); base::WriteFile(data_path, kPadding, sizeof(kPadding)));
ASSERT_TRUE(base::AppendToFile( ASSERT_TRUE(
data_path, kSamplePakContents, kSamplePakSize)); base::AppendToFile(data_path, kSamplePakContentsV4, kSamplePakSizeV4));
base::File file(data_path, base::File::FLAG_OPEN | base::File::FLAG_READ); base::File file(data_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
ASSERT_TRUE(file.IsValid()); ASSERT_TRUE(file.IsValid());
// Load the file through the data pack API. // Load the file through the data pack API.
DataPack pack(SCALE_FACTOR_100P); DataPack pack(SCALE_FACTOR_100P);
base::MemoryMappedFile::Region region = {sizeof(kPadding), kSamplePakSize}; base::MemoryMappedFile::Region region = {sizeof(kPadding), kSamplePakSizeV4};
ASSERT_TRUE(pack.LoadFromFileRegion(std::move(file), region)); ASSERT_TRUE(pack.LoadFromFileRegion(std::move(file), region));
base::StringPiece data; base::StringPiece data;
...@@ -142,11 +138,11 @@ TEST(DataPackTest, LoadFromFileRegion) { ...@@ -142,11 +138,11 @@ TEST(DataPackTest, LoadFromFileRegion) {
ASSERT_FALSE(pack.GetStringPiece(140, &data)); ASSERT_FALSE(pack.GetStringPiece(140, &data));
} }
TEST(DataPackTest, LoadFromBuffer) { TEST(DataPackTest, LoadFromBufferV4) {
DataPack pack(SCALE_FACTOR_100P); DataPack pack(SCALE_FACTOR_100P);
ASSERT_TRUE(pack.LoadFromBuffer( ASSERT_TRUE(pack.LoadFromBuffer(
base::StringPiece(kSamplePakContents, kSamplePakSize))); base::StringPiece(kSamplePakContentsV4, kSamplePakSizeV4)));
base::StringPiece data; base::StringPiece data;
ASSERT_TRUE(pack.HasResource(4)); ASSERT_TRUE(pack.HasResource(4));
...@@ -167,6 +163,31 @@ TEST(DataPackTest, LoadFromBuffer) { ...@@ -167,6 +163,31 @@ TEST(DataPackTest, LoadFromBuffer) {
ASSERT_FALSE(pack.GetStringPiece(140, &data)); ASSERT_FALSE(pack.GetStringPiece(140, &data));
} }
TEST(DataPackTest, LoadFromBufferV5) {
DataPack pack(SCALE_FACTOR_100P);
ASSERT_TRUE(pack.LoadFromBuffer(
base::StringPiece(kSamplePakContentsV5, kSamplePakSizeV5)));
base::StringPiece data;
ASSERT_TRUE(pack.HasResource(4));
ASSERT_TRUE(pack.GetStringPiece(4, &data));
EXPECT_EQ("this is id 4", data);
ASSERT_TRUE(pack.HasResource(6));
ASSERT_TRUE(pack.GetStringPiece(6, &data));
EXPECT_EQ("this is id 6", data);
// Try reading zero-length data blobs, just in case.
ASSERT_TRUE(pack.GetStringPiece(1, &data));
EXPECT_EQ(0U, data.length());
ASSERT_TRUE(pack.GetStringPiece(10, &data));
EXPECT_EQ("this is id 4", data);
// Try looking up an invalid key.
ASSERT_FALSE(pack.HasResource(140));
ASSERT_FALSE(pack.GetStringPiece(140, &data));
}
INSTANTIATE_TEST_CASE_P(WriteBINARY, DataPackTest, ::testing::Values( INSTANTIATE_TEST_CASE_P(WriteBINARY, DataPackTest, ::testing::Values(
DataPack::BINARY)); DataPack::BINARY));
INSTANTIATE_TEST_CASE_P(WriteUTF8, DataPackTest, ::testing::Values( INSTANTIATE_TEST_CASE_P(WriteUTF8, DataPackTest, ::testing::Values(
...@@ -228,8 +249,8 @@ TEST(DataPackTest, ModifiedWhileUsed) { ...@@ -228,8 +249,8 @@ TEST(DataPackTest, ModifiedWhileUsed) {
dir.GetPath().Append(FILE_PATH_LITERAL("sample.pak")); dir.GetPath().Append(FILE_PATH_LITERAL("sample.pak"));
// Dump contents into the pak file. // Dump contents into the pak file.
ASSERT_EQ(base::WriteFile(data_path, kSamplePakContents, kSamplePakSize), ASSERT_EQ(base::WriteFile(data_path, kSamplePakContentsV4, kSamplePakSizeV4),
static_cast<int>(kSamplePakSize)); static_cast<int>(kSamplePakSizeV4));
base::File file(data_path, base::File::FLAG_OPEN | base::File::FLAG_READ); base::File file(data_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
ASSERT_TRUE(file.IsValid()); ASSERT_TRUE(file.IsValid());
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/layout.h" #include "ui/base/layout.h"
#include "ui/base/resource/data_pack.h" #include "ui/base/resource/data_pack.h"
#include "ui/base/resource/data_pack_literal.h"
#include "ui/gfx/codec/png_codec.h" #include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/font_list.h" #include "ui/gfx/font_list.h"
#include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia.h"
...@@ -38,14 +39,6 @@ using ::testing::Return; ...@@ -38,14 +39,6 @@ using ::testing::Return;
using ::testing::ReturnArg; using ::testing::ReturnArg;
namespace ui { namespace ui {
extern const char kSamplePakContents[];
extern const size_t kSamplePakSize;
extern const char kSamplePakContents2x[];
extern const size_t kSamplePakSize2x;
extern const char kEmptyPakContents[];
extern const size_t kEmptyPakSize;
namespace { namespace {
const unsigned char kPngMagic[8] = { 0x89, 'P', 'N', 'G', 13, 10, 26, 10 }; const unsigned char kPngMagic[8] = { 0x89, 'P', 'N', 'G', 13, 10, 26, 10 };
...@@ -416,8 +409,8 @@ TEST_F(ResourceBundleImageTest, GetRawDataResource) { ...@@ -416,8 +409,8 @@ TEST_F(ResourceBundleImageTest, GetRawDataResource) {
dir_path().Append(FILE_PATH_LITERAL("sample_2x.pak")); dir_path().Append(FILE_PATH_LITERAL("sample_2x.pak"));
// Dump contents into the pak files. // Dump contents into the pak files.
ASSERT_EQ(base::WriteFile(data_path, kSamplePakContents, ASSERT_EQ(base::WriteFile(data_path, kSamplePakContentsV4, kSamplePakSizeV4),
kSamplePakSize), static_cast<int>(kSamplePakSize)); static_cast<int>(kSamplePakSizeV4));
ASSERT_EQ(base::WriteFile(data_2x_path, kSamplePakContents2x, ASSERT_EQ(base::WriteFile(data_2x_path, kSamplePakContents2x,
kSamplePakSize2x), static_cast<int>(kSamplePakSize2x)); kSamplePakSize2x), static_cast<int>(kSamplePakSize2x));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment