| /* |
| * 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; |
| } |