// finds the Tyrian data directory const char *data_dir( void ) { const char *dirs[] = { custom_data_dir, TYRIAN_DIR, "data", ".", }; static const char *dir = NULL; if (dir != NULL) return dir; for (uint i = 0; i < COUNTOF(dirs); ++i) { if (dirs[i] == NULL) continue; FILE *f = dir_fopen(dirs[i], "tyrian1.lvl", "rb"); if (f) { fclose(f); dir = dirs[i]; break; } } if (dir == NULL) // data not found dir = ""; return dir; }
// check if file can be opened for reading bool dir_file_exists( const char *dir, const char *file ) { FILE *f = dir_fopen(dir, file, "rb"); if (f != NULL) fclose(f); return (f != NULL); }
// warn when dir_fopen fails FILE *dir_fopen_warn( const char *dir, const char *file, const char *mode ) { FILE *f = dir_fopen(dir, file, mode); if (f == NULL) fprintf(stderr, "warning: failed to open '%s': %s\n", file, strerror(errno)); return f; }
// die when dir_fopen fails FILE *dir_fopen_die( const char *dir, const char *file, const char *mode ) { FILE *f = dir_fopen(dir, file, mode); if (f == NULL) { fprintf(stderr, "error: failed to open '%s': %s\n", file, strerror(errno)); fprintf(stderr, "error: One or more of the required Tyrian " TYRIAN_VERSION " data files could not be found.\n" " Please read the README file.\n"); JE_tyrianHalt(1); } return f; }
// finds the Tyrian data directory const char *data_dir( void ) { const char *dirs[] = { //custom_data_dir, "./data", "./Assets/data", "/data", "/Assets/data", "data", "Assets/data" }; static const char *dir = NULL; if (dir != NULL && (dir[0] != '\0')) return dir; for (uint i = 0; i < COUNTOF(dirs); ++i) { FILE *f = dir_fopen(dirs[i], "tyrian1.lvl", "rb"); if (f) { fclose(f); dir = dirs[i]; break; } } if (dir == NULL) // data not found dir = ""; return dir; }
static int unpack_image(const char *infn, const char *outdn) { struct imagewty_header *header; FILE *ifp, *lfp, *ofp; void *image, *curr; long imagesize; int i; ifp = fopen(infn, "rb"); if (ifp == NULL) { fprintf(stderr, "Error: unable to open %s!\n", infn); return 2; } fseek(ifp, 0, SEEK_END); imagesize = ftell(ifp); fseek(ifp, 0, SEEK_SET); if (imagesize <= 0) { fprintf(stderr, "Error: Invalid file size %ld (%s)\n", imagesize, strerror(errno)); return 3; } image = malloc(imagesize); if (!image) { fprintf(stderr, "Error: Unable to allocate memory for image: %ld\n", imagesize); return 4; } fread(image, imagesize, 1, ifp); fclose(ifp); /* Decrypt header (padded to 1024 bytes) */ curr = rc6_decrypt_inplace(image, 1024, &header_ctx); /* Decrypt file headers */ header = (struct imagewty_header*)image; curr = rc6_decrypt_inplace(curr, header->num_files * 1024, &fileheaders_ctx); /* Decrypt file contents */ for (i=0; i < header->num_files; i++) { struct imagewty_file_header *filehdr; void *next; filehdr = (struct imagewty_file_header*)(image + 1024 + (i * 1024)); next = rc6_decrypt_inplace(curr, filehdr->stored_length, &filecontent_ctx); #if TF_DECRYPT_WORKING if (!(strlen(filehdr->filename) >= 4 && strncmp(filehdr->filename + strlen(filehdr->filename) -4, ".fex", 4) == 0)) { /* Not a 'FEX' file, so we need to decrypt it even more! */ tf_decrypt_inplace(curr, filehdr->stored_length); } #endif curr = next; } if (flag_compat_output == OUTPUT_UNIMG) { lfp = dir_fopen(outdn, "base.hdr", "wb"); if (lfp) { uint32_t *hdr = image + IMAGEWTY_MAGIC_LEN; fprintf(lfp, "%.8s\r\n", header->magic); for (i = 0; i < (sizeof(*header) - IMAGEWTY_MAGIC_LEN) / sizeof(uint32_t); i++) fprintf(lfp, "%08X\r\n", hdr[i]); fclose(lfp); } lfp = dir_fopen(outdn, "Filelist.txt", "wb"); } else if (flag_compat_output == OUTPUT_IMGREPACKER) { lfp = dir_fopen(outdn, "image.cfg", "wb"); if (lfp != NULL) { char timestr[256]; struct tm *tm; time_t t; time(&t); tm = localtime(&t); strcpy(timestr, asctime(tm)); /* strip newline */ timestr[strlen(timestr) -1] = '\0'; fputs(";/**************************************************************************/\r\n", lfp); fprintf(lfp, "; %s\r\n", timestr); fprintf(lfp, "; generated by %s\r\n", progname); fprintf(lfp, "; %s\r\n", infn); fputs(";/**************************************************************************/\r\n", lfp); fputs("[FILELIST]\r\n", lfp); } } for (i=0; i < header->num_files; i++) { struct imagewty_file_header *filehdr; char hdrfname[32], contfname[32]; filehdr = (struct imagewty_file_header*)(image + 1024 + (i * 1024)); if (flag_compat_output == OUTPUT_UNIMG) { printf("Extracting: %.8s %.16s (%u, %u)\n", filehdr->maintype, filehdr->subtype, filehdr->original_length, filehdr->stored_length); sprintf(hdrfname, "%.8s_%.16s.hdr", filehdr->maintype, filehdr->subtype); ofp = dir_fopen(outdn, hdrfname, "wb"); if (ofp) { fwrite(filehdr, filehdr->total_header_size, 1, ofp); fclose(ofp); } sprintf(contfname, "%.8s_%.16s", filehdr->maintype, filehdr->subtype); ofp = dir_fopen(outdn, contfname, "wb"); if (ofp) { fwrite(image + filehdr->offset, filehdr->original_length, 1, ofp); fclose(ofp); } fprintf(lfp, "%s\t%s\r\n", hdrfname, contfname); } else if (flag_compat_output == OUTPUT_IMGREPACKER) { printf("Extracting %s\n", filehdr->filename); ofp = dir_fopen(outdn, filehdr->filename, "wb"); if (ofp) { fwrite(image + filehdr->offset, filehdr->original_length, 1, ofp); fclose(ofp); } fprintf(lfp, "\t{filename = INPUT_DIR .. \"%s\", maintype = \"%.8s\", subtype = \"%.16s\",},\r\n", filehdr->filename[0] == '/' ? filehdr->filename+1 : filehdr->filename, filehdr->maintype, filehdr->subtype); } } if (lfp && flag_compat_output == OUTPUT_IMGREPACKER) { /* Now print the relevant stuff for the image.cfg */ fputs("\r\n[IMAGE_CFG]\r\n", lfp); fprintf(lfp, "version = 0x%06x\r\n", header->version); fprintf(lfp, "pid = 0x%08x\r\n", header->pid); fprintf(lfp, "vid = 0x%08x\r\n", header->vid); fprintf(lfp, "hardwareid = 0x%03x\r\n", header->hardware_id); fprintf(lfp, "firmwareid = 0x%03x\r\n", header->firmware_id); fprintf(lfp, "imagename = %s\r\n", infn); fputs("filelist = FILELIST\r\n", lfp); } if (lfp) fclose(lfp); return 0; }
/* loadAnim opens the file and loads data from it into the header structs. * It should take care to clean up after itself should an error occur. */ int JE_loadAnim( const char *filename ) { uint32_t i, fileSize; char temp[4]; Curlpnum = -1; InFile = dir_fopen(data_dir(), filename, "rb"); if(InFile == NULL) { return(-1); } fileSize = ftell_eof(InFile); if(fileSize < ANIM_OFFSET) { /* We don't know the exact size our file should be yet, * but we do know it should be way more than this */ fclose(InFile); return(-1); } /* Read in the header. The header is 256 bytes long or so, * but that includes a lot of padding as well as several * vars we really don't care about. We shall check the ID and extract * the handful of vars we care about. Every value in the header that * is constant will be ignored. */ efread(&temp, 1, 4, InFile); /* The ID, should equal "LPF " */ fseek(InFile, 2, SEEK_CUR); /* skip over this word */ efread(&FileHeader.nlps, 2, 1, InFile); /* Number of pages */ efread(&FileHeader.nRecords, 4, 1, InFile); /* Number of records */ if (memcmp(temp, "LPF ", 4) != 0 || FileHeader.nlps == 0 || FileHeader.nRecords == 0 || FileHeader.nlps > 256 || FileHeader.nRecords > 65535) { fclose(InFile); return(-1); } /* Read in headers */ fseek(InFile, PAGEHEADER_OFFSET, SEEK_SET); for (i = 0; i < FileHeader.nlps; i++) { efread(&PageHeader[i].baseRecord, 2, 1, InFile); efread(&PageHeader[i].nRecords, 2, 1, InFile); efread(&PageHeader[i].nBytes, 2, 1, InFile); } /* Now we have enough information to calculate the 'expected' file size. * Our calculation SHOULD be equal to fileSize, but we won't begrudge * padding */ if (fileSize < (FileHeader.nlps-1) * ANI_PAGE_SIZE + ANIM_OFFSET + PageHeader[FileHeader.nlps-1].nBytes + PageHeader[FileHeader.nlps-1].nRecords * 2 + 8) { fclose(InFile); return(-1); } /* Now read in the palette. */ fseek(InFile, PALETTE_OFFSET, SEEK_SET); for (i = 0; i < 256; i++) { efread(&colors[i].b, 1, 1, InFile); efread(&colors[i].g, 1, 1, InFile); efread(&colors[i].r, 1, 1, InFile); efread(&colors[i].unused, 1, 1, InFile); } set_palette(colors, 0, 255); /* Whew! That was hard. Let's go grab some beers! */ return(0); }
U16 MemoryAlloc(U16 size, long count, int stored_at) { // Returns handle number if successful, 0 or nullptr if failure U16 handle = 0; int use_this_type; long toallocate; toallocate = count * size; if (toallocate <= 0) // we failed, can't allocate > 2,147,483,647 return 0U; // or it wraps around to negative /* check structure for requested memory type (add em up) to see if sufficient amount is available to grant request */ use_this_type = check_for_mem(stored_at, toallocate); if (use_this_type == NOWHERE) { DisplayError(stored_at, toallocate); goodbye(); } // get next available handle handle = next_handle(); if (handle >= MAXHANDLES || handle == 0) { DisplayHandle(handle); return 0U; // Oops, do something about this! ????? } // attempt to allocate requested memory type bool success = false; switch (use_this_type) { default: case NOWHERE: // MemoryAlloc use_this_type = NOWHERE; // in case nonsense value is passed break; case MEMORY: // MemoryAlloc // Availability of memory checked in check_for_mem() handletable[handle].Linearmem.memory = (BYTE *)malloc(toallocate); handletable[handle].Linearmem.size = toallocate; handletable[handle].Linearmem.stored_at = MEMORY; numTOTALhandles++; success = true; break; case DISK: // MemoryAlloc memfile[9] = (char)(handle % 10 + (int)'0'); memfile[8] = (char)((handle % 100) / 10 + (int)'0'); memfile[7] = (char)((handle % 1000) / 100 + (int)'0'); if (disktarga) handletable[handle].Disk.file = dir_fopen(workdir, light_name, "a+b"); else handletable[handle].Disk.file = dir_fopen(tempdir, memfile, "w+b"); rewind(handletable[handle].Disk.file); if (fseek(handletable[handle].Disk.file, toallocate, SEEK_SET) != 0) handletable[handle].Disk.file = nullptr; if (handletable[handle].Disk.file == nullptr) { handletable[handle].Disk.stored_at = NOWHERE; use_this_type = NOWHERE; WhichDiskError(1); DisplayMemory(); driver_buzzer(buzzer_codes::PROBLEM); break; } numTOTALhandles++; success = true; fclose(handletable[handle].Disk.file); // so clusters aren't lost if we crash while running if (disktarga) handletable[handle].Disk.file = dir_fopen(workdir, light_name, "r+b"); else handletable[handle].Disk.file = dir_fopen(tempdir, memfile, "r+b"); // reopen rewind(handletable[handle].Disk.file); handletable[handle].Disk.size = toallocate; handletable[handle].Disk.stored_at = DISK; use_this_type = DISK; break; } // end of switch if (stored_at != use_this_type && debugflag == debug_flags::display_memory_statistics) { char buf[MSGLEN]; sprintf(buf, "Asked for %s, allocated %lu bytes of %s, handle = %u.", memstr[stored_at], toallocate, memstr[use_this_type], handle); stopmsg(STOPMSG_INFO_ONLY | STOPMSG_NO_BUZZER, (char *)buf); DisplayMemory(); } if (success) return (handle); else // return 0 if failure return 0U; }
static int pack_image(const char *indn, const char *outfn) { struct imagewty_header *header; group_t *head, *filelist; uint32_t i, num_files; variable_t *var; FILE *cfp, *ofp; void *p; /* try to open image configuration */ cfp = dir_fopen(indn, "image.cfg", "r"); if (cfp == NULL) { fprintf(stderr, "Error: unable to open %s/%s!\n", indn, "image.cfg"); return -ENOENT; } ofp = fopen(outfn, "wb"); if (ofp == NULL) { fprintf(stderr, "Error: could not create image file %s!\n", outfn); fclose(cfp); return -ENOENT; } /* file is there, now try to load it */ head = cfg_load(cfp); fclose(cfp); if (head == NULL) { fprintf(stderr, "Error: failed to parse %s/%s!\n", indn, "image.cfg"); return -EINVAL; } /* Got configuration, time to start packing it all up! */ var = cfg_find_var("filelist", head); if (var == NULL || var->type != VT_STRING) { fprintf(stderr, "Error: Unable to find filelist string " "variable in configuration!\n"); cfg_free(head); return -EINVAL; } filelist = cfg_find_group(var->str, head); if (filelist == NULL) { fprintf(stderr, "Error: unable to find group %s!\n", var->str); cfg_free(head); return -EINVAL; } num_files = cfg_count_vars(filelist); if (!num_files) { fprintf(stderr, "Error: no files to pack found in configuration!\n"); cfg_free(head); return -EINVAL; } p = malloc(1024 + num_files * 1024); if (p == NULL) { fprintf(stderr, "Error: failed to allocate memory for image!\n"); cfg_free(head); return -ENOMEM; } /* Initialize image file header */ memset(p, 0, 1024 + num_files * 1024); header = p; memcpy(header->magic, IMAGEWTY_MAGIC, sizeof(header->magic)); header->header_version = 0x0100; header->header_size = 0x50; /* should be 0x60 for version == 0x0300 */ header->ram_base = 0x04D00000; header->version = cfg_get_number("version", head); header->image_size = 0; /* this will be filled in later on */ header->image_header_size = 1024; header->v1.pid = cfg_get_number("pid", head); header->v1.vid = cfg_get_number("vid", head); header->v1.hardware_id = cfg_get_number("hardwareid", head); header->v1.firmware_id = cfg_get_number("firmwareid", head); header->v1.val1 = 1; header->v1.val1024 = 1024; header->v1.num_files = num_files; header->v1.num_files = cfg_count_vars(filelist); header->v1.val1024_2 = 1024; /* Setup file headers */ { uint32_t offset = (num_files +1) * 1024; struct imagewty_file_header *fheaders; variable_t *var; fheaders = (struct imagewty_file_header*) (p + 1024); for(var=filelist->vars; var; var=var->next) { variable_t *v, *fn = NULL, *mt = NULL, *st = NULL; uint32_t size; FILE *fp; for (v=var->items; v; v=v->next) { if (v->type != VT_STRING) continue; if (strcmp(v->name, "filename") == 0) fn = v; else if (strcmp(v->name, "maintype") == 0) mt = v; else if (strcmp(v->name, "subtype") == 0) st = v; } if (!fn || !mt || !st) { fprintf(stderr, "Error: incomplete filelist item!\n"); return -EINVAL; } fheaders->filename_len = IMAGEWTY_FHDR_FILENAME_LEN; fheaders->total_header_size = 1024; strcpy((char*)fheaders->v1.filename, fn->str); strcpy((char*)fheaders->maintype, mt->str); strcpy((char*)fheaders->subtype, st->str); fp = dir_fopen(indn, fn->str, "rb"); if (fp) { fseek(fp, 0, SEEK_END); size = ftell(fp); fclose(fp); } else { fprintf(stderr, "Error: unable to read file '%s'!\n", fn->str); continue; } fheaders->v1.offset = offset; fheaders->v1.stored_length = fheaders->v1.original_length = size; if (fheaders->v1.stored_length & 0x1FF) { fheaders->v1.stored_length &= ~0x1FF; fheaders->v1.stored_length += 0x200; } offset += fheaders->v1.stored_length; fheaders = (struct imagewty_file_header*) ((uint8_t*)fheaders + 1024); } /* We now know the total size of the file; patch it into the main header */ if (offset & 0xFF) offset = (offset & 0xFF) + 0x100; header->image_size = offset; } /* Now we have all headers setup in memory, time to write out the image file */ fwrite(p, 1024, num_files +1, ofp); /* now write the file content too */ for (i = 1; i <= num_files; i++) { struct imagewty_file_header *h = (struct imagewty_file_header*)(p + i * 1024); FILE *fp = dir_fopen(indn, h->v1.filename, "rb"); if (fp != NULL) { char buf[512]; size_t size = 0; while(!feof(fp)) { size_t bytesread = fread(buf, 1, 512, fp); if (bytesread) { if (bytesread & 0x1ff) bytesread = (bytesread & ~0x1ff) + 0x200; if (flag_encryption_enabled) rc6_encrypt_inplace(buf, bytesread, &filecontent_ctx); fwrite(buf, 1, bytesread, ofp); } size += bytesread; } fclose(fp); } } /* Headers no longer used; encrypt and write if requested */ if (flag_encryption_enabled) { void *curr = rc6_encrypt_inplace(p, 1024, &header_ctx); rc6_encrypt_inplace(curr, num_files * 1024, &fileheaders_ctx); rewind(ofp); fwrite(p, 1024, num_files +1, ofp); } fclose(ofp); /* Done, free configuration, no longer needed */ cfg_free(head); return 0; }