blob: ba4d72ef23b87c2ccdab47ca89f0ea58bfe9160b [file] [log] [blame]
/*
* Copyright 2012-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.facebook.buck.android;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.step.ExecutionContext;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Optional;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
/**
* If we end up creating both an obfuscator function and a deobfuscator function, it would be
* nice to load the proguard mapping file once. This class enables sharing that work.
*/
class ProguardTranslatorFactory {
private final Optional<Map<String, String>> rawMap;
private ProguardTranslatorFactory(Optional<Map<String, String>> rawMap) {
this.rawMap = rawMap;
}
static ProguardTranslatorFactory create(
ExecutionContext context,
Optional<Path> proguardFullConfigFile,
Optional<Path> proguardMappingFile)
throws IOException {
return new ProguardTranslatorFactory(
loadOptionalRawMap(context, proguardFullConfigFile, proguardMappingFile));
}
@VisibleForTesting
static ProguardTranslatorFactory createForTest(Optional<Map<String, String>> rawMap) {
return new ProguardTranslatorFactory(rawMap);
}
private static Optional<Map<String, String>> loadOptionalRawMap(
ExecutionContext context,
Optional<Path> proguardFullConfigFile,
Optional<Path> proguardMappingFile)
throws IOException {
if (!proguardFullConfigFile.isPresent()) {
return Optional.absent();
}
ProjectFilesystem projectFilesystem = context.getProjectFilesystem();
Path pathToProguardConfig = proguardFullConfigFile.get();
// Proguard doesn't print a mapping when obfuscation is disabled.
boolean obfuscationSkipped = Iterables.any(
projectFilesystem.readLines(pathToProguardConfig),
Predicates.equalTo("-dontobfuscate"));
if (obfuscationSkipped) {
return Optional.absent();
}
List<String> lines = projectFilesystem.readLines(proguardMappingFile.get());
return Optional.of(ProguardMapping.readClassMapping(lines));
}
public Function<String, String> createDeobfuscationFunction() {
return createFunction(false);
}
public Function<String, String> createObfuscationFunction() {
return createFunction(true);
}
private Function<String, String> createFunction(boolean isForObfuscation) {
if (!rawMap.isPresent()) {
return Functions.identity();
}
ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
for (Map.Entry<String, String> entry : rawMap.get().entrySet()) {
String original = entry.getKey().replace('.', '/');
String obfuscated = entry.getValue().replace('.', '/');
builder.put(
isForObfuscation ? original : obfuscated,
isForObfuscation ? obfuscated : original);
}
final Map<String, String> map = builder.build();
return new Function<String, String>() {
@Override
public String apply(String input) {
String mapped = map.get(input);
if (mapped != null) {
return mapped;
} else {
return input;
}
}
};
}
}