1 | /*
|
---|
2 | * xk5 :
|
---|
3 | * Extraction des fichiers à partir d'un fichier K7 (format MO)
|
---|
4 | *
|
---|
5 | * Copyright (c) 2011 Puls
|
---|
6 | *
|
---|
7 | * This program is free software; you can redistribute it and/or modify
|
---|
8 | * it under the terms of the GNU General Public License as published by
|
---|
9 | * the Free Software Foundation; either version 2 of the License, or
|
---|
10 | * (at your option) any later version.
|
---|
11 | *
|
---|
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.
|
---|
16 | *
|
---|
17 | * You should have received a copy of the GNU General Public License
|
---|
18 | * along with this program; if not, write to the Free Software
|
---|
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
---|
20 | */
|
---|
21 |
|
---|
22 |
|
---|
23 | #include <stdio.h>
|
---|
24 | #include <string.h>
|
---|
25 | #include <stdint.h>
|
---|
26 | #include <stdlib.h>
|
---|
27 |
|
---|
28 | typedef enum { FALSE, TRUE } bool_t;
|
---|
29 |
|
---|
30 | enum {
|
---|
31 | E_CANT_READ_FILE = -100,
|
---|
32 | E_CANT_WRITE_FILE,
|
---|
33 | E_CHECKSUM,
|
---|
34 | E_END_OF_CASSETTE ,
|
---|
35 | E_READ_ERROR,
|
---|
36 | E_MEMORY
|
---|
37 | };
|
---|
38 |
|
---|
39 |
|
---|
40 | static const struct {
|
---|
41 | int err;
|
---|
42 | char str[33];
|
---|
43 | } elist [] = {
|
---|
44 | { E_CANT_READ_FILE ,"Cannot read file" },
|
---|
45 | { E_CANT_WRITE_FILE ,"Cannot write file" },
|
---|
46 | { E_CHECKSUM ,"Checksum error" },
|
---|
47 | { E_END_OF_CASSETTE ,"End of cassette reached" },
|
---|
48 | { E_READ_ERROR ,"Read error" },
|
---|
49 | { E_MEMORY ,"Memory error" },
|
---|
50 | { 0 ,"Ok" }
|
---|
51 | };
|
---|
52 |
|
---|
53 |
|
---|
54 | static void
|
---|
55 | display_error (char *message, int err) {
|
---|
56 | int i = 0;
|
---|
57 |
|
---|
58 | while ((err != elist[i].err) && (elist[i].err < 0))
|
---|
59 | i++;
|
---|
60 | (void)printf ("%s : %s\n", message, (char *)elist[i].str);
|
---|
61 | }
|
---|
62 |
|
---|
63 |
|
---|
64 | static void
|
---|
65 | clean_string (char *str) {
|
---|
66 | int i;
|
---|
67 |
|
---|
68 | for (i=(int)strlen(str)-1; (i>=0)&&(str[i]<=' '); i--)
|
---|
69 | str[i] = '\0';
|
---|
70 | }
|
---|
71 |
|
---|
72 |
|
---|
73 | static int
|
---|
74 | k5_read_byte (FILE *file, uint8_t *byte)
|
---|
75 | /*@globals errno@*/ {
|
---|
76 | int err = 0;
|
---|
77 |
|
---|
78 | *byte = (uint8_t)fgetc (file);
|
---|
79 | if ( feof (file) != 0) err = E_END_OF_CASSETTE;
|
---|
80 | if (ferror (file) != 0) err = E_READ_ERROR;
|
---|
81 | return err;
|
---|
82 | }
|
---|
83 |
|
---|
84 |
|
---|
85 | static int
|
---|
86 | k5_read_block (FILE *file, uint8_t *buf, uint8_t *size, uint8_t *type)
|
---|
87 | /*@globals errno@*/ {
|
---|
88 | int err = 0;
|
---|
89 |
|
---|
90 | err = k5_read_byte (file, type);
|
---|
91 | if (err == 0) {
|
---|
92 | err = k5_read_byte (file, size);
|
---|
93 | *size -= 2;
|
---|
94 | if ((err == 0) && (*size != 0)) {
|
---|
95 | if (fread (buf, 1, *size, file) != *size) {
|
---|
96 | if ( feof (file) != 0) err = E_END_OF_CASSETTE;
|
---|
97 | if (ferror (file) != 0) err = E_READ_ERROR;
|
---|
98 | }
|
---|
99 | }
|
---|
100 | }
|
---|
101 | return err;
|
---|
102 | }
|
---|
103 |
|
---|
104 |
|
---|
105 | static int
|
---|
106 | k5_search_gap (FILE *file)
|
---|
107 | /*@globals errno@*/ {
|
---|
108 | int err = 0;
|
---|
109 | uint8_t byte = 0;
|
---|
110 | int count = 0;
|
---|
111 |
|
---|
112 | while ((count < 5) && (err == 0)) {
|
---|
113 | err = k5_read_byte (file, &byte);
|
---|
114 | if (byte == 0x01) count++; else count = 0;
|
---|
115 | }
|
---|
116 | return err;
|
---|
117 | }
|
---|
118 |
|
---|
119 |
|
---|
120 | static uint8_t
|
---|
121 | k5_checksum (uint8_t *buf, uint8_t size){
|
---|
122 | uint8_t i;
|
---|
123 | uint8_t checksum ;
|
---|
124 |
|
---|
125 | checksum = 0;
|
---|
126 | for (i = 0; i < size; i++)
|
---|
127 | checksum += buf[i];
|
---|
128 | return -checksum;
|
---|
129 | }
|
---|
130 |
|
---|
131 |
|
---|
132 | static int
|
---|
133 | k5_find_block (FILE *file, uint8_t *buf, uint8_t *size, uint8_t *type, uint8_t *checksum)
|
---|
134 | /*@globals errno@*/ {
|
---|
135 | int err = 0;
|
---|
136 | uint8_t byte = 0;
|
---|
137 | bool_t block_found = FALSE;
|
---|
138 |
|
---|
139 | while ((err == 0) && (block_found == FALSE)) {
|
---|
140 | err = k5_search_gap (file);
|
---|
141 | byte = 0x01;
|
---|
142 | while ((err == 0) && (byte == 0x01))
|
---|
143 | err = k5_read_byte (file, &byte);
|
---|
144 | if ((err == 0) && (byte == 0x3c)) {
|
---|
145 | err = k5_read_byte (file, &byte);
|
---|
146 | if ((err == 0) && (byte == 0x5a)) {
|
---|
147 | err = k5_read_block (file, buf, size, type);
|
---|
148 | }
|
---|
149 | }
|
---|
150 | if (err == 0) {
|
---|
151 | *checksum = (uint8_t)fgetc (file);
|
---|
152 | if (ferror (file) != 0) err = E_READ_ERROR;
|
---|
153 | else block_found = TRUE;
|
---|
154 | }
|
---|
155 | }
|
---|
156 | return err;
|
---|
157 | }
|
---|
158 |
|
---|
159 |
|
---|
160 | static void
|
---|
161 | k5_pc_filename (uint8_t *buf, char *name) {
|
---|
162 | char pc_name[9] = "";
|
---|
163 | char pc_ext[4] = "";
|
---|
164 |
|
---|
165 | strncat (pc_name, (char *)buf, 8);
|
---|
166 | strncat (pc_ext, (char *)buf+8, 3);
|
---|
167 | clean_string (pc_name);
|
---|
168 | clean_string (pc_ext);
|
---|
169 | *name = '\0';
|
---|
170 | (void)snprintf (name, 12, "%s.%s", pc_name, pc_ext);
|
---|
171 | }
|
---|
172 |
|
---|
173 |
|
---|
174 | static int
|
---|
175 | k5_searching (FILE *file, char *name)
|
---|
176 | /*@globals errno@*/ {
|
---|
177 | int err = 0;
|
---|
178 | uint8_t type = 0x01;
|
---|
179 | uint8_t size = 0;
|
---|
180 | uint8_t checksum = 0;
|
---|
181 | uint8_t buf[255];
|
---|
182 |
|
---|
183 | memset (buf, 0x00, sizeof (&buf));
|
---|
184 | while ((type != 0x00) && (err == 0)) {
|
---|
185 | err = k5_find_block (file, buf, &size, &type, &checksum);
|
---|
186 | if (err == 0) {
|
---|
187 | if (checksum != k5_checksum (buf, size))
|
---|
188 | err = E_CHECKSUM;
|
---|
189 | k5_pc_filename (buf, name);
|
---|
190 | }
|
---|
191 | }
|
---|
192 | return err;
|
---|
193 | }
|
---|
194 |
|
---|
195 |
|
---|
196 | static int
|
---|
197 | k5_fload (FILE *file, uint8_t *buf, size_t *index, char *name)
|
---|
198 | /*@globals errno@*/ {
|
---|
199 | int err = 0;
|
---|
200 | uint8_t type = 0x01;
|
---|
201 | uint8_t size = 0;
|
---|
202 | uint8_t checksum = 0;
|
---|
203 |
|
---|
204 | if ((file != NULL) && (buf != NULL)) {
|
---|
205 | err = k5_searching (file, name);
|
---|
206 | *index = 0;
|
---|
207 | while ((type != 0xff) && (err == 0)) {
|
---|
208 | err = k5_find_block (file, buf + *index, &size, &type, &checksum);
|
---|
209 | *index += (size_t)size;
|
---|
210 | }
|
---|
211 | }
|
---|
212 | return err;
|
---|
213 | }
|
---|
214 |
|
---|
215 |
|
---|
216 | static int
|
---|
217 | k5_extract (char *name)
|
---|
218 | /*@globals errno,stdout@*/ {
|
---|
219 | static FILE /*@dependent@*//*@null@*/*file = NULL;
|
---|
220 | static FILE /*@dependent@*//*@null@*/*fd_dest = NULL;
|
---|
221 | uint8_t *buf = NULL;
|
---|
222 | size_t size = 0;
|
---|
223 | int err = 0;
|
---|
224 | long int pos = 0;
|
---|
225 | char dstName[20] = "";
|
---|
226 |
|
---|
227 | buf = (uint8_t*)calloc (1, 100000);
|
---|
228 | if (buf != NULL) {
|
---|
229 | file = fopen(name, "rb");
|
---|
230 | if (file != NULL) {
|
---|
231 | while (err == 0) {
|
---|
232 | err = k5_fload (file, buf, &size, dstName);
|
---|
233 | if (err == 0) {
|
---|
234 | pos = ftell (file);
|
---|
235 | (void)printf ("%07d '%s' (%d bytes)\n", (int)pos, dstName, (int)size);
|
---|
236 | fd_dest = fopen (dstName, "wb");
|
---|
237 | if (fd_dest != NULL) {
|
---|
238 | if (fwrite (buf, 1, size, fd_dest) != size)
|
---|
239 | err = E_READ_ERROR;
|
---|
240 | (void)fclose (fd_dest);
|
---|
241 | } else err = E_CANT_WRITE_FILE;
|
---|
242 | }
|
---|
243 | }
|
---|
244 | (void)fclose (file);
|
---|
245 | } else err = E_CANT_READ_FILE;
|
---|
246 | free (buf);
|
---|
247 | } else err = E_MEMORY;
|
---|
248 | return err;
|
---|
249 | }
|
---|
250 |
|
---|
251 |
|
---|
252 | int
|
---|
253 | main(int argc, char *argv[])
|
---|
254 | /*@globals errno,stdout@*/ {
|
---|
255 | char name[300+1] = "";
|
---|
256 |
|
---|
257 | if (argc != 2) {
|
---|
258 | (void)printf (" xk5 version 0.1 (c) oct 2011 Puls\n");
|
---|
259 | (void)printf (" Usage : xk5 <k5file>\n");
|
---|
260 | } else {
|
---|
261 | (void)snprintf (name, 300, "%s", argv[1]);
|
---|
262 | clean_string (name);
|
---|
263 | display_error (name, k5_extract (name));
|
---|
264 | }
|
---|
265 | return EXIT_SUCCESS;
|
---|
266 | }
|
---|
267 |
|
---|