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

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

tool: implement the "getpcx" and "move" commands.

  • Property svn:keywords set to Id
File size: 6.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
159    if (cmd == CMD_GET)
160    {
161        int id = atoi(argv[3]);
162
163        if (id < 0 || id >= dir.total)
164        {
165            fprintf(stderr, "abuse-tool: id %i not found in %s\n", id, file);
166            return EXIT_FAILURE;
167        }
168
169        spec_entry *se = dir.entries[id];
170        fp.seek(se->offset, SEEK_SET);
171
172        for (size_t todo = se->size; todo > 0; )
173        {
174            uint8_t buf[1024];
175            int step = Min(todo, 1024);
176            fp.read(buf, step);
177            fwrite(buf, step, 1, stdout);
178            todo -= step;
179        }
180        return EXIT_SUCCESS;
181    }
182
183    if (cmd == CMD_GETPCX)
184    {
185        palette *pal;
186        int imgid = atoi(argv[3]);
187        int palid = argc > 4 ? atoi(argv[4]) : -1;
188
189        for (int i = 0; palid == -1 && i < dir.total; i++)
190            if (dir.entries[i]->type == SPEC_PALETTE)
191                palid = i;
192
193        if (palid == -1)
194            pal = new palette(256);
195        else
196            pal = new palette(dir.entries[palid], &fp);
197
198        image *im = new image(&fp, dir.entries[imgid]);
199        write_PCX(im, pal, "/dev/stdout");
200        delete im;
201        delete pal;
202        return EXIT_SUCCESS;
203    }
204
205    if (cmd == CMD_MOVE)
206    {
207        int src = atoi(argv[3]);
208        int dst = atoi(argv[4]);
209
210        if (src < 0 || dst < 0 || src >= dir.total || dst >= dir.total)
211        {
212            fprintf(stderr, "abuse-tool: ids %i/%i out of range\n", src, dst);
213            return EXIT_FAILURE;
214        }
215
216        dir.FullyLoad(&fp);
217
218        spec_entry *tmp = dir.entries[src];
219        for (int d = src < dst ? 1 : -1; src != dst; src += d)
220            dir.entries[src] = dir.entries[src + d];
221        dir.entries[dst] = tmp;
222
223        dir.calc_offsets();
224        fp.seek(0, SEEK_SET); // FIXME: create a new file
225        dir.write(&fp);
226        for (int i = 0; i < dir.total; i++)
227            fp.write(dir.entries[i]->data, dir.entries[i]->size);
228    }
229
230    return EXIT_SUCCESS;
231}
232
233static void Usage()
234{
235    fprintf(stderr, "%s",
236            "Usage: abuse-tool <spec_file> <command> [args...]\n"
237            "List of available commands:\n"
238            "  list                  list the contents of a SPEC file\n"
239            "  get <id>              dump entry <id> to stdout\n"
240            "  getpcx <id>           dump PCX image <id> to stdout\n"
241            "  move <i1> <i2>        move entry <i1> to <i2>\n");
242}
243
Note: See TracBrowser for help on using the repository browser.