Skip to content

Commit

Permalink
Extract helper methods for mapping files and serialization
Browse files Browse the repository at this point in the history
Summary: This diff extracts helper functions out for mapping files, and handling serialized bytes. This functionality was getting used from a couple of different places (i.e. passes, instr tests, etc) and in subsequent diffs I'll have some more use cases.

Reviewed By: maxmg22

Differential Revision: D6488826

fbshipit-source-id: 0e3e547115f81555fdcd0f5259382592862e7b9d
  • Loading branch information
wsanville authored and facebook-github-bot committed Dec 8, 2017
1 parent 50e3b3b commit b39e7ae
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 75 deletions.
12 changes: 12 additions & 0 deletions libredex/RedexResources.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@

std::string read_entire_file(const std::string& filename);
void write_entire_file(const std::string& filename, const std::string& contents);
void* map_file(
const char* path,
int& file_descriptor,
size_t& length,
const bool mode_write = false);
size_t write_serialized_data(
const android::Vector<char>& cVec,
int file_descriptor,
void* file_pointer,
const size_t& length);
void unmap_and_close(int file_descriptor, void* file_pointer, size_t length);

std::string get_string_attribute_value(const android::ResXMLTree& parser,
const android::String16& attribute_name);
bool has_raw_attribute_value(
Expand Down
55 changes: 55 additions & 0 deletions libresource/RedexResources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
#include <boost/filesystem.hpp>
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <fstream>
#include <map>
#include <boost/regex.hpp>
#include <sstream>
#include <string>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unordered_set>
#include <vector>

Expand All @@ -25,8 +28,12 @@
#endif

#include "androidfw/ResourceTypes.h"
#include "utils/ByteOrder.h"
#include "utils/Errors.h"
#include "utils/Log.h"
#include "utils/String16.h"
#include "utils/String8.h"
#include "utils/Serialize.h"
#include "utils/TypeHelpers.h"

#include "StringUtil.h"
Expand Down Expand Up @@ -762,3 +769,51 @@ std::unordered_set<std::string> get_native_classes(const std::string& apk_direct
}
return all_classes;
}

void* map_file(
const char* path,
int& file_descriptor,
size_t& length,
const bool mode_write) {
file_descriptor = open(path, mode_write ? O_RDWR : O_RDONLY);
if (file_descriptor <= 0) {
throw std::runtime_error("Failed to open arsc file");
}
struct stat st = {};
if (fstat(file_descriptor, &st) == -1) {
close(file_descriptor);
throw std::runtime_error("Failed to get file length");
}
length = (size_t)st.st_size;
int flags = PROT_READ;
if (mode_write) {
flags |= PROT_WRITE;
}
void* fp = mmap(nullptr, length, flags, MAP_SHARED, file_descriptor, 0);
if (fp == MAP_FAILED) {
close(file_descriptor);
throw std::runtime_error("Failed to mmap file");
}
return fp;
}

void unmap_and_close(int file_descriptor, void* file_pointer, size_t length) {
munmap(file_pointer, length);
close(file_descriptor);
}

size_t write_serialized_data(
const android::Vector<char>& cVec,
int file_descriptor,
void* file_pointer,
const size_t& length) {
size_t vec_size = cVec.size();
if (vec_size > 0) {
memcpy(file_pointer, &(cVec[0]), vec_size);
}

munmap(file_pointer, length);
ftruncate(file_descriptor, cVec.size());
close(file_descriptor);
return vec_size > 0 ? vec_size : length;
}
76 changes: 1 addition & 75 deletions libresource/ResourceTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "utils/ByteOrder.h"
#include "utils/Debug.h"
#include "utils/Log.h"
#include "utils/Serialize.h"
#include "utils/String16.h"
#include "utils/String8.h"

Expand Down Expand Up @@ -468,81 +469,6 @@ void ResStringPool::appendString(String8 s) {
mAppendedStrings.push_back(s);
}

void align_vec(Vector<char>& cVec, size_t s) {
size_t r = cVec.size() % s;
if (r > 0) {
for (size_t i = s - r; i > 0; i--) {
cVec.push_back(0);
}
}
}

void push_short(Vector<char>& cVec, uint16_t data) {
auto swapped = dtohs(data);
cVec.push_back(swapped);
cVec.push_back(swapped >> 8);
}

void push_long(Vector<char>& cVec, uint32_t data) {
auto swapped = dtohl(data);
cVec.push_back(swapped);
cVec.push_back(swapped >> 8);
cVec.push_back(swapped >> 16);
cVec.push_back(swapped >> 24);
}

void push_u8_length(Vector<char>& cVec, size_t len) {
// If len > 2^7-1, then set the most significant bit, then use a second byte
// to describe the length (leaving 15 bits for the actual len).
if (len >= 0x80) {
const auto mask = 0x8000;
LOG_FATAL_IF(len >= mask, "String length too large");
// Set the high bit, then push it in two pieces (can't just push short).
uint16_t encoded = mask | len;
uint8_t high = encoded >> 8;
uint8_t low = encoded & 0xFF;
cVec.push_back(high);
cVec.push_back(low);
} else {
cVec.push_back((char) len);
}
}

void encode_string8(Vector<char>& cVec, String8 s) {
// aapt2 writes both the utf16 length followed by utf8 length
size_t len = s.length();
const uint8_t* u8_str = (const uint8_t*) s.string();
auto u16_len = utf8_to_utf16_length(u8_str, len);
push_u8_length(cVec, u16_len);
push_u8_length(cVec, len);
// Push each char
for (uint8_t* c = (uint8_t*) u8_str; *c; c++) {
cVec.push_back(*c);
}
cVec.push_back('\0');
}

void encode_string16(Vector<char>& cVec, String16 s) {
// Push uint16_t (2 bytes) describing the length. If length > 2^15-1, then set
// most significant bit, then use two uint16_t to describe the length (first
// uint16_t will be the high word).
auto len = s.size();
if (len >= 0x8000) {
const auto mask = 0x80000000;
LOG_FATAL_IF(len >= mask, "String length too large");
uint32_t encoded = mask | len;
push_short(cVec, encoded >> 16);
push_short(cVec, encoded & 0xFFFF);
} else {
push_short(cVec, (uint16_t)len);
}
auto u16_str = s.string();
for (uint16_t* c = (uint16_t*)u16_str; *c; c++) {
push_short(cVec, *c);
}
push_short(cVec, '\0');
}

void ResStringPool::serializeWithAdditionalStrings(Vector<char>& cVec) {
LOG_FATAL_IF(
mHeader->styleCount > 0,
Expand Down
95 changes: 95 additions & 0 deletions libresource/Serialize.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* Copyright (c) 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#include "utils/ByteOrder.h"
#include "utils/Debug.h"
#include "utils/Log.h"
#include "utils/String16.h"
#include "utils/String8.h"
#include "utils/Unicode.h"
#include "utils/Vector.h"

namespace android {

void align_vec(android::Vector<char>& cVec, size_t s) {
size_t r = cVec.size() % s;
if (r > 0) {
for (size_t i = s - r; i > 0; i--) {
cVec.push_back(0);
}
}
}

void push_short(android::Vector<char>& cVec, uint16_t data) {
auto swapped = dtohs(data);
cVec.push_back(swapped);
cVec.push_back(swapped >> 8);
}

void push_long(android::Vector<char>& cVec, uint32_t data) {
auto swapped = dtohl(data);
cVec.push_back(swapped);
cVec.push_back(swapped >> 8);
cVec.push_back(swapped >> 16);
cVec.push_back(swapped >> 24);
}

void push_u8_length(android::Vector<char>& cVec, size_t len) {
// If len > 2^7-1, then set the most significant bit, then use a second byte
// to describe the length (leaving 15 bits for the actual len).
if (len >= 0x80) {
const auto mask = 0x8000;
LOG_FATAL_IF(len >= mask, "String length too large");
// Set the high bit, then push it in two pieces (can't just push short).
uint16_t encoded = mask | len;
uint8_t high = encoded >> 8;
uint8_t low = encoded & 0xFF;
cVec.push_back(high);
cVec.push_back(low);
} else {
cVec.push_back((char) len);
}
}

void encode_string8(android::Vector<char>& cVec, android::String8 s) {
// aapt2 writes both the utf16 length followed by utf8 length
size_t len = s.length();
const uint8_t* u8_str = (const uint8_t*) s.string();
auto u16_len = utf8_to_utf16_length(u8_str, len);
push_u8_length(cVec, u16_len);
push_u8_length(cVec, len);
// Push each char
for (uint8_t* c = (uint8_t*) u8_str; *c; c++) {
cVec.push_back(*c);
}
cVec.push_back('\0');
}

void encode_string16(android::Vector<char>& cVec, android::String16 s) {
// Push uint16_t (2 bytes) describing the length. If length > 2^15-1, then set
// most significant bit, then use two uint16_t to describe the length (first
// uint16_t will be the high word).
auto len = s.size();
if (len >= 0x8000) {
const auto mask = 0x80000000;
LOG_FATAL_IF(len >= mask, "String length too large");
uint32_t encoded = mask | len;
push_short(cVec, encoded >> 16);
push_short(cVec, encoded & 0xFFFF);
} else {
push_short(cVec, (uint16_t)len);
}
auto u16_str = s.string();
for (uint16_t* c = (uint16_t*)u16_str; *c; c++) {
push_short(cVec, *c);
}
push_short(cVec, '\0');
}

} // namespace android
31 changes: 31 additions & 0 deletions libresource/utils/Serialize.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Copyright (c) 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#ifndef _FB_ANDROID_SERIALIZE_H
#define _FB_ANDROID_SERIALIZE_H

#include "utils/ByteOrder.h"
#include "utils/Debug.h"
#include "utils/Log.h"
#include "utils/String16.h"
#include "utils/String8.h"
#include "utils/Unicode.h"
#include "utils/Vector.h"

namespace android {

void align_vec(android::Vector<char>& cVec, size_t s);
void push_short(android::Vector<char>& cVec, uint16_t data);
void push_long(android::Vector<char>& cVec, uint32_t data);
void push_u8_length(android::Vector<char>& cVec, size_t len);
void encode_string8(android::Vector<char>& cVec, android::String8 s);
void encode_string16(android::Vector<char>& cVec, android::String16 s);

}
#endif

0 comments on commit b39e7ae

Please sign in to comment.