15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/data_pack.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/memory_mapped_file.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted_memory.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_piece.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For details of the file layout, see 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://dev.chromium.org/developers/design-documents/linuxresourcesandlocalizedstrings 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const uint32 kFileFormatVersion = 4; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Length of file header: version, entry count and text encoding type. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const size_t kHeaderLength = 2 * sizeof(uint32) + sizeof(uint8); 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma pack(push,2) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct DataPackEntry { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16 resource_id; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 file_offset; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int CompareById(const void* void_key, const void* void_entry) { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16 key = *reinterpret_cast<const uint16*>(void_key); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DataPackEntry* entry = 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<const DataPackEntry*>(void_entry); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (key < entry->resource_id) { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (key > entry->resource_id) { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma pack(pop) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMPILE_ASSERT(sizeof(DataPackEntry) == 6, size_of_entry_must_be_six); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We're crashing when trying to load a pak file on Windows. Add some error 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// codes for logging. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://crbug.com/58056 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum LoadErrors { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INIT_FAILED = 1, 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BAD_VERSION, 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INDEX_TRUNCATED, 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ENTRY_NOT_FOUND, 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HEADER_TRUNCATED, 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WRONG_ENCODING, 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INIT_FAILED_FROM_FILE, 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOAD_ERRORS_COUNT, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ui { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DataPack::DataPack(ui::ScaleFactor scale_factor) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : resource_count_(0), 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) text_encoding_type_(BINARY), 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scale_factor_(scale_factor) { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DataPack::~DataPack() { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DataPack::LoadFromPath(const base::FilePath& path) { 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_.reset(new base::MemoryMappedFile); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!mmap_->Initialize(path)) { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Failed to mmap datapack"; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INIT_FAILED, 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOAD_ERRORS_COUNT); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mmap_.reset(); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LoadImpl(); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool DataPack::LoadFromFile(base::File file) { 885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return LoadFromFileRegion(file.Pass(), 895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::MemoryMappedFile::Region::kWholeFile); 905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool DataPack::LoadFromFileRegion( 935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::File file, 945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const base::MemoryMappedFile::Region& region) { 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mmap_.reset(new base::MemoryMappedFile); 965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!mmap_->Initialize(file.Pass(), region)) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Failed to mmap datapack"; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INIT_FAILED_FROM_FILE, 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOAD_ERRORS_COUNT); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mmap_.reset(); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LoadImpl(); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DataPack::LoadImpl() { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sanity check the header of the file. 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (kHeaderLength > mmap_->length()) { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Data pack file corruption: incomplete file header."; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("DataPack.Load", HEADER_TRUNCATED, 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOAD_ERRORS_COUNT); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mmap_.reset(); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Parse the header of the file. 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First uint32: version; second: resource count; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint32* ptr = reinterpret_cast<const uint32*>(mmap_->data()); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 version = ptr[0]; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (version != kFileFormatVersion) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Bad data pack version: got " << version << ", expected " 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << kFileFormatVersion; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("DataPack.Load", BAD_VERSION, 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOAD_ERRORS_COUNT); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mmap_.reset(); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_count_ = ptr[1]; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // third: text encoding. 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint8* ptr_encoding = reinterpret_cast<const uint8*>(ptr + 2); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) text_encoding_type_ = static_cast<TextEncodingType>(*ptr_encoding); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (text_encoding_type_ != UTF8 && text_encoding_type_ != UTF16 && 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) text_encoding_type_ != BINARY) { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Bad data pack text encoding: got " << text_encoding_type_ 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << ", expected between " << BINARY << " and " << UTF16; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("DataPack.Load", WRONG_ENCODING, 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOAD_ERRORS_COUNT); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mmap_.reset(); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sanity check the file. 144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // 1) Check we have enough entries. There's an extra entry after the last item 145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // which gives the length of the last item. 146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (kHeaderLength + (resource_count_ + 1) * sizeof(DataPackEntry) > 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mmap_->length()) { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Data pack file corruption: too short for number of " 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "entries specified."; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INDEX_TRUNCATED, 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOAD_ERRORS_COUNT); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mmap_.reset(); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2) Verify the entries are within the appropriate bounds. There's an extra 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // entry after the last item which gives us the length of the last item. 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < resource_count_ + 1; ++i) { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DataPackEntry* entry = reinterpret_cast<const DataPackEntry*>( 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mmap_->data() + kHeaderLength + (i * sizeof(DataPackEntry))); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (entry->file_offset > mmap_->length()) { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Entry #" << i << " in data pack points off end of file. " 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Was the file corrupted?"; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("DataPack.Load", ENTRY_NOT_FOUND, 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOAD_ERRORS_COUNT); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mmap_.reset(); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DataPack::HasResource(uint16 resource_id) const { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !!bsearch(&resource_id, mmap_->data() + kHeaderLength, resource_count_, 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(DataPackEntry), DataPackEntry::CompareById); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DataPack::GetStringPiece(uint16 resource_id, 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringPiece* data) const { 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It won't be hard to make this endian-agnostic, but it's not worth 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bothering to do right now. 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__BYTE_ORDER) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Linux check 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) datapack_assumes_little_endian); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(__BIG_ENDIAN__) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mac check 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) #error DataPack assumes little endian 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DataPackEntry* target = reinterpret_cast<const DataPackEntry*>( 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bsearch(&resource_id, mmap_->data() + kHeaderLength, resource_count_, 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(DataPackEntry), DataPackEntry::CompareById)); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!target) { 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const DataPackEntry* next_entry = target + 1; 199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // If the next entry points beyond the end of the file this data pack's entry 200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // table is corrupt. Log an error and return false. See 201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // http://crbug.com/371301. 202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (next_entry->file_offset > mmap_->length()) { 203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t entry_index = target - 204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) reinterpret_cast<const DataPackEntry*>(mmap_->data() + kHeaderLength); 205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) LOG(ERROR) << "Entry #" << entry_index << " in data pack points off end " 206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) << "of file. This should have been caught when loading. Was the " 207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) << "file modified?"; 208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return false; 209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) size_t length = next_entry->file_offset - target->file_offset; 212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) data->set(reinterpret_cast<const char*>(mmap_->data() + target->file_offset), 213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) length); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::RefCountedStaticMemory* DataPack::GetStaticMemory( 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16 resource_id) const { 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringPiece piece; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetStringPiece(resource_id, &piece)) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return new base::RefCountedStaticMemory(piece.data(), piece.length()); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ResourceHandle::TextEncodingType DataPack::GetTextEncodingType() const { 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return text_encoding_type_; 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ui::ScaleFactor DataPack::GetScaleFactor() const { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return scale_factor_; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DataPack::WritePack(const base::FilePath& path, 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::map<uint16, base::StringPiece>& resources, 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TextEncodingType textEncodingType) { 238a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) FILE* file = base::OpenFile(path, "wb"); 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!file) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fwrite(&kFileFormatVersion, sizeof(kFileFormatVersion), 1, file) != 1) { 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to write file version"; 244a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CloseFile(file); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: the python version of this function explicitly sorted keys, but 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // std::map is a sorted associative container, we shouldn't have to do that. 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 entry_count = resources.size(); 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fwrite(&entry_count, sizeof(entry_count), 1, file) != 1) { 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to write entry count"; 253a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CloseFile(file); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (textEncodingType != UTF8 && textEncodingType != UTF16 && 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) textEncodingType != BINARY) { 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Invalid text encoding type, got " << textEncodingType 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << ", expected between " << BINARY << " and " << UTF16; 261a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CloseFile(file); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8 write_buffer = textEncodingType; 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fwrite(&write_buffer, sizeof(uint8), 1, file) != 1) { 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to write file text resources encoding"; 268a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CloseFile(file); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Each entry is a uint16 + a uint32. We have an extra entry after the last 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // item so we can compute the size of the list item. 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 index_length = (entry_count + 1) * sizeof(DataPackEntry); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 data_offset = kHeaderLength + index_length; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::map<uint16, base::StringPiece>::const_iterator it = 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resources.begin(); 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != resources.end(); ++it) { 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16 resource_id = it->first; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fwrite(&resource_id, sizeof(resource_id), 1, file) != 1) { 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to write id for " << resource_id; 282a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CloseFile(file); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fwrite(&data_offset, sizeof(data_offset), 1, file) != 1) { 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to write offset for " << resource_id; 288a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CloseFile(file); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data_offset += it->second.length(); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We place an extra entry after the last item that allows us to read the 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // size of the last item. 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint16 resource_id = 0; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fwrite(&resource_id, sizeof(resource_id), 1, file) != 1) { 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to write extra resource id."; 300a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CloseFile(file); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fwrite(&data_offset, sizeof(data_offset), 1, file) != 1) { 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to write extra offset."; 306a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CloseFile(file); 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::map<uint16, base::StringPiece>::const_iterator it = 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resources.begin(); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != resources.end(); ++it) { 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fwrite(it->second.data(), it->second.length(), 1, file) != 1) { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to write data for " << it->first; 315a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CloseFile(file); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 320a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CloseFile(file); 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace ui 326