ttarchive.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. /******************************************************************************
  2. *
  3. * project name: TI-68k Developer Utilities
  4. * file name: ttarchive.c
  5. * initial date: 16/08/2000
  6. * author: thomas.nussbaumer@gmx.net
  7. * description: archive generation tool
  8. *
  9. ******************************************************************************/
  10. /*
  11. This file is part of TI-68k Developer Utilities.
  12. This file is free software; you can redistribute it and/or
  13. modify it under the terms of the GNU Lesser General Public
  14. License as published by the Free Software Foundation; either
  15. version 2.1 of the License, or (at your option) any later version.
  16. As a special exception, UNMODIFIED copies of ttarchive may also be
  17. redistributed or sold without source code, for any purpose. (The Lesser
  18. General Public License restrictions do apply in other respects; for example,
  19. they cover modification of the program.) This exception notice must be
  20. removed on modified copies of this file.
  21. This program is distributed in the hope that it will be useful,
  22. but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  24. Lesser General Public License for more details.
  25. You should have received a copy of the GNU Lesser General Public
  26. License along with this library; if not, write to the Free Software
  27. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  28. */
  29. #ifndef __TTARCHIVE__
  30. #define __TTARCHIVE__
  31. // if EMBEDDED_USE is defined, than we use this sourcefile from within another
  32. // sourcefile
  33. #ifndef EMBEDDED_USE
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <stdlib.h>
  37. #include <ctype.h>
  38. #include <time.h>
  39. #include "ttversion.h"
  40. #include "revtools.h"
  41. #include "tt.h"
  42. #include "strhead.h"
  43. #include "ttarchive.h"
  44. #include "bin2oth.c"
  45. #include "packhead.h"
  46. #ifdef FILE_REVISION
  47. #undef FILE_REVISION
  48. #endif
  49. #define FILE_REVISION "1.11"
  50. //-----------------------------------------------------------------------------
  51. //
  52. // format of TTA (TIGCC Tools Archive):
  53. // ------------------------------------
  54. //
  55. // unsigned char magic1; ... must be 't'
  56. // unsigned char magic2; ... must be 't'
  57. // unsigned char magic3; ... must be 'a'
  58. // unsigned char version; ... version of fileformat (0 at the moment)
  59. // unsigned int nr_entries; ... count of entries
  60. // TTAEntry info[nr_entries]; ... header information of all entries
  61. // <entry data> ... here comes the data of the entries
  62. //
  63. // TTAEntry is defined as:
  64. //
  65. // typedef struct {
  66. // unsigned int offset; // offset to the entry data
  67. // unsigned int length; // length of entry
  68. // char name[8]; // entry name
  69. // unsigned int misc[2]; // info from cfg file (may be queried by a prg)
  70. // } TTAEntry;
  71. //
  72. //-----------------------------------------------------------------------------
  73. //=============================================================================
  74. // outputs usage information of this tool
  75. //=============================================================================
  76. void PrintUsage() {
  77. PRINT_ID("TTArchive");
  78. fprintf(USAGE_OUT, "Usage: ttarchive [flags] <cfgfile> <varname> [folder]\n\n"\
  79. " -89 .... generate TI89 variable\n"\
  80. " -92 .... generate TI92p variable\n"\
  81. " -v .... verbose (unsets -quiet)\n"\
  82. " -quiet ... don't output standard messages (unsets -v)\n"\
  83. " -e <extension> .... use special extension\n\n"\
  84. " cfgfile .... configuration file to use\n"\
  85. " varname .... on-calc variable name of output\n"\
  86. " folder .... on-calc destination folder (OPTIONAL)\n\n"\
  87. " generates an archive file. The contents of the archive\n"\
  88. " have to be specified in a configfile where each line contains\n"\
  89. " one file which should be added to the archive.\n"\
  90. " An archive file can hold compressed or uncompressed entries.\n"\
  91. " If an entry should be compressed add tag \"compress\" at the\n"\
  92. " end of the config line.\n\n"\
  93. " [-------- format of one line in the configfile --------]\n"\
  94. " <file_to_store> <varname> <attr1> <attr2> [compress]\n\n"\
  95. " file_to_store ... name including path to inputfile\n"\
  96. " varname ... name used to find data in archive (max. 8 chars)\n"\
  97. " attr1 attr2 ... misc. attributes which may be queried from program\n"\
  98. " (0..65536)\n"\
  99. " compress ... if this tag is set on the end of the line the\n"\
  100. " given inputfile will be compressed before adding\n"\
  101. " it to the archive\n\n");
  102. }
  103. #endif
  104. #ifndef EMBEDDED_USE
  105. #define EMBEDDED_USE
  106. #include "ttpack.c"
  107. #undef EMBEDDED_USE
  108. #else
  109. #include "ttpack.c"
  110. #endif
  111. //=============================================================================
  112. // this function parses the configfile and generates a complete RAM image of
  113. // the final output
  114. //
  115. // its quite a hack. normally I hate such spaghetti code, but it was done in
  116. // 10 minutes and works. why should I touch it again ?
  117. //=============================================================================
  118. unsigned char* ProcessConfigFile(char* cfgname,unsigned long* psize,int verbose) {
  119. FILE* fp = fopen(cfgname,"r");
  120. FILE* tmpfp;
  121. char fname[200];
  122. char name[200];
  123. char inputline[1024];
  124. unsigned int misc1;
  125. unsigned int misc2;
  126. unsigned int parsed;
  127. unsigned int lines;
  128. unsigned long flength;
  129. unsigned int offset;
  130. TTAEntry* newptr;
  131. unsigned char* newptr2;
  132. TTAEntry* entries = NULL;
  133. unsigned char* data = NULL;
  134. unsigned char description[TTA_DESC_LENGTH];
  135. int input;
  136. char option[200];
  137. int do_packing;
  138. char* tmp_packname = "tmppack.pck";
  139. //----------------------------------
  140. // check if file is opened correctly
  141. //----------------------------------
  142. if (!fp) {
  143. fprintf(stderr,"ERROR: cannot open configfile %s\n",cfgname);
  144. return 0;
  145. }
  146. lines = 0;
  147. offset = 0;
  148. //----------------------------------------------------
  149. // check if there is a description in the configfile
  150. //
  151. // the description of a TTA file may only be specified
  152. // in the first line of the configfile.
  153. // if the first line starts with '#' the next max.20
  154. // character are taken as description of the TTArchive
  155. //----------------------------------------------------
  156. memset(description,0,TTA_DESC_LENGTH);
  157. input = fgetc(fp);
  158. if (input == '#') {
  159. int i = 0;
  160. do {
  161. input = fgetc(fp);
  162. if (input != EOF) description[i++] = input;
  163. }
  164. while (input != EOF && input != 0x0D && input != 0x0A && i < TTA_DESC_LENGTH);
  165. if (i > 0) description[i-1] = 0;
  166. }
  167. rewind(fp);
  168. if (verbose) {
  169. if (description[0]) fprintf(stderr,"description = [%s]\n",description);
  170. else fprintf(stderr,"description = ***none***\n");
  171. }
  172. input = 0;
  173. while (!feof(fp)) {
  174. if (!input && description[0]) { // skip first line if it is a description
  175. fgets(inputline,1023,fp);
  176. input = 1;
  177. continue;
  178. }
  179. if (fgets(inputline,1023,fp)==NULL) break;
  180. parsed = sscanf(inputline,"%s %s %u %u %s \n",fname,name,&misc1,&misc2,option);
  181. if ((signed int)parsed == EOF) break;
  182. lines++;
  183. if (parsed != 4 && parsed != 5) {
  184. fprintf(stderr,"ERROR in line %d: invalid number of parameters (%d)\n",lines,parsed);
  185. fprintf(stderr,"input was [%s]\n",inputline);
  186. fclose(fp);
  187. if (entries) free(entries);
  188. if (data) free(data);
  189. return 0;
  190. }
  191. if (parsed == 5 && !strcmp(option,"compress")) do_packing = 1;
  192. else do_packing = 0;
  193. newptr = (TTAEntry*)realloc(entries,sizeof(TTAEntry)*lines);
  194. if (!newptr) {
  195. fprintf(stderr,"ERROR: cannot allocate memory\n");
  196. fclose(fp);
  197. if (entries) free(entries);
  198. if (data) free(data);
  199. return 0;
  200. }
  201. entries = newptr;
  202. if (do_packing) {
  203. char* ttpack_params[4];
  204. ttpack_params[0] = "";
  205. ttpack_params[1] = "-quiet";
  206. ttpack_params[2] = fname;
  207. ttpack_params[3] = tmp_packname;
  208. if (verbose) printf("[line %02d] process packing %s -> %s ...\n",lines,fname,tmp_packname);
  209. if (TTPack(4,ttpack_params)) {
  210. fprintf(stderr,"ERROR in line %d: cannot compress file %s to %s\n",lines,fname,tmp_packname);
  211. if (entries) free(entries);
  212. if (data) free(data);
  213. fclose(fp);
  214. return 0;
  215. }
  216. strcpy(fname,tmp_packname);
  217. }
  218. else {
  219. if (verbose) printf("[line %02d] dont process packing on %s\n",lines,fname);
  220. }
  221. tmpfp = fopen(fname,"rb");
  222. if (!tmpfp) {
  223. fprintf(stderr,"ERROR in line %d: cannot open file %s\n",lines,fname);
  224. if (entries) free(entries);
  225. if (data) free(data);
  226. fclose(fp);
  227. if (do_packing) remove(tmp_packname);
  228. return 0;
  229. }
  230. fseek(tmpfp,0,SEEK_END);
  231. flength = ftell(tmpfp);
  232. if (flength+offset+lines*sizeof(TTAEntry) > TT_MAX_OTHDATA) {
  233. fprintf(stderr,"ERROR in line %d: will not fit anymore in archive (%lu > %d)\n",
  234. lines,flength+offset+lines*sizeof(TTAEntry),TT_MAX_OTHDATA);
  235. if (entries) free(entries);
  236. if (data) free(data);
  237. fclose(tmpfp);
  238. fclose(fp);
  239. if (do_packing) remove(tmp_packname);
  240. return 0;
  241. }
  242. fseek(tmpfp,0,SEEK_SET);
  243. newptr2 = realloc(data,offset+flength);
  244. if (!newptr2) {
  245. fprintf(stderr,"ERROR in line %d: cannot allocate memory\n",lines);
  246. if (entries) free(entries);
  247. if (data) free(data);
  248. fclose(tmpfp);
  249. fclose(fp);
  250. if (do_packing) remove(tmp_packname);
  251. return 0;
  252. }
  253. data = newptr2;
  254. if (fread(data+offset,flength,1,tmpfp) != 1) {
  255. fprintf(stderr,"ERROR in line %d: reading input data failed\n",lines);
  256. if (entries) free(entries);
  257. if (data) free(data);
  258. fclose(tmpfp);
  259. fclose(fp);
  260. if (do_packing) remove(tmp_packname);
  261. return 0;
  262. }
  263. fclose(tmpfp);
  264. if (do_packing) remove(tmp_packname);
  265. strncpy(entries[lines-1].name,name,8);
  266. entries[lines-1].offset[0] = offset >> 8;
  267. entries[lines-1].offset[1] = offset & 0xff;
  268. entries[lines-1].length[0] = flength >> 8;
  269. entries[lines-1].length[1] = flength & 0xff;
  270. entries[lines-1].misc1[0] = misc1 >> 8;
  271. entries[lines-1].misc1[1] = misc1 & 0xff;
  272. entries[lines-1].misc2[0] = misc2 >> 8;
  273. entries[lines-1].misc2[1] = misc2 & 0xff;
  274. if (verbose) printf("[line %02d] written - offset=%05u var=%s (%u %u)\n",lines,offset,name,misc1,misc2);
  275. offset+=flength;
  276. }
  277. fclose(fp);
  278. if (!entries) return 0;
  279. newptr2 = malloc(sizeof(TTAEntry)*lines + offset +6);
  280. if (!newptr2) {
  281. free(entries);
  282. free(data);
  283. return 0;
  284. }
  285. *newptr2 = 't'; // write magic characters and format version
  286. *(newptr2+1) = 't';
  287. *(newptr2+2) = 'a';
  288. *(newptr2+3) = 0;
  289. *(newptr2+4) = lines>>8;
  290. *(newptr2+5) = lines & 0xff;
  291. memcpy(newptr2+6,entries,sizeof(TTAEntry)*lines);
  292. memcpy(newptr2+6+sizeof(TTAEntry)*lines,data,offset);
  293. *psize = sizeof(TTAEntry)*lines + offset + 6;
  294. if (entries) free(entries);
  295. if (data) free(data);
  296. if (description[0]) {
  297. if (*psize + TTA_DESC_LENGTH + 3 > TT_MAX_OTHDATA) {
  298. fprintf(stderr,"ERROR: no place for description. generation aborted.\n");
  299. free(newptr2);
  300. return 0;
  301. }
  302. data = realloc(newptr2,*psize + TTA_DESC_LENGTH + 3);
  303. if (!data) {
  304. fprintf(stderr,"ERROR: cannot allocate memory.\n");
  305. free(newptr2);
  306. return 0;
  307. }
  308. newptr2 = data;
  309. data = newptr2+*psize;
  310. *data++ = 0;
  311. memcpy(data,description,20);
  312. data+=20;
  313. *data++=0;
  314. *data=0xad; // ad == archive description
  315. *psize += TTA_DESC_LENGTH + 3;
  316. }
  317. return newptr2;
  318. }
  319. //=============================================================================
  320. // nomen omen est
  321. //=============================================================================
  322. #ifndef EMBEDDED_USE
  323. int main(int argc,char *argv[]) {
  324. #else
  325. int TTArchive(int argc,char *argv[]) {
  326. #endif
  327. char* folder = NULL;
  328. char* name = NULL;
  329. char* cfgname = NULL;
  330. int calctype = -1;
  331. FILE* ofp;
  332. char outfile[1024];
  333. unsigned char* buffer;
  334. unsigned long length;
  335. unsigned char* outbuffer;
  336. unsigned int outlength;
  337. unsigned int retval;
  338. char* extension = "tta"; // default extension
  339. int n;
  340. int verbose = 0;
  341. int quiet = 0;
  342. // check for too less arguments
  343. if (argc < 4) {
  344. #ifndef EMBEDDED_USE
  345. PrintUsage();
  346. #endif
  347. return 1;
  348. }
  349. // parse arguments
  350. for (n=1; n<argc; n++) {
  351. if (!strcmp(argv[n], "-89")) calctype = CALC_TI89;
  352. else if (!strcmp(argv[n], "-92")) calctype = CALC_TI92P;
  353. else if (!strcmp(argv[n], "-quiet")) verbose = 0,quiet = 1;
  354. else if (!strcmp(argv[n], "-v")) verbose = 1,quiet = 0;
  355. else if (!strcmp(argv[n],"-e")) {
  356. if (n==argc-1) {
  357. #ifndef EMBEDDED_USE
  358. PrintUsage();
  359. #endif
  360. return 1;
  361. }
  362. else {
  363. int length;
  364. n++;
  365. extension = argv[n];
  366. length = strlen(extension);
  367. if (length < 1 || length > 4) {
  368. fprintf(stderr,"ERROR: extension have to be between 1 and 4 characters\n");
  369. return 1;
  370. }
  371. }
  372. }
  373. else if (argv[n][0] == '-') {
  374. fprintf(stderr,"ERROR: invalid option %s",argv[n]);
  375. return 1;
  376. }
  377. else if (!cfgname) cfgname = argv[n];
  378. else if (!name) name = argv[n];
  379. else if (!folder) folder = argv[n];
  380. else {
  381. #ifndef EMBEDDED_USE
  382. PrintUsage();
  383. #endif
  384. return 1;
  385. }
  386. }
  387. // check if all necessary arguments are supplied
  388. if (!cfgname || !name || calctype == -1) {
  389. #ifndef EMBEDDED_USE
  390. PrintUsage();
  391. #endif
  392. return 1;
  393. }
  394. #ifndef EMBEDDED_USE
  395. if (!quiet) PRINT_ID("TTArchive");
  396. #endif
  397. if (calctype == CALC_TI89) sprintf(outfile,"%s.89y",name);
  398. else sprintf(outfile,"%s.9xy",name);
  399. buffer = ProcessConfigFile(cfgname,&length,verbose);
  400. if (!buffer) return 1;
  401. if (!(ofp = fopen(outfile,"wb"))) {
  402. fprintf(stderr,"ERROR: cannot open outputfile %s\n",outfile);
  403. return 1;
  404. }
  405. outbuffer = DataBuffer2OTHBuffer(calctype,folder,name,extension,length,buffer,&outlength);
  406. retval = 0;
  407. if (!outbuffer) {
  408. retval = 1;
  409. }
  410. else {
  411. if (fwrite(outbuffer,outlength,1,ofp) != 1) {
  412. fprintf(stderr,"ERROR: cannot write %u bytes to %s\n",outlength,outfile);
  413. retval = 1;
  414. }
  415. else {
  416. if (!quiet) fprintf(stdout,"%u bytes written to %s\n",outlength,outfile);
  417. }
  418. free(outbuffer);
  419. }
  420. free(buffer);
  421. fclose(ofp);
  422. return retval;
  423. }
  424. #endif
  425. //#############################################################################
  426. //###################### NO MORE FAKES BEYOND THIS LINE #######################
  427. //#############################################################################
  428. //
  429. //=============================================================================
  430. // Revision History
  431. //=============================================================================
  432. //
  433. // Revision 1.11 2009/01/25 Lionel Debroux
  434. // Changes by Romain Liévin and/or me for 64-bit compatibility.
  435. // Adapt to new version display (revtools.h).
  436. //
  437. // Revision 1.10 2002/03/14 10:45:49 tnussb
  438. // (1) by adding the word "compress" at the end of a line in the configuration
  439. // file, ttarchive will automatically compress this file now, before adding
  440. // it to the archive
  441. // (2) new flag "-quiet" added (suppress standard messages)
  442. // (3) specifying of extensions between 1 and 4 characters is possible now
  443. // (4) usage text adapted
  444. //
  445. // Revision 1.9 2002/03/04 14:32:41 tnussb
  446. // now tool can be used as embedded version from within other tools
  447. // by defining EMBEDDED_VERSION before including the sourcefile
  448. //
  449. // Revision 1.8 2002/02/07 09:49:36 tnussb
  450. // all local includes changed, because header files are now located in pctools folder
  451. //
  452. // Revision 1.7 2000/11/28 00:05:12 Thomas Nussbaumer
  453. // using now USAGE_OUT stream for usage info
  454. //
  455. // Revision 1.6 2000/08/26 12:57:32 Thomas Nussbaumer
  456. // outputs now sizes if ebook gets to long
  457. //
  458. // Revision 1.5 2000/08/23 19:22:59 Thomas Nussbaumer
  459. // (1) using now macros for automatic version display (revtools.h)
  460. // (2) minor comments added
  461. // (3) usage information now near top of file to find it quicker
  462. //
  463. // Revision 1.4 2000/08/23 01:10:57 Thomas Nussbaumer
  464. // (1) using now bin2oth.c for wrapping
  465. // (2) handling of archive description (20 bytes) added
  466. //
  467. // Revision 1.3 2000/08/20 16:25:21 Thomas Nussbaumer
  468. // missing initialization of extension pointer added
  469. //
  470. // Revision 1.2 2000/08/20 15:29:36 Thomas Nussbaumer
  471. // flag -e <extension> added (use personalized in calc extension)
  472. //
  473. // Revision 1.1 2000/08/16 23:05:59 Thomas Nussbaumer
  474. // initial version
  475. //
  476. //
  477. //
  478. //