zymosis: renamed "SLL" to "SLS"
[zymosis.git] / src / pisdos / pisdos.c
blob948eb9ba665db04b576b5fa7eda402fd183eaebf
1 /***************************************************************************
3 * pisDOS disk file extractor
5 * Written by Ketmar Dark <ketmar@ketmar.no-ip.org>
6 * Used some information from HalfElf XiSD FAR plugin
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, version 3 of the License ONLY.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 **************************************************************************/
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
28 #include "../libfusefdc/libfusefdc.h"
31 //==========================================================================
33 // cprintLibFDC
35 //==========================================================================
36 static void cprintLibFDC (int type, const char *msg) {
37 switch (type) {
38 case LIBFDC_MSG_DEBUG: fprintf(stderr, "LIBFDC[debug]: %s\n", msg); break;
39 case LIBFDC_MSG_WARNING: fprintf(stderr, "LIBFDC[warn]: %s\n", msg); break;
40 case LIBFDC_MSG_ERROR: fprintf(stderr, "LIBFDC[error]: %s\n", msg); break;
41 default: fprintf(stderr, "LIBFDC[???]: %s\n", msg); break; // the thing that should not be
43 fflush(stderr);
47 //==========================================================================
49 // pisdos_print_dir_entry
51 //==========================================================================
52 static int pisdos_print_dir_entry (const PisDOS_DirEnt *de, void *udata) {
53 const char *month_names[12] = {"jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"};
54 PisDOSDateTime dt;
55 pisdos_unpack_date(&dt, de->date);
56 if (dt.month > 11) dt.month = 11;
57 char name[16];
58 pisdos_get_name(name, de);
59 if (pisdos_is_dir(de)) {
60 if (de->attr&PISDOS_FLAG_DIR) strcat(name, "/"); else strcat(name, "*");
61 fprintf(stdout, "%-13s", name);
62 fprintf(stdout, "%04u/%s/%02u --:--:--", dt.year, month_names[dt.month], dt.day+1);
63 if (de->attr&PISDOS_FLAG_HIDDEN) fprintf(stdout, " [HIDDEN]");
64 if ((de->attr&PISDOS_FLAG_CONTINUOUS) == 0) fprintf(stdout, " [SEGMENTED]");
65 fprintf(stdout, "\n");
66 } else {
67 pisdos_unpack_time(&dt, de->file.time);
68 fprintf(stdout, "%-13s", name);
69 fprintf(stdout, "%04u/%s/%02u %02u:%02u:%02u", dt.year, month_names[dt.month], dt.day+1,
70 dt.hour, dt.minute, dt.second);
71 fprintf(stdout, " %8u", pisdos_get_entry_size(de));
72 if (de->attr&PISDOS_FLAG_HIDDEN) fprintf(stdout, " [HIDDEN]");
73 if ((de->attr&PISDOS_FLAG_CONTINUOUS) == 0) fprintf(stdout, " [SEGMENTED]");
74 fprintf(stdout, "\n");
76 return 0;
80 //==========================================================================
82 // pisdos_list_dir
84 //==========================================================================
85 static void pisdos_list_dir (disk_t *dsk, const PisDOS_DirEnt *dirde) {
86 pisdos_dir_foreach(dsk, dirde, &pisdos_print_dir_entry, NULL);
87 fflush(stdout);
91 //==========================================================================
93 // main
95 //==========================================================================
96 int main (int argc, char **argv) {
97 disk_t dsk;
99 libfdcMessageCB = &cprintLibFDC;
101 int dump_dpb = 0;
102 const char *diskimg_fname = NULL;
103 int file_start = 0;
105 for (int f = 1; f < argc; ++f) {
106 const char *arg = argv[f];
107 if (!arg || !arg[0]) continue;
109 if (strcmp(arg, "--") == 0) {
110 fprintf(stderr, "wtf?\n");
111 return 1;
114 if (arg[0] == '-') {
115 if (strcmp(arg, "--dpb") == 0) { dump_dpb = 1; continue; }
116 if (strcmp(arg, "--help") == 0) { diskimg_fname = NULL; break; }
117 if (strcmp(arg, "-h") == 0) { diskimg_fname = NULL; break; }
118 fprintf(stderr, "FATAL: unknown option '%s'\n", arg);
119 return 1;
122 if (!diskimg_fname) {
123 diskimg_fname = argv[f];
124 continue;
127 // file names
128 file_start = f;
129 break;
132 if (!diskimg_fname) {
133 fprintf(stderr, "usage: pisdos diskimg [path]\n");
134 return 1;
137 disk_init_struct(&dsk);
139 const int dopres = disk_open(&dsk, diskimg_fname);
140 if (dopres != DISK_OK) {
141 fprintf(stderr, "FATAL: cannot open disk image '%s'! (error: %s)\n",
142 diskimg_fname, disk_strerror(dopres));
143 disk_close(&dsk);
144 return 1;
147 fflush(stderr);
148 fprintf(stdout, "*** DISK INFO: %d heads, %d cylinders; %d BPT ***\n",
149 dsk.sides, dsk.cylinders, dsk.bpt);
150 fflush(stdout);
153 char dsktitle[16];
154 pisdos_get_title(dsktitle, pisdos_get_dpb(&dsk));
155 if (dsktitle[0]) fprintf(stdout, "*** DISK TITLE: %s ***\n", dsktitle);
158 if (dump_dpb) {
159 #if 0
160 disk_write(&dsk, "_z00.fdi");
161 #endif
162 pisdos_debug_dump_dpb(&dsk);
163 disk_close(&dsk);
164 return 0;
167 #if 0
169 const uint8_t *blk = pisdos_block_ptr(&dsk, 43);
170 fprintf(stderr, "frag_count : %u\n", blk[0]);
171 fprintf(stderr, "frag_start : %u\n", blk[1]|(blk[2]<<8));
172 fprintf(stderr, "frag_length: %u\n", blk[3]);
173 exit(0);
175 #endif
177 if (!file_start) {
178 pisdos_list_dir(&dsk, NULL);
179 disk_close(&dsk);
180 return 0;
183 PisDOSFindInfo fi;
184 char outfname[16];
187 for (int f = file_start; f < argc; ++f) {
188 const PisDOS_DirEnt *de = pisdos_findfirst(&fi, &dsk, argv[f]);
189 if (!de) {
190 fprintf(stderr, "ERROR: cannot find files with mask '%s'!\n", argv[f]);
191 continue;
194 while (de) {
195 memset(outfname, 0, sizeof(outfname));
196 pisdos_get_name(outfname+1, de);
197 outfname[0] = '_';
199 if (pisdos_is_dir(de)) {
200 fprintf(stdout, "===== %s/ =====\n", outfname+1);
201 pisdos_list_dir(&dsk, de);
202 fprintf(stdout, "------------\n");
203 fflush(stdout);
204 } else {
205 PisDOSFragList frags;
206 if (pisdos_build_frags(&dsk, de, &frags) != 0) {
207 fprintf(stderr, "ERROR: cannot build fragment list for file '%s'\n", outfname+1);
208 continue;
211 FILE *fo = fopen(outfname, "w");
212 if (!fo) {
213 fprintf(stderr, "ERROR: cannot create host file '%s'!\n", outfname);
214 disk_close(&dsk);
215 return 1;
217 uint32_t pos = 0;
218 uint32_t left = pisdos_get_entry_size(de);
219 while (left) {
220 uint32_t rd = (left > 256 ? 256 : left);
221 const void *bp = pisdos_next_block(&dsk, &frags);
222 if (!bp) {
223 fprintf(stderr, "ERROR reading pisdos file at position %u (%u bytes left)\n",
224 pos, left);
225 break;
227 if (fwrite(bp, rd, 1, fo) != 1) {
228 fprintf(stderr, "ERROR writing host file at position %u (%u bytes left)\n",
229 pos, left);
230 break;
232 pos += rd;
233 left -= rd;
235 fclose(fo);
236 fprintf(stdout, "extracted '%s'.\n", outfname);
237 fflush(stdout);
240 de = pisdos_findnext(&fi);
244 disk_close(&dsk);
246 return 0;