/** * Save a chunk of data. * @param fp The file to save to. * @param header The chunk identification string (4 chars, always). * @param saveProc The proc to call to generate the content of the chunk. * @return True if and only if all bytes were written successful. */ static bool Save_Chunk(FILE *fp, char *header, bool (*saveProc)(FILE *fp)) { uint32 position; uint32 length; uint32 lengthSwapped; if (fwrite(header, 4, 1, fp) != 1) return false; /* Reserve the length field */ length = 0; if (fwrite(&length, 4, 1, fp) != 1) return false; /* Store the content of the chunk, and remember the length */ position = ftell(fp); if (!saveProc(fp)) return false; length = ftell(fp) - position; /* Ensure we are word aligned */ if ((length & 1) == 1) { uint8 empty = 0; if (fwrite(&empty, 1, 1, fp) != 1) return false; } /* Write back the chunk size */ fseek(fp, position - 4, SEEK_SET); lengthSwapped = HTOBE32(length); if (fwrite(&lengthSwapped, 4, 1, fp) != 1) return false; fseek(fp, 0, SEEK_END); return true; }
static void FillSavegameDesc(bool save) { uint8 i; for (i = 0; i < 5; i++) { char *desc = g_savegameDesc[i]; char *filename; uint8 fileId; *desc = '\0'; if (s_savegameIndexBase - i < 0) continue; if (s_savegameIndexBase - i == s_savegameCountOnDisk) { if (!save) continue; strncpy(desc, String_Get_ByIndex(STR_EMPTY_SLOT_), 50); continue; } filename = GenerateSavegameFilename(s_savegameIndexBase - i); if (!File_Exists(filename)) continue; fileId = ChunkFile_Open(filename); ChunkFile_Read(fileId, HTOBE32(CC_NAME), desc, 50); ChunkFile_Close(fileId); continue; } }
/** * Seek to the given chunk inside a chunk file. * * @param index The index given by ChunkFile_Open() of the file. * @param chunk The chunk to seek to. * @return The length of the chunk (0 if not found). */ uint32 ChunkFile_Seek(uint8 index, uint32 chunk) { uint32 value = 0; uint32 length = 0; bool first = true; while (true) { if (File_Read(index, &value, 4) != 4 && !first) return 0; if (value == 0 && File_Read(index, &value, 4) != 4 && !first) return 0; if (File_Read(index, &length, 4) != 4 && !first) return 0; length = HTOBE32(length); if (value == chunk) { File_Seek(index, -8, 1); return length; } if (first) { File_Seek(index, 12, 0); first = false; continue; } length += 1; length &= 0xFFFFFFFE; File_Seek(index, length, 1); } }
void psbuf_put_4(struct puffs_framebuf *pb, uint32_t val) { int rv; HTOBE32(val); rv = puffs_framebuf_putdata(pb, &val, 4); CHECK(rv == 0); }
/** * Save the game for real. It creates all the required chunks and stores them * to the file. It updates the field lengths where needed. * * @param fp The file to save to. * @param description The description of the savegame. * @return True if and only if all bytes were written successful. */ static bool Save_Main(FILE *fp, char *description) { uint32 length; uint32 lengthSwapped; /* Write the 'FORM' chunk (in which all other chunks are) */ if (fwrite("FORM", 4, 1, fp) != 1) return false; /* Write zero length for now. We come back to this value before closing */ length = 0; if (fwrite(&length, 4, 1, fp) != 1) return false; /* Write the 'SCEN' chunk. Never contains content. */ if (fwrite("SCEN", 4, 1, fp) != 1) return false; /* Write the 'NAME' chunk. Keep ourself word-aligned. */ if (fwrite("NAME", 4, 1, fp) != 1) return false; length = min(255, strlen(description) + 1); lengthSwapped = HTOBE32(length); if (fwrite(&lengthSwapped, 4, 1, fp) != 1) return false; if (fwrite(description, length, 1, fp) != 1) return false; /* Ensure we are word aligned */ if ((length & 1) == 1) { uint8 empty = 0; if (fwrite(&empty, 1, 1, fp) != 1) return false; } /* Store all additional chunks */ if (!Save_Chunk(fp, "INFO", &Info_Save)) return false; if (!Save_Chunk(fp, "PLYR", &House_Save)) return false; if (!Save_Chunk(fp, "UNIT", &Unit_Save)) return false; if (!Save_Chunk(fp, "BLDG", &Structure_Save)) return false; if (!Save_Chunk(fp, "MAP ", &Map_Save)) return false; if (!Save_Chunk(fp, "TEAM", &Team_Save)) return false; /* Write the total length of all data in the FORM chunk */ length = ftell(fp) - 8; fseek(fp, 4, SEEK_SET); lengthSwapped = HTOBE32(length); if (fwrite(&lengthSwapped, 4, 1, fp) != 1) return false; return true; }
static void GUI_Mentat_LoadHelpSubjects(bool init) { static uint8 *helpDataList = NULL; uint8 fileID; uint32 length; uint32 counter; uint8 *helpSubjects; uint16 i; if (init) { helpDataList = GFX_Screen_Get_ByIndex(SCREEN_1); s_topHelpList = 0; s_selectedHelpSubject = 0; sprintf(s_mentatFilename, "MENTAT%c", g_table_houseInfo[g_playerHouseID].name[0]); strncpy(s_mentatFilename, String_GenerateFilename(s_mentatFilename), sizeof(s_mentatFilename)); } fileID = ChunkFile_Open(s_mentatFilename); length = ChunkFile_Read(fileID, HTOBE32(CC_NAME), helpDataList, GFX_Screen_GetSize_ByIndex(SCREEN_1)); ChunkFile_Close(fileID); s_numberHelpSubjects = 0; helpSubjects = helpDataList; counter = 0; while (counter < length) { uint8 size = *helpSubjects; counter += size; if (helpSubjects[size - 1] > g_campaignID + 1) { while (size-- != 0) *helpSubjects++ = '\0'; continue; } helpSubjects[size - 1] = size; helpSubjects += size; s_numberHelpSubjects++; } helpSubjects = helpDataList; while (*helpSubjects == '\0') helpSubjects++; for (i = 0; i < s_topHelpList; i++) helpSubjects = String_NextString(helpSubjects); s_helpSubjects = helpSubjects; }
/** * Open a chunk file (starting with FORM) for reading. * * @param filename The name of the file to open. * @return An index value refering to the opened file, or FILE_INVALID. */ uint8 ChunkFile_Open(const char *filename) { uint8 index; uint32 header; index = File_Open(filename, 1); File_Close(index); index = File_Open(filename, 1); File_Read(index, &header, 4); if (header != HTOBE32('FORM')) { File_Close(index); return FILE_INVALID; } File_Seek(index, 4, 1); return index; }
/** * Read bytes from a chunk file into a buffer. * * @param index The index given by ChunkFile_Open() of the file. * @param chunk The chunk to read from. * @param buffer The buffer to read into. * @param length The amount of bytes to read. * @return The amount of bytes truly read, or 0 if there was a failure. */ uint32 ChunkFile_Read(uint8 index, uint32 chunk, void *buffer, uint32 buflen) { uint32 value = 0; uint32 length = 0; bool first = true; while (true) { if (File_Read(index, &value, 4) != 4 && !first) return 0; if (value == 0 && File_Read(index, &value, 4) != 4 && !first) return 0; if (File_Read(index, &length, 4) != 4 && !first) return 0; length = HTOBE32(length); if (value == chunk) { buflen = min(buflen, length); File_Read(index, buffer, buflen); length += 1; length &= 0xFFFFFFFE; if (buflen < length) File_Seek(index, length - buflen, 1); return buflen; } if (first) { File_Seek(index, 12, 0); first = false; continue; } length += 1; length &= 0xFFFFFFFE; File_Seek(index, length, 1); } }
static void GUI_Mentat_ShowHelp(void) { struct { uint8 notused[8]; uint32 length; } info; uint8 *subject; uint16 i; bool noDesc; uint8 fileID; uint32 offset; char *compressedText; char *desc; char *picture; char *text; bool loc12; subject = s_helpSubjects; for (i = 0; i < s_selectedHelpSubject; i++) subject = String_NextString(subject); noDesc = (subject[5] == '0'); offset = HTOBE32(*(uint32 *)(subject + 1)); fileID = ChunkFile_Open(s_mentatFilename); ChunkFile_Read(fileID, HTOBE32(CC_INFO), &info, 12); ChunkFile_Close(fileID); info.length = HTOBE32(info.length); text = g_readBuffer; compressedText = GFX_Screen_Get_ByIndex(SCREEN_1); fileID = File_Open(s_mentatFilename, FILE_MODE_READ); File_Seek(fileID, offset, 0); File_Read(fileID, compressedText, info.length); String_Decompress(compressedText, text); String_TranslateSpecial(text, text); File_Close(fileID); while (*text != '*' && *text != '?') text++; loc12 = (*text == '*'); *text++ = '\0'; if (noDesc) { uint16 index; picture = g_scenario.pictureBriefing; desc = NULL; text = (char *)g_readBuffer; index = *text - 44 + g_campaignID * 4 + STR_HOUSE_HARKONNENFROM_THE_DARK_WORLD_OF_GIEDI_PRIME_THE_SAVAGE_HOUSE_HARKONNEN_HAS_SPREAD_ACROSS_THE_UNIVERSE_A_CRUEL_PEOPLE_THE_HARKONNEN_ARE_RUTHLESS_TOWARDS_BOTH_FRIEND_AND_FOE_IN_THEIR_FANATICAL_PURSUIT_OF_POWER + g_playerHouseID * 40; strncpy(g_readBuffer, String_Get_ByIndex(index), g_readBufferSize); } else { picture = (char *)g_readBuffer; desc = text; while (*text != '\0' && *text != 0xC) text++; if (*text != '\0') *text++ = '\0'; } GUI_Mentat_Loop(picture, desc, text, loc12 ? 1 : 0, g_widgetMentatFirst); GUI_Widget_MakeNormal(g_widgetMentatFirst, false); GUI_Mentat_LoadHelpSubjects(false); GUI_Mentat_Create_HelpScreen_Widgets(); GUI_Mentat_Draw(true); }