1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2010 The Android Open Source Project
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License.
6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License.
15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <androidfw/ObbFile.h>
18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <utils/String8.h>
19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <getopt.h>
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <stdio.h>
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <stdlib.h>
23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#include <string.h>
24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiusing namespace android;
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char* gProgName = "obbtool";
28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const char* gProgVersion = "1.0";
29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic int wantUsage = 0;
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic int wantVersion = 0;
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#define SALT_LEN 8
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#define ADD_OPTS "n:v:os:"
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskistatic const struct option longopts[] = {
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {"help",       no_argument, &wantUsage,   1},
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {"version",    no_argument, &wantVersion, 1},
39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /* Args for "add" */
41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {"name",       required_argument, NULL, 'n'},
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {"version",    required_argument, NULL, 'v'},
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {"overlay",    optional_argument, NULL, 'o'},
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {"salt",       required_argument, NULL, 's'},
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {NULL, 0, NULL, '\0'}
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiclass PackageInfo {
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic:
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    PackageInfo()
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            : packageName(NULL)
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            , packageVersion(-1)
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            , overlay(false)
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            , salted(false)
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    {
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        memset(&salt, 0, sizeof(salt));
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    char* packageName;
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int packageVersion;
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool overlay;
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    bool salted;
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    unsigned char salt[SALT_LEN];
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski};
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Print usage info.
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid usage(void)
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stderr, "Opaque Binary Blob (OBB) Tool\n\n");
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stderr, "Usage:\n");
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stderr,
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        " %s a[dd] [ OPTIONS ] FILENAME\n"
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "   Adds an OBB signature to the file.\n\n", gProgName);
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stderr,
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "   Options:\n"
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "     -n <package name>      sets the OBB package name (required)\n"
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "     -v <OBB version>       sets the OBB version (required)\n"
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "     -o                     sets the OBB overlay flag\n"
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "     -s <8 byte hex salt>   sets the crypto key salt (if encrypted)\n"
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "\n");
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stderr,
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        " %s r[emove] FILENAME\n"
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "   Removes the OBB signature from the file.\n\n", gProgName);
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stderr,
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        " %s i[nfo] FILENAME\n"
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        "   Prints the OBB signature information of a file.\n\n", gProgName);
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
924eedc1018f46bf2ce1d8780a1fd6415700c4ee1dBrian Carlstromvoid doAdd(const char* filename, PackageInfo* info) {
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ObbFile *obb = new ObbFile();
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (obb->readFrom(filename)) {
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: %s: OBB signature already present\n", filename);
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    obb->setPackageName(String8(info->packageName));
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    obb->setVersion(info->packageVersion);
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    obb->setOverlay(info->overlay);
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (info->salted) {
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        obb->setSalt(info->salt, SALT_LEN);
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!obb->writeTo(filename)) {
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: %s: couldn't write OBB signature: %s\n",
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                filename, strerror(errno));
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stderr, "OBB signature successfully written\n");
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid doRemove(const char* filename) {
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ObbFile *obb = new ObbFile();
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!obb->readFrom(filename)) {
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: %s: no OBB signature present\n", filename);
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!obb->removeFrom(filename)) {
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: %s: couldn't remove OBB signature\n", filename);
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    fprintf(stderr, "OBB signature successfully removed\n");
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskivoid doInfo(const char* filename) {
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    ObbFile *obb = new ObbFile();
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!obb->readFrom(filename)) {
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: %s: couldn't read OBB signature\n", filename);
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return;
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("OBB info for '%s':\n", filename);
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("Package name: %s\n", obb->getPackageName().string());
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("     Version: %d\n", obb->getVersion());
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("       Flags: 0x%08x\n", obb->getFlags());
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("     Overlay: %s\n", obb->isOverlay() ? "true" : "false");
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    printf("        Salt: ");
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    size_t saltLen;
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    const unsigned char* salt = obb->getSalt(&saltLen);
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (salt != NULL) {
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i = 0; i < SALT_LEN; i++) {
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            printf("%02x", salt[i]);
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("\n");
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else {
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        printf("<empty>\n");
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool fromHex(char h, unsigned char *b) {
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (h >= '0' && h <= '9') {
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *b = h - '0';
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return true;
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (h >= 'a' && h <= 'f') {
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *b = h - 'a' + 10;
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return true;
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    } else if (h >= 'A' && h <= 'F') {
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        *b = h - 'A' + 10;
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return true;
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return false;
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibool hexToByte(char h1, char h2, unsigned char* b) {
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    unsigned char first, second;
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!fromHex(h1, &first)) return false;
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (!fromHex(h2, &second)) return false;
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    *b = (first << 4) | second;
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return true;
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Parse args.
180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiint main(int argc, char* const argv[])
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski{
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int opt;
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int option_index = 0;
1854eedc1018f46bf2ce1d8780a1fd6415700c4ee1dBrian Carlstrom    PackageInfo package_info;
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    int result = 1;    // pessimistically assume an error.
188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (argc < 2) {
190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        wantUsage = 1;
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    while ((opt = getopt_long(argc, argv, ADD_OPTS, longopts, &option_index)) != -1) {
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        switch (opt) {
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case 0:
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (longopts[option_index].flag)
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "'%s' requires an argument\n", longopts[option_index].name);
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            wantUsage = 1;
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case 'n':
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            package_info.packageName = optarg;
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            break;
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case 'v': {
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            char* end;
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            package_info.packageVersion = strtol(optarg, &end, 10);
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (*optarg == '\0' || *end != '\0') {
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: invalid version; should be integer!\n\n");
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                wantUsage = 1;
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            break;
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case 'o':
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            package_info.overlay = true;
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            break;
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case 's':
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (strlen(optarg) != SALT_LEN * 2) {
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: salt must be 8 bytes in hex (e.g., ABCD65031337D00D)\n\n");
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                wantUsage = 1;
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            package_info.salted = true;
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            unsigned char b;
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            for (int i = 0, j = 0; i < SALT_LEN; i++, j+=2) {
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (!hexToByte(optarg[j], optarg[j+1], &b)) {
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    fprintf(stderr, "ERROR: salt must be in hex (e.g., ABCD65031337D00D)\n");
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    wantUsage = 1;
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    goto bail;
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                package_info.salt[i] = b;
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            break;
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case '?':
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            wantUsage = 1;
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (wantVersion) {
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "%s %s\n", gProgName, gProgVersion);
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (wantUsage) {
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail;
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski#define CHECK_OP(name) \
252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (strncmp(op, name, opsize)) { \
253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        fprintf(stderr, "ERROR: unknown function '%s'!\n\n", op); \
254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        wantUsage = 1; \
255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        goto bail; \
256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
257282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
258282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (optind < argc) {
259282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* op = argv[optind++];
260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const int opsize = strlen(op);
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (optind >= argc) {
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: filename required!\n\n");
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            wantUsage = 1;
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        const char* filename = argv[optind++];
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        switch (op[0]) {
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case 'a':
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            CHECK_OP("add");
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (package_info.packageName == NULL) {
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                fprintf(stderr, "ERROR: arguments required 'packageName' and 'version'\n");
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                goto bail;
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            doAdd(filename, &package_info);
278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            break;
279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case 'r':
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            CHECK_OP("remove");
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            doRemove(filename);
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            break;
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        case 'i':
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            CHECK_OP("info");
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            doInfo(filename);
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            break;
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        default:
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            fprintf(stderr, "ERROR: unknown command '%s'!\n\n", op);
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            wantUsage = 1;
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            goto bail;
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskibail:
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    if (wantUsage) {
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        usage();
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        result = 2;
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    return result;
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
302