/** * Load a standard MIDI file. * @param filename name of the file to load * @returns true if loaded was successful */ bool MidiFile::LoadFile(const char *filename) { _midifile_instance = this; this->blocks.clear(); this->tempos.clear(); this->tickdiv = 0; bool success = false; FILE *file = FioFOpenFile(filename, "rb", Subdirectory::BASESET_DIR); if (file == NULL) return false; SMFHeader header; if (!ReadSMFHeader(file, header)) goto cleanup; /* Only format 0 (single-track) and format 1 (multi-track single-song) are accepted for now */ if (header.format != 0 && header.format != 1) goto cleanup; /* Doesn't support SMPTE timecode files */ if ((header.tickdiv & 0x8000) != 0) goto cleanup; this->tickdiv = header.tickdiv; for (; header.tracks > 0; header.tracks--) { if (!ReadTrackChunk(file, *this)) { goto cleanup; } } success = FixupMidiData(*this); cleanup: FioFCloseFile(file); return success; }
/** * Calculate the MD5 sum for a GRF, and store it in the config. * @param config GRF to compute. * @param subdir The subdirectory to look in. * @return MD5 sum was successfully computed */ static bool CalcGRFMD5Sum(GRFConfig *config, Subdirectory subdir) { FILE *f; Md5 checksum; uint8 buffer[1024]; size_t len, size; /* open the file */ f = FioFOpenFile(config->filename, "rb", subdir, &size); if (f == NULL) return false; long start = ftell(f); size = min(size, GRFGetSizeOfDataSection(f)); if (start < 0 || fseek(f, start, SEEK_SET) < 0) { FioFCloseFile(f); return false; } /* calculate md5sum */ while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) { size -= len; checksum.Append(buffer, len); } checksum.Finish(config->ident.md5sum); FioFCloseFile(f); return true; }
static void debug_print(const char *dbg, const char *buf) { #if defined(ENABLE_NETWORK) if (_debug_socket != INVALID_SOCKET) { char buf2[1024 + 32]; snprintf(buf2, lengthof(buf2), "%sdbg: [%s] %s\n", GetLogPrefix(), dbg, buf); send(_debug_socket, buf2, (int)strlen(buf2), 0); return; } #endif /* ENABLE_NETWORK */ if (strcmp(dbg, "desync") != 0) { #if defined(WINCE) /* We need to do OTTD2FS twice, but as it uses a static buffer, we need to store one temporary */ TCHAR tbuf[512]; _sntprintf(tbuf, sizeof(tbuf), _T("%s"), OTTD2FS(dbg)); NKDbgPrintfW(_T("dbg: [%s] %s\n"), tbuf, OTTD2FS(buf)); #else fprintf(stderr, "%sdbg: [%s] %s\n", GetLogPrefix(), dbg, buf); #endif IConsoleDebug(dbg, buf); } else { static FILE *f = FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR); if (f == NULL) return; fprintf(f, "%s%s\n", GetLogPrefix(), buf); fflush(f); } }
void FioOpenFile(int slot, const char *filename) { FILE *f; #if defined(LIMITED_FDS) FioFreeHandle(); #endif /* LIMITED_FDS */ f = FioFOpenFile(filename); if (f == NULL) usererror("Cannot open file '%s'", filename); uint32 pos = ftell(f); FioCloseFile(slot); // if file was opened before, close it _fio.handles[slot] = f; _fio.filenames[slot] = filename; /* Store the filename without path and extension */ const char *t = strrchr(filename, PATHSEPCHAR); _fio.shortnames[slot] = strdup(t == NULL ? filename : t); char *t2 = strrchr(_fio.shortnames[slot], '.'); if (t2 != NULL) *t2 = '\0'; strtolower(_fio.shortnames[slot]); #if defined(LIMITED_FDS) _fio.usage_count[slot] = 0; _fio.open_handles++; #endif /* LIMITED_FDS */ FioSeekToFile(slot, pos); }
/* Add the file and calculate the md5 sum. */ virtual bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) { Md5 checksum; uint8 buffer[1024]; size_t len, size; byte tmp_md5sum[16]; /* Open the file ... */ FILE *f = FioFOpenFile(filename, "rb", this->dir, &size); if (f == NULL) return false; /* ... calculate md5sum... */ while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) { size -= len; checksum.Append(buffer, len); } checksum.Finish(tmp_md5sum); FioFCloseFile(f); /* ... and xor it to the overall md5sum. */ for (uint i = 0; i < sizeof(md5sum); i++) this->md5sum[i] ^= tmp_md5sum[i]; return true; }
/** * Check whether the given file exists * @param filename the file to try for existance * @param subdir the subdirectory to look in * @return true if and only if the file can be opened */ bool FioCheckFileExists(const char *filename, Subdirectory subdir) { FILE *f = FioFOpenFile(filename, "rb", subdir); if (f == NULL) return false; FioFCloseFile(f); return true; }
/** * Read the header of a standard MIDI file. * @param[in] filename name of file to read from * @param[out] header filled with data read * @return true if the file could be opened and contained a header with correct format */ bool MidiFile::ReadSMFHeader(const char *filename, SMFHeader &header) { FILE *file = FioFOpenFile(filename, "rb", Subdirectory::BASESET_DIR); if (!file) return false; bool result = ReadSMFHeader(file, header); FioFCloseFile(file); return result; }
/** * Reads the heightmap and/or size of the heightmap from a PNG file. * If map == NULL only the size of the PNG is read, otherwise a map * with grayscale pixels is allocated and assigned to *map. */ static bool ReadHeightmapPNG(char *filename, uint *x, uint *y, byte **map) { FILE *fp; png_structp png_ptr = NULL; png_infop info_ptr = NULL; fp = FioFOpenFile(filename, "rb"); if (fp == NULL) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR); return false; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR); fclose(fp); return false; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL || setjmp(png_jmpbuf(png_ptr))) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return false; } png_init_io(png_ptr, fp); /* Allocate memory and read image, without alpha or 16-bit samples * (result is either 8-bit indexed/grayscale or 24-bit RGB) */ png_set_packing(png_ptr); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_STRIP_16, NULL); /* Maps of wrong colour-depth are not used. * (this should have been taken care of by stripping alpha and 16-bit samples on load) */ if ((png_get_channels(png_ptr, info_ptr) != 1) && (png_get_channels(png_ptr, info_ptr) != 3) && (png_get_bit_depth(png_ptr, info_ptr) != 8)) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_IMAGE_TYPE, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return false; } if (map != NULL) { *map = MallocT<byte>(png_get_image_width(png_ptr, info_ptr) * png_get_image_height(png_ptr, info_ptr)); ReadHeightmapPNGImageData(*map, png_ptr, info_ptr); } *x = png_get_image_width(png_ptr, info_ptr); *y = png_get_image_height(png_ptr, info_ptr); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return true; }
/** * Reads the heightmap and/or size of the heightmap from a BMP file. * If map == nullptr only the size of the BMP is read, otherwise a map * with grayscale pixels is allocated and assigned to *map. */ static bool ReadHeightmapBMP(const char *filename, uint *x, uint *y, byte **map) { FILE *f; BmpInfo info; BmpData data; BmpBuffer buffer; /* Init BmpData */ memset(&data, 0, sizeof(data)); f = FioFOpenFile(filename, "rb", HEIGHTMAP_DIR); if (f == nullptr) { ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR); return false; } BmpInitializeBuffer(&buffer, f); if (!BmpReadHeader(&buffer, &info, &data)) { ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR); fclose(f); BmpDestroyData(&data); return false; } /* Check if image dimensions don't overflow a size_t to avoid memory corruption. */ if ((uint64)info.width * info.height >= (size_t)-1 / (info.bpp == 24 ? 3 : 1)) { ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR); fclose(f); BmpDestroyData(&data); return false; } if (map != nullptr) { if (!BmpReadBitmap(&buffer, &info, &data)) { ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR); fclose(f); BmpDestroyData(&data); return false; } *map = MallocT<byte>(info.width * info.height); ReadHeightmapBMPImageData(*map, &info, &data); } BmpDestroyData(&data); *x = info.width; *y = info.height; fclose(f); return true; }
/** * Calculate and check the MD5 hash of the supplied GRF. * @param file The file get the hash of. * @param subdir The sub directory to get the files from. * @return * - #CR_MATCH if the MD5 hash matches * - #CR_MISMATCH if the MD5 does not match * - #CR_NO_FILE if the file misses */ /* static */ MD5File::ChecksumResult GraphicsSet::CheckMD5(const MD5File *file, Subdirectory subdir) { size_t size = 0; FILE *f = FioFOpenFile(file->filename, "rb", subdir, &size); if (f == NULL) return MD5File::CR_NO_FILE; size_t max = GRFGetSizeOfDataSection(f); FioFCloseFile(f); return file->CheckMD5(subdir, max); }
/** Opens OpenTTD files somewhere in a personal or global directory */ FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize) { FILE *f = NULL; Searchpath sp; assert(subdir < NUM_SUBDIRS || subdir == NO_DIRECTORY); FOR_ALL_SEARCHPATHS(sp) { f = FioFOpenFileSp(filename, mode, sp, subdir, filesize); if (f != NULL || subdir == NO_DIRECTORY) break; } /* We can only use .tar in case of data-dir, and read-mode */ if (f == NULL && mode[0] == 'r') { static const uint MAX_RESOLVED_LENGTH = 2 * (100 + 100 + 155) + 1; // Enough space to hold two filenames plus link. See 'TarHeader'. char resolved_name[MAX_RESOLVED_LENGTH]; /* Filenames in tars are always forced to be lowercase */ strecpy(resolved_name, filename, lastof(resolved_name)); strtolower(resolved_name); size_t resolved_len = strlen(resolved_name); /* Resolve ONE directory link */ for (TarLinkList::iterator link = _tar_linklist.begin(); link != _tar_linklist.end(); link++) { const std::string &src = link->first; size_t len = src.length(); if (resolved_len >= len && resolved_name[len - 1] == PATHSEPCHAR && strncmp(src.c_str(), resolved_name, len) == 0) { /* Apply link */ char resolved_name2[MAX_RESOLVED_LENGTH]; const std::string &dest = link->second; strecpy(resolved_name2, &(resolved_name[len]), lastof(resolved_name2)); strecpy(resolved_name, dest.c_str(), lastof(resolved_name)); strecpy(&(resolved_name[dest.length()]), resolved_name2, lastof(resolved_name)); break; // Only resolve one level } } TarFileList::iterator it = _tar_filelist.find(resolved_name); if (it != _tar_filelist.end()) { f = FioFOpenFileTar(&((*it).second), filesize); } } /* Sometimes a full path is given. To support * the 'subdirectory' must be 'removed'. */ if (f == NULL && subdir != NO_DIRECTORY) { f = FioFOpenFile(filename, mode, NO_DIRECTORY, filesize); } return f; }
/** * Read all the raw language strings from the given file. * @param file The file to read from. * @return The raw strings, or NULL upon error. */ LanguageStrings *ReadRawLanguageStrings(const char *file) { LanguageStrings *ret = NULL; FILE *fh = NULL; try { size_t to_read; fh = FioFOpenFile(file, "rb", GAME_DIR, &to_read); if (fh == NULL) { return NULL; } const char *langname = strrchr(file, PATHSEPCHAR); if (langname == NULL) { langname = file; } else { langname++; } /* Check for invalid empty filename */ if (*langname == '.' || *langname == 0) { fclose(fh); return NULL; } ret = new LanguageStrings(langname, strchr(langname, '.')); char buffer[2048]; while (to_read != 0 && fgets(buffer, sizeof(buffer), fh) != NULL) { size_t len = strlen(buffer); /* Remove trailing spaces/newlines from the string. */ size_t i = len; while (i > 0 && (buffer[i - 1] == '\r' || buffer[i - 1] == '\n' || buffer[i - 1] == ' ')) i--; buffer[i] = '\0'; *ret->lines.Append() = stredup(buffer, buffer + to_read - 1); if (len > to_read) { to_read = 0; } else { to_read -= len; } } fclose(fh); return ret; } catch (...) { if (fh != NULL) fclose(fh); delete ret; return NULL; } }
void GetOldSaveGameName(const char *file, char *title, const char *last) { FILE *f = FioFOpenFile(file, "rb", NO_DIRECTORY); if (f == NULL) { *title = '\0'; return; } DetermineOldSavegameType(f, title, last); fclose(f); }
bool LoadOldSaveGame(const char *file) { LoadgameState ls; DEBUG(oldloader, 3, "Trying to load a TTD(Patch) savegame"); InitLoading(&ls); /* Open file */ ls.file = FioFOpenFile(file, "rb", NO_DIRECTORY); if (ls.file == NULL) { DEBUG(oldloader, 0, "Cannot open file '%s'", file); return false; } SavegameType type = DetermineOldSavegameType(ls.file, NULL, NULL); LoadOldMainProc *proc = NULL; switch (type) { case SGT_TTO: proc = &LoadTTOMain; break; case SGT_TTD: proc = &LoadTTDMain; break; default: break; } _savegame_type = type; bool game_loaded; try { game_loaded = proc != NULL && proc(&ls); } catch (...) { game_loaded = false; } if (!game_loaded) { SetSaveLoadError(STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED); fclose(ls.file); return false; } _pause_mode = 2; return true; }
/** * Reads the heightmap and/or size of the heightmap from a BMP file. * If map == NULL only the size of the BMP is read, otherwise a map * with grayscale pixels is allocated and assigned to *map. */ static bool ReadHeightmapBMP(char *filename, uint *x, uint *y, byte **map) { FILE *f; BmpInfo info; BmpData data; BmpBuffer buffer; /* Init BmpData */ memset(&data, 0, sizeof(data)); f = FioFOpenFile(filename, "rb"); if (f == NULL) { ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR); return false; } BmpInitializeBuffer(&buffer, f); if (!BmpReadHeader(&buffer, &info, &data)) { ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR); fclose(f); BmpDestroyData(&data); return false; } if (map != NULL) { if (!BmpReadBitmap(&buffer, &info, &data)) { ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR); fclose(f); BmpDestroyData(&data); return false; } *map = MallocT<byte>(info.width * info.height); ReadHeightmapBMPImageData(*map, &info, &data); } BmpDestroyData(&data); *x = info.width; *y = info.height; fclose(f); return true; }
/** * Calculate the MD5 sum for a GRF, and store it in the config. * @param config GRF to compute. * @return MD5 sum was successfully computed */ static bool CalcGRFMD5Sum(GRFConfig *config) { FILE *f; Md5 checksum; uint8 buffer[1024]; size_t len, size; /* open the file */ f = FioFOpenFile(config->filename, "rb", DATA_DIR, &size); if (f == NULL) return false; /* calculate md5sum */ while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) { size -= len; checksum.Append(buffer, len); } checksum.Finish(config->ident.md5sum); FioFCloseFile(f); return true; }
/** * Calculate and check the MD5 hash of the supplied filename. * @param subdir The sub directory to get the files from * @return * - #CR_MATCH if the MD5 hash matches * - #CR_MISMATCH if the MD5 does not match * - #CR_NO_FILE if the file misses */ MD5File::ChecksumResult MD5File::CheckMD5(Subdirectory subdir) const { size_t size; FILE *f = FioFOpenFile(this->filename, "rb", subdir, &size); if (f == NULL) return CR_NO_FILE; Md5 checksum; uint8 buffer[1024]; uint8 digest[16]; size_t len; while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) { size -= len; checksum.Append(buffer, len); } FioFCloseFile(f); checksum.Finish(digest); return memcmp(this->hash, digest, sizeof(this->hash)) == 0 ? CR_MATCH : CR_MISMATCH; }
/** * Read all the raw language strings from the given file. * @param file The file to read from. * @return The raw strings, or NULL upon error. */ LanguageStrings *ReadRawLanguageStrings(const char *file) { LanguageStrings *ret = NULL; try { size_t to_read; FILE *fh = FioFOpenFile(file, "rb", GAME_DIR, &to_read); if (fh == NULL) { return NULL; } ret = new LanguageStrings(file); char buffer[2048]; while (to_read != 0 && fgets(buffer, sizeof(buffer), fh) != NULL) { size_t len = strlen(buffer); /* Remove trailing spaces/newlines from the string. */ size_t i = len; while (i > 0 && (buffer[i - 1] == '\r' || buffer[i - 1] == '\n' || buffer[i - 1] == ' ')) i--; buffer[i] = '\0'; *ret->lines.Append() = strndup(buffer, to_read); if (len > to_read) { to_read = 0; } else { to_read -= len; } } return ret; } catch (...) { delete ret; return NULL; } }
void IniFile::LoadFromDisk(const char *filename) { assert(this->last_group == &this->group); char buffer[1024]; IniGroup *group = NULL; char *comment = NULL; uint comment_size = 0; uint comment_alloc = 0; size_t end; /* * Now we are going to open a file that contains no more than simple * plain text. That would raise the question: "why open the file as * if it is a binary file?". That's simple... Microsoft, in all * their greatness and wisdom decided it would be useful if ftell * is aware of '\r\n' and "sees" that as a single character. The * easiest way to test for that situation is by searching for '\n' * and decrease the value every time you encounter a '\n'. This will * thus also make ftell "see" the '\r' when it is not there, so the * result of ftell will be highly unreliable. So to work around this * marvel of wisdom we have to open in as a binary file. */ FILE *in = FioFOpenFile(filename, "rb", DATA_DIR, &end); if (in == NULL) return; end += ftell(in); /* for each line in the file */ while ((size_t)ftell(in) < end && fgets(buffer, sizeof(buffer), in)) { char c, *s; /* trim whitespace from the left side */ for (s = buffer; *s == ' ' || *s == '\t'; s++) {} /* trim whitespace from right side. */ char *e = s + strlen(s); while (e > s && ((c = e[-1]) == '\n' || c == '\r' || c == ' ' || c == '\t')) e--; *e = '\0'; /* skip comments and empty lines */ if (*s == '#' || *s == ';' || *s == '\0') { uint ns = comment_size + (e - s + 1); uint a = comment_alloc; /* add to comment */ if (ns > a) { a = max(a, 128U); do a *= 2; while (a < ns); comment = ReallocT(comment, comment_alloc = a); } uint pos = comment_size; comment_size += (e - s + 1); comment[pos + e - s] = '\n'; // comment newline memcpy(comment + pos, s, e - s); // copy comment contents continue; } /* it's a group? */ if (s[0] == '[') { if (e[-1] != ']') { ShowInfoF("ini: invalid group name '%s'", buffer); } else { e--; } s++; // skip [ group = new IniGroup(this, s, e - s); if (comment_size) { group->comment = strndup(comment, comment_size); comment_size = 0; } } else if (group) { char *t; /* find end of keyname */ if (*s == '\"') { s++; for (t = s; *t != '\0' && *t != '\"'; t++) {} if (*t == '\"') *t = ' '; } else { for (t = s; *t != '\0' && *t != '=' && *t != '\t' && *t != ' '; t++) {} } /* it's an item in an existing group */ IniItem *item = new IniItem(group, s, t - s); if (comment_size) { item->comment = strndup(comment, comment_size); comment_size = 0; } /* find start of parameter */ while (*t == '=' || *t == ' ' || *t == '\t') t++; bool quoted = (*t == '\"'); /* remove starting quotation marks */ if (*t == '\"') t++; /* remove ending quotation marks */ e = t + strlen(t); if (e > t && e[-1] == '\"') e--; *e = '\0'; /* If the value was not quoted and empty, it must be NULL */ item->value = (!quoted && e == t) ? NULL : strndup(t, e - t); } else { /* it's an orphan item */ ShowInfoF("ini: '%s' outside of group", buffer); } } if (comment_size > 0) { this->comment = strndup(comment, comment_size); comment_size = 0; } free(comment); fclose(in); }
void DisplaySplashImage() { FILE *f = FioFOpenFile(SPLASH_IMAGE_FILE); if (f == NULL) return; png_byte header[8]; fread(header, sizeof(png_byte), 8, f); if (png_sig_cmp(header, 0, 8) != 0) { fclose(f); return; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, png_my_error, png_my_warning); if (png_ptr == NULL) { fclose(f); return; } png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(f); return; } png_infop end_info = png_create_info_struct(png_ptr); if (end_info == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(f); return; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return; } png_init_io(png_ptr, f); png_set_sig_bytes(png_ptr, 8); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); uint width = png_get_image_width(png_ptr, info_ptr); uint height = png_get_image_height(png_ptr, info_ptr); uint bit_depth = png_get_bit_depth(png_ptr, info_ptr); uint color_type = png_get_color_type(png_ptr, info_ptr); if (color_type != PNG_COLOR_TYPE_PALETTE || bit_depth != 8) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return; } if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return; } png_colorp palette; int num_palette; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); png_bytep *row_pointers = png_get_rows(png_ptr, info_ptr); if (width > (uint) _screen.width) width = _screen.width; if (height > (uint) _screen.height) height = _screen.height; uint xoff = (_screen.width - width) / 2; uint yoff = (_screen.height - height) / 2; switch (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth()) { case 8: { uint8 *dst_ptr = (uint8 *)_screen.dst_ptr; /* Initialize buffer */ MemSetT(dst_ptr, 0xff, _screen.pitch * _screen.height); for (uint y = 0; y < height; y++) { uint8 *src = row_pointers[y]; uint8 *dst = dst_ptr + (yoff + y) * _screen.pitch + xoff; memcpy(dst, src, width); } for (int i = 0; i < num_palette; i++) { _cur_palette[i].a = i == 0 ? 0 : 0xff; _cur_palette[i].r = palette[i].red; _cur_palette[i].g = palette[i].green; _cur_palette[i].b = palette[i].blue; } _cur_palette[0xff].a = 0xff; _cur_palette[0xff].r = 0; _cur_palette[0xff].g = 0; _cur_palette[0xff].b = 0; _pal_first_dirty = 0; _pal_count_dirty = 256; break; } case 32: { uint32 *dst_ptr = (uint32 *)_screen.dst_ptr; /* Initialize buffer */ MemSetT(dst_ptr, 0, _screen.pitch * _screen.height); for (uint y = 0; y < height; y++) { uint8 *src = row_pointers[y]; uint32 *dst = dst_ptr + (yoff + y) * _screen.pitch + xoff; for (uint x = 0; x < width; x++) { dst[x] = palette[src[x]].blue | (palette[src[x]].green << 8) | (palette[src[x]].red << 16) | 0xff000000; } } break; } } png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return; }
/* virtual */ FILE *IniFile::OpenFile(const char *filename, Subdirectory subdir, size_t *size) { /* Open the text file in binary mode to prevent end-of-line translations * done by ftell() and friends, as defined by K&R. */ return FioFOpenFile(filename, "rb", subdir, size); }
/** * Reads the heightmap and/or size of the heightmap from a PNG file. * If map == nullptr only the size of the PNG is read, otherwise a map * with grayscale pixels is allocated and assigned to *map. */ static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, byte **map) { FILE *fp; png_structp png_ptr = nullptr; png_infop info_ptr = nullptr; fp = FioFOpenFile(filename, "rb", HEIGHTMAP_DIR); if (fp == nullptr) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR); return false; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (png_ptr == nullptr) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR); fclose(fp); return false; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == nullptr || setjmp(png_jmpbuf(png_ptr))) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return false; } png_init_io(png_ptr, fp); /* Allocate memory and read image, without alpha or 16-bit samples * (result is either 8-bit indexed/grayscale or 24-bit RGB) */ png_set_packing(png_ptr); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_STRIP_16, nullptr); /* Maps of wrong colour-depth are not used. * (this should have been taken care of by stripping alpha and 16-bit samples on load) */ if ((png_get_channels(png_ptr, info_ptr) != 1) && (png_get_channels(png_ptr, info_ptr) != 3) && (png_get_bit_depth(png_ptr, info_ptr) != 8)) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_IMAGE_TYPE, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return false; } uint width = png_get_image_width(png_ptr, info_ptr); uint height = png_get_image_height(png_ptr, info_ptr); /* Check if image dimensions don't overflow a size_t to avoid memory corruption. */ if ((uint64)width * height >= (size_t)-1) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return false; } if (map != nullptr) { *map = MallocT<byte>(width * height); ReadHeightmapPNGImageData(*map, png_ptr, info_ptr); } *x = width; *y = height; fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return true; }
/** * Try to add a fios item set with the given filename. * @param filename the full path to the file to read * @param basepath_length amount of characters to chop of before to get a relative filename * @return true if the file is added. */ bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) { const char *ext = strrchr(filename, '.'); if (ext == NULL) return false; char fios_title[64]; fios_title[0] = '\0'; // reset the title; FiosType type = this->callback_proc(this->mode, filename, ext, fios_title, lastof(fios_title)); if (type == FIOS_TYPE_INVALID) return false; for (const FiosItem *fios = _fios_items.Begin(); fios != _fios_items.End(); fios++) { if (strcmp(fios->name, filename) == 0) return false; } FiosItem *fios = _fios_items.Append(); #ifdef WIN32 struct _stat sb; if (_tstat(OTTD2FS(filename), &sb) == 0) { #else struct stat sb; if (stat(filename, &sb) == 0) { #endif fios->mtime = sb.st_mtime; } else { fios->mtime = 0; } fios->type = type; strecpy(fios->name, filename, lastof(fios->name)); /* If the file doesn't have a title, use its filename */ const char *t = fios_title; if (StrEmpty(fios_title)) { t = strrchr(filename, PATHSEPCHAR); t = (t == NULL) ? filename : (t + 1); } strecpy(fios->title, t, lastof(fios->title)); str_validate(fios->title, lastof(fios->title)); return true; } /** * Fill the list of the files in a directory, according to some arbitrary rule. * @param mode The mode we are in. Some modes don't allow 'parent'. * @param callback_proc The function that is called where you need to do the filtering. * @param subdir The directory from where to start (global) searching. */ static void FiosGetFileList(SaveLoadDialogMode mode, fios_getlist_callback_proc *callback_proc, Subdirectory subdir) { struct stat sb; struct dirent *dirent; DIR *dir; FiosItem *fios; int sort_start; char d_name[sizeof(fios->name)]; _fios_items.Clear(); /* A parent directory link exists if we are not in the root directory */ if (!FiosIsRoot(_fios_path)) { fios = _fios_items.Append(); fios->type = FIOS_TYPE_PARENT; fios->mtime = 0; strecpy(fios->name, "..", lastof(fios->name)); strecpy(fios->title, ".. (Parent directory)", lastof(fios->title)); } /* Show subdirectories */ if ((dir = ttd_opendir(_fios_path)) != NULL) { while ((dirent = readdir(dir)) != NULL) { strecpy(d_name, FS2OTTD(dirent->d_name), lastof(d_name)); /* found file must be directory, but not '.' or '..' */ if (FiosIsValidFile(_fios_path, dirent, &sb) && S_ISDIR(sb.st_mode) && (!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) && strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) { fios = _fios_items.Append(); fios->type = FIOS_TYPE_DIR; fios->mtime = 0; strecpy(fios->name, d_name, lastof(fios->name)); snprintf(fios->title, lengthof(fios->title), "%s" PATHSEP " (Directory)", d_name); str_validate(fios->title, lastof(fios->title)); } } closedir(dir); } /* Sort the subdirs always by name, ascending, remember user-sorting order */ { SortingBits order = _savegame_sort_order; _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING; QSortT(_fios_items.Begin(), _fios_items.Length(), CompareFiosItems); _savegame_sort_order = order; } /* This is where to start sorting for the filenames */ sort_start = _fios_items.Length(); /* Show files */ FiosFileScanner scanner(mode, callback_proc); if (subdir == NO_DIRECTORY) { scanner.Scan(NULL, _fios_path, false); } else { scanner.Scan(NULL, subdir, true, true); } QSortT(_fios_items.Get(sort_start), _fios_items.Length() - sort_start, CompareFiosItems); /* Show drives */ FiosGetDrives(); _fios_items.Compact(); } /** * Get the title of a file, which (if exists) is stored in a file named * the same as the data file but with '.title' added to it. * @param file filename to get the title for * @param title the title buffer to fill * @param last the last element in the title buffer * @param subdir the sub directory to search in */ static void GetFileTitle(const char *file, char *title, const char *last, Subdirectory subdir) { char buf[MAX_PATH]; strecpy(buf, file, lastof(buf)); strecat(buf, ".title", lastof(buf)); FILE *f = FioFOpenFile(buf, "r", subdir); if (f == NULL) return; size_t read = fread(title, 1, last - title, f); assert(title + read <= last); title[read] = '\0'; str_validate(title, last); FioFCloseFile(f); }