blob: 49e077fc2af6ed137ea108615cceb3170ad65c4e [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* 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.
*/
#include <utils/ObbFile.h>
#include <utils/String8.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
using namespace android;
static const char* gProgName = "obbtool";
static const char* gProgVersion = "1.0";
static int wantUsage = 0;
static int wantVersion = 0;
#define ADD_OPTS "n:v:o"
static const struct option longopts[] = {
{"help", no_argument, &wantUsage, 1},
{"version", no_argument, &wantVersion, 1},
/* Args for "add" */
{"name", required_argument, NULL, 'n'},
{"version", required_argument, NULL, 'v'},
{"overlay", optional_argument, NULL, 'o'},
{NULL, 0, NULL, '\0'}
};
struct package_info_t {
char* packageName;
int packageVersion;
bool overlay;
};
/*
* Print usage info.
*/
void usage(void)
{
fprintf(stderr, "Opaque Binary Blob (OBB) Tool\n\n");
fprintf(stderr, "Usage:\n");
fprintf(stderr,
" %s a[dd] [ OPTIONS ] FILENAME\n"
" Adds an OBB signature to the file.\n\n", gProgName);
fprintf(stderr,
" %s r[emove] FILENAME\n"
" Removes the OBB signature from the file.\n\n", gProgName);
fprintf(stderr,
" %s i[nfo] FILENAME\n"
" Prints the OBB signature information of a file.\n\n", gProgName);
}
void doAdd(const char* filename, struct package_info_t* info) {
ObbFile *obb = new ObbFile();
if (obb->readFrom(filename)) {
fprintf(stderr, "ERROR: %s: OBB signature already present\n", filename);
return;
}
obb->setPackageName(String8(info->packageName));
obb->setVersion(info->packageVersion);
obb->setOverlay(info->overlay);
if (!obb->writeTo(filename)) {
fprintf(stderr, "ERROR: %s: couldn't write OBB signature: %s\n",
filename, strerror(errno));
return;
}
fprintf(stderr, "OBB signature successfully written\n");
}
void doRemove(const char* filename) {
ObbFile *obb = new ObbFile();
if (!obb->readFrom(filename)) {
fprintf(stderr, "ERROR: %s: no OBB signature present\n", filename);
return;
}
if (!obb->removeFrom(filename)) {
fprintf(stderr, "ERROR: %s: couldn't remove OBB signature\n", filename);
return;
}
fprintf(stderr, "OBB signature successfully removed\n");
}
void doInfo(const char* filename) {
ObbFile *obb = new ObbFile();
if (!obb->readFrom(filename)) {
fprintf(stderr, "ERROR: %s: couldn't read OBB signature\n", filename);
return;
}
printf("OBB info for '%s':\n", filename);
printf("Package name: %s\n", obb->getPackageName().string());
printf(" Version: %d\n", obb->getVersion());
printf(" Flags: 0x%08x\n", obb->getFlags());
printf(" Overlay: %s\n", obb->isOverlay() ? "true" : "false");
}
/*
* Parse args.
*/
int main(int argc, char* const argv[])
{
const char *prog = argv[0];
struct options *options;
int opt;
int option_index = 0;
struct package_info_t package_info;
int result = 1; // pessimistically assume an error.
if (argc < 2) {
wantUsage = 1;
goto bail;
}
while ((opt = getopt_long(argc, argv, ADD_OPTS, longopts, &option_index)) != -1) {
switch (opt) {
case 0:
if (longopts[option_index].flag)
break;
fprintf(stderr, "'%s' requires an argument\n", longopts[option_index].name);
wantUsage = 1;
goto bail;
case 'n':
package_info.packageName = optarg;
break;
case 'v': {
char *end;
package_info.packageVersion = strtol(optarg, &end, 10);
if (*optarg == '\0' || *end != '\0') {
fprintf(stderr, "ERROR: invalid version; should be integer!\n\n");
wantUsage = 1;
goto bail;
}
break;
}
case 'o':
package_info.overlay = true;
break;
case '?':
wantUsage = 1;
goto bail;
}
}
if (wantVersion) {
fprintf(stderr, "%s %s\n", gProgName, gProgVersion);
}
if (wantUsage) {
goto bail;
}
#define CHECK_OP(name) \
if (strncmp(op, name, opsize)) { \
fprintf(stderr, "ERROR: unknown function '%s'!\n\n", op); \
wantUsage = 1; \
goto bail; \
}
if (optind < argc) {
const char* op = argv[optind++];
const int opsize = strlen(op);
if (optind >= argc) {
fprintf(stderr, "ERROR: filename required!\n\n");
wantUsage = 1;
goto bail;
}
const char* filename = argv[optind++];
switch (op[0]) {
case 'a':
CHECK_OP("add");
if (package_info.packageName == NULL) {
fprintf(stderr, "ERROR: arguments required 'packageName' and 'version'\n");
goto bail;
}
doAdd(filename, &package_info);
break;
case 'r':
CHECK_OP("remove");
doRemove(filename);
break;
case 'i':
CHECK_OP("info");
doInfo(filename);
break;
default:
fprintf(stderr, "ERROR: unknown command '%s'!\n\n", op);
wantUsage = 1;
goto bail;
}
}
bail:
if (wantUsage) {
usage();
result = 2;
}
return result;
}