source: abuse/trunk/src/tool/abuse-tool.cpp @ 548

Last change on this file since 548 was 548, checked in by Sam Hocevar, 11 years ago

tool: implement the rename' and del' commands.

  • Property svn:keywords set to Id
File size: 7.0 KB
Line 
1//
2// Abuse Tool - package manager for Abuse format
3//
4// Copyright: (c) 2011 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11#include "config.h"
12
13#include <cstring>
14#include <cstdio>
15
16#include "common.h"
17#include "specs.h"
18#include "image.h"
19#include "pcxread.h"
20
21static void Usage();
22
23enum
24{
25    CMD_INVALID,
26    CMD_LIST,
27    CMD_GET,
28    CMD_MOVE,
29    CMD_DEL,
30    CMD_PUT,
31    CMD_RENAME,
32    CMD_GETPCX,
33    CMD_PUTPCX,
34};
35
36int main(int argc, char *argv[])
37{
38    if (argc < 3)
39    {
40        Usage();
41        return EXIT_FAILURE;
42    }
43
44    int cmd = !strcmp(argv[2], "list") ? CMD_LIST
45            : !strcmp(argv[2], "get") ? CMD_GET
46            : !strcmp(argv[2], "del") ? CMD_DEL
47            : !strcmp(argv[2], "put") ? CMD_PUT
48            : !strcmp(argv[2], "move") ? CMD_MOVE
49            : !strcmp(argv[2], "rename") ? CMD_RENAME
50            : !strcmp(argv[2], "getpcx") ? CMD_GETPCX
51            : !strcmp(argv[2], "putpcx") ? CMD_PUTPCX
52            : CMD_INVALID;
53
54    if (cmd == CMD_INVALID)
55    {
56        fprintf(stderr, "abuse-tool: unknown command `%s'\n", argv[2]);
57        return EXIT_FAILURE;
58    }
59
60    /* Check argument count and file access mode */
61    char const *mode = "rwb";
62    int minargc = 3;
63
64    switch (cmd)
65    {
66    case CMD_LIST:
67        mode = "rb"; // Read-only access
68        break;
69    case CMD_GET:
70        minargc = 4;
71        mode = "rb"; // Read-only access
72        break;
73    case CMD_PUT:
74        minargc = 5;
75        break;
76    case CMD_MOVE:
77        minargc = 5;
78        break;
79    case CMD_RENAME:
80        minargc = 5;
81        break;
82    case CMD_DEL:
83        minargc = 4;
84        break;
85    case CMD_GETPCX:
86        minargc = 4;
87        mode = "rb"; // Read-only access
88        break;
89    case CMD_PUTPCX:
90        minargc = 5;
91        break;
92    }
93
94    if (argc < minargc)
95    {
96        fprintf(stderr, "abuse-tool: too few arguments to command `%s'\n",
97                         argv[2]);
98        return EXIT_FAILURE;
99    }
100
101    /* Open the SPEC file */
102    char tmpfile[4096];
103    char const *file = argv[1];
104    snprintf(tmpfile, 4096, "%s.tmp", file);
105
106    jFILE fp(file, mode);
107    if (fp.open_failure())
108    {
109        fprintf(stderr, "ERROR - could not open %s\n", file);
110        return EXIT_FAILURE;
111    }
112
113    spec_directory dir(&fp);
114
115    /* Now really execute commands */
116    if (cmd == CMD_LIST)
117    {
118        printf("   id  type     size  name & information\n");
119        printf(" ----  ----  -------  ----------------------------\n");
120
121        for (int i = 0; i < dir.total; i++)
122        {
123            spec_entry *se = dir.entries[i];
124
125            /* Print basic information */
126            printf("% 5i   % 3i % 8i  %s",
127                   i, se->type, (int)se->size, se->name);
128
129            /* Is there anything special to say? */
130            switch (se->type)
131            {
132            case SPEC_IMAGE:
133            case SPEC_FORETILE:
134            case SPEC_BACKTILE:
135            case SPEC_CHARACTER:
136            case SPEC_CHARACTER2:
137              {
138                image *im = new image(&fp, se);
139                printf(" (%i x %i pixels)", im->Size().x, im->Size().y);
140                delete im;
141                break;
142              }
143            case SPEC_PALETTE:
144              {
145                palette *pal = new palette(se, &fp);
146                printf(" (%i colors)", pal->pal_size());
147                delete pal;
148                break;
149              }
150            }
151
152            /* Finish line */
153            putchar('\n');
154        }
155
156        return EXIT_SUCCESS;
157    }
158    else if (cmd == CMD_GET)
159    {
160        int id = atoi(argv[3]);
161
162        if (id < 0 || id >= dir.total)
163        {
164            fprintf(stderr, "abuse-tool: id %i not found in %s\n", id, file);
165            return EXIT_FAILURE;
166        }
167
168        spec_entry *se = dir.entries[id];
169        fp.seek(se->offset, SEEK_SET);
170
171        for (size_t todo = se->size; todo > 0; )
172        {
173            uint8_t buf[1024];
174            int step = Min(todo, 1024);
175            fp.read(buf, step);
176            fwrite(buf, step, 1, stdout);
177            todo -= step;
178        }
179        return EXIT_SUCCESS;
180    }
181    else if (cmd == CMD_GETPCX)
182    {
183        palette *pal;
184        int imgid = atoi(argv[3]);
185        int palid = argc > 4 ? atoi(argv[4]) : -1;
186
187        for (int i = 0; palid == -1 && i < dir.total; i++)
188            if (dir.entries[i]->type == SPEC_PALETTE)
189                palid = i;
190
191        if (palid == -1)
192            pal = new palette(256);
193        else
194            pal = new palette(dir.entries[palid], &fp);
195
196        image *im = new image(&fp, dir.entries[imgid]);
197        write_PCX(im, pal, "/dev/stdout");
198        delete im;
199        delete pal;
200        return EXIT_SUCCESS;
201    }
202    else if (cmd == CMD_MOVE)
203    {
204        int src = atoi(argv[3]);
205        int dst = atoi(argv[4]);
206
207        if (src < 0 || dst < 0 || src >= dir.total || dst >= dir.total)
208        {
209            fprintf(stderr, "abuse-tool: ids %i/%i out of range\n", src, dst);
210            return EXIT_FAILURE;
211        }
212
213        dir.FullyLoad(&fp);
214
215        spec_entry *tmp = dir.entries[src];
216        for (int d = src < dst ? 1 : -1; src != dst; src += d)
217            dir.entries[src] = dir.entries[src + d];
218        dir.entries[dst] = tmp;
219    }
220    else if (cmd == CMD_RENAME)
221    {
222        int id = atoi(argv[3]);
223
224        if (id < 0 || id >= dir.total)
225        {
226            fprintf(stderr, "abuse-tool: id %i out of range\n", id);
227            return EXIT_FAILURE;
228        }
229
230        dir.FullyLoad(&fp);
231        dir.entries[id]->name = argv[4];
232    }
233    else if (cmd == CMD_DEL)
234    {
235        int id = atoi(argv[3]);
236
237        if (id < 0 || id >= dir.total)
238        {
239            fprintf(stderr, "abuse-tool: id %i out of range\n", id);
240            return EXIT_FAILURE;
241        }
242
243        dir.total--;
244        for (int i = id; i < dir.total; i++)
245            dir.entries[i] = dir.entries[i + 1];
246
247        dir.FullyLoad(&fp);
248    }
249    else
250    {
251        /* Not implemented yet */
252        return EXIT_FAILURE;
253    }
254
255    /* If we get here, we need to write the directory back */
256    dir.calc_offsets();
257    fp.seek(0, SEEK_SET); // FIXME: create a new file
258    dir.write(&fp);
259    for (int i = 0; i < dir.total; i++)
260        fp.write(dir.entries[i]->data, dir.entries[i]->size);
261
262    return EXIT_SUCCESS;
263}
264
265static void Usage()
266{
267    fprintf(stderr, "%s",
268            "Usage: abuse-tool <spec_file> <command> [args...]\n"
269            "List of available commands:\n"
270            "  list                  list the contents of a SPEC file\n"
271            "  get <id>              dump entry <id> to stdout\n"
272            "  getpcx <id>           dump PCX image <id> to stdout\n"
273            "  del <id>              delete entry <id>\n"
274            "  rename <id> <name>    rename entry <id> to <name>\n"
275            "  move <id1> <id2>      move entry <id1> to <id2>\n");
276}
277
Note: See TracBrowser for help on using the repository browser.