source: Thomson/tools/xk5.c @ 69

Last change on this file since 69 was 56, checked in by pulkomandy, 6 years ago

xk5: fix off-by-one error in snprintf length.

  • The length includes the string terminator, 8+3+1+1=13.
File size: 6.7 KB
Line 
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
28typedef enum { FALSE, TRUE } bool_t;
29
30enum {
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
40static 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
54static void
55display_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
64static void
65clean_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
73static int
74k5_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
85static int
86k5_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
105static int
106k5_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
120static uint8_t
121k5_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
132static int
133k5_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
160static void
161k5_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, 13, "%8s.%3s", pc_name, pc_ext);
171}
172
173
174static int
175k5_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
196static int
197k5_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
216static int
217k5_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
252int
253main(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
Note: See TracBrowser for help on using the repository browser.