я и говорю, занимательное чтиво! :) во всех отношениях :)
Вид для печати
Народ, попробуйте вариант того-же самого только на Питоне. Требуется минимум 2.7 для нормальной работы с командной строкой.
В теории этот модуль можно использовать где угодно т.к. это не набор ф-ций, а полноценное ООП АПИ.
Теоретически оно работает как надо, но я особенно не проверял.
С коментариями - велкам.
Для SCL файлов не пишется контрольная сумма.
Подфикшенная версия + сборка под винду
UPD: исправлена обработка параметров автостарта и бейсикаКод:#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define TYPE_UNKNOWN 0
#define TYPE_SCL 1
#define TYPE_TRD 2
int readfile(char* fname, char* buf, int maxlen) {
FILE *infile = fopen(fname,"rb");
if (!infile) return -1; // failed to open file
fseek(infile, 0, SEEK_END);
int iflen = ftell(infile);
rewind(infile);
if (iflen <= maxlen) {
fread(buf, iflen, 1, infile);
} else {
iflen = 0;
}
fclose(infile);
return iflen;
}
int savefile(char* fname, char* buf, int len) {
FILE *file = fopen(fname, "wb");
if (!file) return 0;
fwrite(buf, len, 1, file);
fclose(file);
return 1;
}
int testsig(char* buf, int len) {
if ((strncmp("SINCLAIR", buf, 8) == 0) && (buf[8] >= 0)) return TYPE_SCL; // SCL
if ((len > 0x900) && (buf[0x8e7] == 0x10)) return TYPE_TRD; // TRD
return TYPE_UNKNOWN; // unknown
}
void extractfile(char* buf, unsigned char* ptr, int fpos, char* fname) {
int len = ptr[11] | (ptr[12] << 8);
unsigned char slen = ptr[13];
unsigned char rlen = ptr[12] + (ptr[11] ? 1 : 0);
if (slen != rlen) len = (slen << 8);
FILE *ofile = fopen(fname, "wb");
if (!ofile) {
printf("Can't write to file '%s'\n",fname);
} else {
fwrite(buf+fpos, len, 1, ofile);
fclose(ofile);
}
}
void makedsc(char* ptr, char* fname, char fext, int len, unsigned char slen, int isBasic) {
strncpy(ptr, fname, 8); // filename
ptr[8] = fext; // ext
ptr[11] = len & 0xff; // length
ptr[12] = ((len & 0xff00) >> 8);
ptr[13] = slen; // sectors lenght
if (isBasic) {
ptr[9] = ptr[11];
ptr[10] = ptr[12];
} else {
ptr[9] = ptr[10] = 0;
}
}
void addcrc(char* data, int len) {
unsigned int crc = 0;
for (int i = 0; i != len; ++i) {
crc += (unsigned char)data[i];
}
memcpy(data + len, &crc, 4);
}
void pack(char* fextra, char* aname, int isBasic, int autoStart) {
char fname[8];
char fext;
int fnsize = strlen(fextra);
char* dotpos = strrchr(fextra,'.'); // locate last dot
if (dotpos == NULL) {
fext = 'C';
} else if (dotpos[1] == 0x00) {
fext = 'C';
fnsize = dotpos - fextra;
} else {
fext = dotpos[1];
fnsize = dotpos - fextra;
}
if (isBasic) fext = 'B';
if (fnsize > 8) fnsize = 8;
memset(fname, 0x20, 8);
memcpy(fname, fextra, fnsize);
char *inbuf = (char *)malloc(0x10000 * sizeof(char));
int iflen = readfile(fextra, inbuf, 0xff00);
if (iflen == -1) {
printf("Can't read file '%s'\n",fextra);
free(inbuf);
return;
}
if (iflen == 0) {
printf("Input file '%s' is too long (0xff00 is a maximum)\n",fextra);
free(inbuf);
return;
}
if (isBasic) {
inbuf[iflen] = 0x80;
inbuf[iflen+1] = 0xaa;
inbuf[iflen+2] = autoStart & 0xff;
inbuf[iflen+3] = ((autoStart & 0xff00) >> 8);
}
char *obuf = (char *)malloc(0xa0000 * sizeof(char));
int olen = readfile(aname, obuf, 0xa0000);
if (olen < 1) {
printf("Can't read output file '%s'\n", aname);
free(inbuf);
free(obuf);
return;
}
int mode = testsig(obuf, olen);
int dataLen = iflen + (isBasic ? 4 : 0); // 80 aa <autostart>
unsigned char seclen = ((dataLen & 0xff00) >> 8) + ((dataLen & 0xff) ? 1 : 0); // sectors len
unsigned char lastsec, lasttrk, files;
unsigned int freesec, fpos, secnum;
char* ptr = obuf;
char dsc[16];
switch (mode) {
case TYPE_SCL:
files = obuf[8];
if (files > 127) {
printf("Too many files in image\n");
break;
}
obuf[8]++;
freesec = 9 + 14 * files; // old catalog len
memmove(obuf + freesec + 14, obuf + freesec, olen - freesec);
makedsc(obuf + freesec, fname, fext, iflen, seclen, isBasic);
memcpy(obuf + olen - 4 + 14, inbuf, seclen * 256);
addcrc(obuf, olen - 4 + seclen * 256 + 14);
savefile(aname, obuf, olen + seclen * 256 + 14);
break;
case TYPE_TRD:
files = obuf[0x8e4];
if (files > 127) {
printf("Too many files in image\n");
break;
}
freesec = (obuf[0x8e5] & 0xff) | ((obuf[0x8e6] & 0xff) << 8);
if (freesec < seclen) {
printf("No room for file\n");
break;
}
lastsec = obuf[0x8e1];
lasttrk = obuf[0x8e2];
files++;
obuf[0x8e4] = files;
freesec -= seclen;
obuf[0x8e5] = freesec & 0xff;
obuf[0x8e6] = ((freesec & 0xff00) >> 8);
while (*ptr) // find 1st free descriptor
ptr += 16;
makedsc(ptr, fname, fext, iflen, seclen, isBasic);
ptr[14] = lastsec;
ptr[15] = lasttrk;
secnum = ((lasttrk << 4) + lastsec); // free sector num
fpos = (secnum << 8); // (lasttrk<<12)+(lastsec<<8);
secnum += seclen;
lastsec = secnum & 15;
lasttrk = ((secnum & 0xfff0) >> 4);
obuf[0x8e1] = lastsec;
obuf[0x8e2] = lasttrk;
memcpy(obuf + fpos, inbuf, dataLen); // copy file data
savefile(aname, obuf, 0xa0000);
break;
default:
printf("Unknown image format\n");
break;
}
free(inbuf);
free(obuf);
}
void extract(char* fextra, char* aname) {
int felen = strlen(fextra);
if (felen > 10) {
printf("Filename is too long ('filename.C' is maximum)\n");
return;
}
if (felen < 2) {
printf("Filename is too short (must be '.C' at least)\n");
return;
}
if (fextra[felen - 2] != '.') {
printf("Filename must be in 'fileneme.e' format\n");
return;
}
char fname[9];
memset(fname,0x20,9);
memcpy(fname,fextra,felen-2);
fname[8] = fextra[felen-1];
char *buf = (char *)malloc(0xa0000 * sizeof(char));
int len=readfile(aname,buf,0xa0000);
if (len < 1) {
printf("Can't read file '%s'\n",aname);
free(buf);
return;
}
int mode = testsig(buf, len);
unsigned char* ptr = (unsigned char*)buf;
int i = 0;
int fpos;
switch (mode) {
case TYPE_SCL:
ptr += 9;
fpos = 9 + buf[8] * 14; // begin of data
while (i < buf[8]) {
if (strncmp(fname, (char*)ptr, 9) == 0) {
extractfile(buf, ptr, fpos, fextra);
}
fpos += (ptr[13] << 8);
ptr += 14;
i++;
}
break;
case TYPE_TRD:
while(*ptr && (i < 128)) {
if (strncmp(fname, (char*)ptr, 9) == 0) {
fpos=(ptr[15] << 12) + (ptr[14] << 8); // position of begin of file in buf
extractfile(buf, ptr, fpos, fextra);
}
ptr += 16;
i++;
}
break;
default:
printf("Unknown image format\n");
break;
}
free(buf);
}
void list(char* fname) {
char *buf = (char *)malloc(0xa0000 * sizeof(char));
int len = readfile(fname, buf,0xa0000);
if (len < 1) {
printf("Can't read file '%s'\n",fname);
free(buf);
return;
}
int mode = testsig(buf, len);
unsigned char* ptr = (unsigned char*)buf;
unsigned char i = 0;
int start;
switch (mode) {
case TYPE_SCL:
ptr += 9;
printf("Name\t\tExt\tStart\tSize\tSLen\n---------------------------\n");
while (i < buf[8]) {
start = ptr[9] | (ptr[10] << 8);
len = ptr[11] | (ptr[12] << 8);
printf("%.8s\t%c\t%i\t%i\t%i\n",ptr,ptr[8], start, len, ptr[13]);
ptr+=14;
i++;
}
break;
case TYPE_TRD:
printf("Name\t\tExt\tStart\tSize\tSLen\tTrk\tSec\n---------------------------\n");
while (*ptr && (i < 128)) {
if (*ptr != 1) {
start = ptr[9] | (ptr[10] << 8);
len = ptr[11] | (ptr[12] << 8);
printf("%.8s\t%c\t%i\t%i\t%i\t%i\t%i\n",ptr,ptr[8],start,len,ptr[13],ptr[14],ptr[15]);
}
ptr+=16; i++;
}
break;
default:
printf("Unknown image format\n");
break;
}
free(buf);
}
void createtrd(char* fname) {
char *buf = (char *)malloc(0xa0000 * sizeof(char));
memset(buf, 0x00, 0xa0000);
buf[0x8e2] = 0x01;
buf[0x8e3] = 0x16;
buf[0x8e5] = 0xf0;
buf[0x8e6] = 0x09;
buf[0x8e7] = 0x10;
FILE *ofile = fopen(fname,"wb");
if (!ofile) {
printf("Can't write to file '%s'\n",fname);
} else {
fwrite(buf,0xa0000,1,ofile);
fclose(ofile);
}
free(buf);
}
void createscl(char* fname) {
char data[] = {'S', 'I', 'N', 'C', 'L', 'A', 'I', 'R', 0, 0, 0, 0, 0};
addcrc(data, 9);
savefile(fname, data, sizeof(data));
}
void help() {
printf("Usage:\n");
printf(" list filename\t\t\t\tlist of files\n");
printf(" ctrd filename\t\t\t\tcreate new TRD\n");
printf(" cscl filename\t\t\t\tcreate new SCL\n");
printf(" add filename archname [parameters]\tadd file to archive\n");
printf(" parameters:\n");
printf(" --autostart <number>\n");
printf(" --basic\n");
printf(" pop filename archname\t\t\textract file from archive\n");
}
int main(int ac,char* av[]) {
char* com = NULL;
char* fname1 = NULL;
char* fname2 = NULL;
int isBasic = 0;
int autoStart = 0;
for (int i = 1; i != ac; ++i) {
char* poptarg = av[i];
if (strcmp(poptarg, "--autostart") == 0) {
if (i == ac - 1) {
printf("Invalid parameters count!\n");
return 1;
}
autoStart = atoi(av[++i]);
} else if (strcmp(poptarg, "--basic") == 0) {
isBasic = 1;
} else {
if (!com) com = poptarg;
else if (!fname1) fname1 = poptarg;
else if (!fname2) fname2 = poptarg;
}
}
if (!fname1) help();
else if (strcmp(com,"list") == 0) list(fname1);
else if (strcmp(com,"ctrd") == 0) createtrd(fname1);
else if (strcmp(com,"cscl") == 0) createscl(fname1);
else if (!fname2) help();
else if (strcmp(com,"pop") == 0) extract(fname1,fname2);
else if (strcmp(com,"add") == 0) pack(fname1,fname2,isBasic,autoStart);
else help();
return 0;
}
Что непонятно? Как CLI утилитами пользоваться?
да.
Вызываешь в консоли, передавая параметры через командную строку. Формат параметров в хелпе (выдается при запуске без параметров).