mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' into port/psp2
This commit is contained in:
commit
33ca1e2e9c
3
CHANGES
3
CHANGES
|
@ -57,6 +57,7 @@ Bugfixes:
|
||||||
- ARM7: ARMHotplugDetach should call deinit
|
- ARM7: ARMHotplugDetach should call deinit
|
||||||
- Qt: Fix window being too tall after exiting fullscreen
|
- Qt: Fix window being too tall after exiting fullscreen
|
||||||
- Qt: Fix a missing va_end call in the log handler lambda within the GameController constructor
|
- Qt: Fix a missing va_end call in the log handler lambda within the GameController constructor
|
||||||
|
- GBA Cheats: Fix Pro Action Replay and GameShark issues when used together
|
||||||
Misc:
|
Misc:
|
||||||
- Qt: Handle saving input settings better
|
- Qt: Handle saving input settings better
|
||||||
- Debugger: Free watchpoints in addition to breakpoints
|
- Debugger: Free watchpoints in addition to breakpoints
|
||||||
|
@ -97,6 +98,8 @@ Misc:
|
||||||
- GBA Hardware: Backport generic RTC source into core
|
- GBA Hardware: Backport generic RTC source into core
|
||||||
- All: Proper handling of Unicode file paths
|
- All: Proper handling of Unicode file paths
|
||||||
- GBA Video: Slightly optimize mode 0 mosaic rendering
|
- GBA Video: Slightly optimize mode 0 mosaic rendering
|
||||||
|
- VFS: Add sync method to force syncing with backing
|
||||||
|
- GBA: Savedata is now synced shortly after data finishes being written
|
||||||
|
|
||||||
0.2.1: (2015-05-13)
|
0.2.1: (2015-05-13)
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
|
|
@ -197,6 +197,7 @@ bool GBACheatAddGameShark(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
|
||||||
|
|
||||||
switch (set->gsaVersion) {
|
switch (set->gsaVersion) {
|
||||||
case 0:
|
case 0:
|
||||||
|
case 3:
|
||||||
GBACheatSetGameSharkVersion(set, 1);
|
GBACheatSetGameSharkVersion(set, 1);
|
||||||
// Fall through
|
// Fall through
|
||||||
case 1:
|
case 1:
|
||||||
|
|
|
@ -297,9 +297,10 @@ bool GBACheatAddProActionReplay(struct GBACheatSet* set, uint32_t op1, uint32_t
|
||||||
|
|
||||||
switch (set->gsaVersion) {
|
switch (set->gsaVersion) {
|
||||||
case 0:
|
case 0:
|
||||||
|
case 1:
|
||||||
GBACheatSetGameSharkVersion(set, 3);
|
GBACheatSetGameSharkVersion(set, 3);
|
||||||
// Fall through
|
// Fall through
|
||||||
case 1:
|
case 3:
|
||||||
GBACheatDecryptGameShark(&o1, &o2, set->gsaSeeds);
|
GBACheatDecryptGameShark(&o1, &o2, set->gsaSeeds);
|
||||||
return GBACheatAddProActionReplayRaw(set, o1, o2);
|
return GBACheatAddProActionReplayRaw(set, o1, o2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -756,6 +756,8 @@ void GBAFrameStarted(struct GBA* gba) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAFrameEnded(struct GBA* gba) {
|
void GBAFrameEnded(struct GBA* gba) {
|
||||||
|
GBASavedataClean(&gba->memory.savedata, gba->video.frameCounter);
|
||||||
|
|
||||||
if (gba->rr) {
|
if (gba->rr) {
|
||||||
gba->rr->nextFrame(gba->rr);
|
gba->rr->nextFrame(gba->rr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -818,6 +818,7 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
|
||||||
GBASavedataWriteFlash(&memory->savedata, address, value);
|
GBASavedataWriteFlash(&memory->savedata, address, value);
|
||||||
} else if (memory->savedata.type == SAVEDATA_SRAM) {
|
} else if (memory->savedata.type == SAVEDATA_SRAM) {
|
||||||
memory->savedata.data[address & (SIZE_CART_SRAM - 1)] = value;
|
memory->savedata.data[address & (SIZE_CART_SRAM - 1)] = value;
|
||||||
|
memory->savedata.dirty |= SAVEDATA_DIRT_NEW;
|
||||||
} else if (memory->hw.devices & HW_TILT) {
|
} else if (memory->hw.devices & HW_TILT) {
|
||||||
GBAHardwareTiltWrite(&memory->hw, address & OFFSET_MASK, value);
|
GBAHardwareTiltWrite(&memory->hw, address & OFFSET_MASK, value);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
// Other games vary from very little, with a fairly solid 20500 cycle count. (Observed on a SST (D4BF) chip).
|
// Other games vary from very little, with a fairly solid 20500 cycle count. (Observed on a SST (D4BF) chip).
|
||||||
// An average estimation is as follows.
|
// An average estimation is as follows.
|
||||||
#define FLASH_SETTLE_CYCLES 18000
|
#define FLASH_SETTLE_CYCLES 18000
|
||||||
|
#define CLEANUP_THRESHOLD 15
|
||||||
|
|
||||||
static void _flashSwitchBank(struct GBASavedata* savedata, int bank);
|
static void _flashSwitchBank(struct GBASavedata* savedata, int bank);
|
||||||
static void _flashErase(struct GBASavedata* savedata);
|
static void _flashErase(struct GBASavedata* savedata);
|
||||||
|
@ -33,6 +34,8 @@ void GBASavedataInit(struct GBASavedata* savedata, struct VFile* vf) {
|
||||||
savedata->vf = vf;
|
savedata->vf = vf;
|
||||||
savedata->realVf = vf;
|
savedata->realVf = vf;
|
||||||
savedata->mapMode = MAP_WRITE;
|
savedata->mapMode = MAP_WRITE;
|
||||||
|
savedata->dirty = 0;
|
||||||
|
savedata->dirtAge = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBASavedataDeinit(struct GBASavedata* savedata) {
|
void GBASavedataDeinit(struct GBASavedata* savedata) {
|
||||||
|
@ -252,6 +255,7 @@ void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8
|
||||||
case FLASH_STATE_RAW:
|
case FLASH_STATE_RAW:
|
||||||
switch (savedata->command) {
|
switch (savedata->command) {
|
||||||
case FLASH_COMMAND_PROGRAM:
|
case FLASH_COMMAND_PROGRAM:
|
||||||
|
savedata->dirty |= SAVEDATA_DIRT_NEW;
|
||||||
savedata->currentBank[address] = value;
|
savedata->currentBank[address] = value;
|
||||||
savedata->command = FLASH_COMMAND_NONE;
|
savedata->command = FLASH_COMMAND_NONE;
|
||||||
break;
|
break;
|
||||||
|
@ -359,6 +363,7 @@ void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32
|
||||||
uint8_t current = savedata->data[savedata->writeAddress >> 3];
|
uint8_t current = savedata->data[savedata->writeAddress >> 3];
|
||||||
current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
|
current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7)));
|
||||||
current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
|
current |= (value & 0x1) << (0x7 - (savedata->writeAddress & 0x7));
|
||||||
|
savedata->dirty |= SAVEDATA_DIRT_NEW;
|
||||||
savedata->data[savedata->writeAddress >> 3] = current;
|
savedata->data[savedata->writeAddress >> 3] = current;
|
||||||
++savedata->writeAddress;
|
++savedata->writeAddress;
|
||||||
} else {
|
} else {
|
||||||
|
@ -401,6 +406,38 @@ uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GBASavedataClean(struct GBASavedata* savedata, uint32_t frameCount) {
|
||||||
|
if (savedata->dirty & SAVEDATA_DIRT_NEW) {
|
||||||
|
savedata->dirty &= ~SAVEDATA_DIRT_NEW;
|
||||||
|
if (!(savedata->dirty & SAVEDATA_DIRT_SEEN)) {
|
||||||
|
savedata->dirtAge = frameCount;
|
||||||
|
savedata->dirty |= SAVEDATA_DIRT_SEEN;
|
||||||
|
}
|
||||||
|
} else if ((savedata->dirty & SAVEDATA_DIRT_SEEN) && frameCount - savedata->dirtAge > CLEANUP_THRESHOLD) {
|
||||||
|
size_t size;
|
||||||
|
switch (savedata->type) {
|
||||||
|
case SAVEDATA_EEPROM:
|
||||||
|
size = SIZE_CART_EEPROM;
|
||||||
|
break;
|
||||||
|
case SAVEDATA_SRAM:
|
||||||
|
size = SIZE_CART_SRAM;
|
||||||
|
break;
|
||||||
|
case SAVEDATA_FLASH512:
|
||||||
|
size = SIZE_CART_FLASH512;
|
||||||
|
break;
|
||||||
|
case SAVEDATA_FLASH1M:
|
||||||
|
size = SIZE_CART_FLASH1M;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
size = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
savedata->vf->sync(savedata->vf, savedata->data, size);
|
||||||
|
savedata->dirty = 0;
|
||||||
|
GBALog(0, GBA_LOG_INFO, "Savedata synced");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData) {
|
void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData) {
|
||||||
state->savedata.type = savedata->type;
|
state->savedata.type = savedata->type;
|
||||||
state->savedata.command = savedata->command;
|
state->savedata.command = savedata->command;
|
||||||
|
@ -451,6 +488,7 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) {
|
||||||
|
|
||||||
void _flashErase(struct GBASavedata* savedata) {
|
void _flashErase(struct GBASavedata* savedata) {
|
||||||
GBALog(0, GBA_LOG_DEBUG, "Performing flash chip erase");
|
GBALog(0, GBA_LOG_DEBUG, "Performing flash chip erase");
|
||||||
|
savedata->dirty |= SAVEDATA_DIRT_NEW;
|
||||||
size_t size = SIZE_CART_FLASH512;
|
size_t size = SIZE_CART_FLASH512;
|
||||||
if (savedata->type == SAVEDATA_FLASH1M) {
|
if (savedata->type == SAVEDATA_FLASH1M) {
|
||||||
size = SIZE_CART_FLASH1M;
|
size = SIZE_CART_FLASH1M;
|
||||||
|
@ -460,6 +498,7 @@ void _flashErase(struct GBASavedata* savedata) {
|
||||||
|
|
||||||
void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart) {
|
void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart) {
|
||||||
GBALog(0, GBA_LOG_DEBUG, "Performing flash sector erase at 0x%04x", sectorStart);
|
GBALog(0, GBA_LOG_DEBUG, "Performing flash sector erase at 0x%04x", sectorStart);
|
||||||
|
savedata->dirty |= SAVEDATA_DIRT_NEW;
|
||||||
size_t size = 0x1000;
|
size_t size = 0x1000;
|
||||||
if (savedata->type == SAVEDATA_FLASH1M) {
|
if (savedata->type == SAVEDATA_FLASH1M) {
|
||||||
GBALog(0, GBA_LOG_DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart);
|
GBALog(0, GBA_LOG_DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart);
|
||||||
|
|
|
@ -51,6 +51,11 @@ enum FlashManufacturer {
|
||||||
FLASH_MFG_SANYO = 0x1362
|
FLASH_MFG_SANYO = 0x1362
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SavedataDirty {
|
||||||
|
SAVEDATA_DIRT_NEW = 1,
|
||||||
|
SAVEDATA_DIRT_SEEN = 2
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SAVEDATA_FLASH_BASE = 0x0E005555,
|
SAVEDATA_FLASH_BASE = 0x0E005555,
|
||||||
|
|
||||||
|
@ -77,6 +82,9 @@ struct GBASavedata {
|
||||||
unsigned settling;
|
unsigned settling;
|
||||||
int dust;
|
int dust;
|
||||||
|
|
||||||
|
enum SavedataDirty dirty;
|
||||||
|
uint32_t dirtAge;
|
||||||
|
|
||||||
enum FlashStateMachine flashState;
|
enum FlashStateMachine flashState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -98,6 +106,8 @@ void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8
|
||||||
uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata);
|
uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata);
|
||||||
void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize);
|
void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32_t writeSize);
|
||||||
|
|
||||||
|
void GBASavedataClean(struct GBASavedata* savedata, uint32_t frameCount);
|
||||||
|
|
||||||
struct GBASerializedState;
|
struct GBASerializedState;
|
||||||
void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData);
|
void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData);
|
||||||
void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state, bool includeData);
|
void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state, bool includeData);
|
||||||
|
|
|
@ -126,6 +126,31 @@ bool GBAConfigSave(const struct GBAConfig* config) {
|
||||||
return ConfigurationWrite(&config->configTable, path);
|
return ConfigurationWrite(&config->configTable, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GBAConfigMakePortable(const struct GBAConfig* config) {
|
||||||
|
struct VFile* portable;
|
||||||
|
#ifndef _WIN32
|
||||||
|
char out[PATH_MAX];
|
||||||
|
getcwd(out, PATH_MAX);
|
||||||
|
strncat(out, PATH_SEP "portable.ini", PATH_MAX - strlen(out));
|
||||||
|
portable = VFileOpen(out, O_WRONLY | O_CREAT);
|
||||||
|
#else
|
||||||
|
char out[MAX_PATH];
|
||||||
|
wchar_t wpath[MAX_PATH];
|
||||||
|
wchar_t wprojectName[MAX_PATH];
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, projectName, -1, wprojectName, MAX_PATH);
|
||||||
|
HMODULE hModule = GetModuleHandleW(NULL);
|
||||||
|
GetModuleFileNameW(hModule, wpath, MAX_PATH);
|
||||||
|
PathRemoveFileSpecW(wpath);
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, wpath, -1, out, MAX_PATH, 0, 0);
|
||||||
|
StringCchCatA(out, MAX_PATH, "\\portable.ini");
|
||||||
|
portable = VFileOpen(out, O_WRONLY | O_CREAT);
|
||||||
|
#endif
|
||||||
|
if (portable) {
|
||||||
|
portable->close(portable);
|
||||||
|
GBAConfigSave(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GBAConfigDirectory(char* out, size_t outLength) {
|
void GBAConfigDirectory(char* out, size_t outLength) {
|
||||||
struct VFile* portable;
|
struct VFile* portable;
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
|
|
@ -52,6 +52,7 @@ void GBAConfigDeinit(struct GBAConfig*);
|
||||||
bool GBAConfigLoad(struct GBAConfig*);
|
bool GBAConfigLoad(struct GBAConfig*);
|
||||||
bool GBAConfigSave(const struct GBAConfig*);
|
bool GBAConfigSave(const struct GBAConfig*);
|
||||||
|
|
||||||
|
void GBAConfigMakePortable(const struct GBAConfig*);
|
||||||
void GBAConfigDirectory(char* out, size_t outLength);
|
void GBAConfigDirectory(char* out, size_t outLength);
|
||||||
|
|
||||||
const char* GBAConfigGetValue(const struct GBAConfig*, const char* key);
|
const char* GBAConfigGetValue(const struct GBAConfig*, const char* key);
|
||||||
|
|
|
@ -258,3 +258,19 @@ void ConfigController::write() {
|
||||||
GBAConfigSave(&m_config);
|
GBAConfigSave(&m_config);
|
||||||
m_settings->sync();
|
m_settings->sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigController::makePortable() {
|
||||||
|
GBAConfigMakePortable(&m_config);
|
||||||
|
|
||||||
|
char path[PATH_MAX];
|
||||||
|
GBAConfigDirectory(path, sizeof(path));
|
||||||
|
QString fileName(path);
|
||||||
|
fileName.append(QDir::separator());
|
||||||
|
fileName.append("qt.ini");
|
||||||
|
QSettings* settings2 = new QSettings(fileName, QSettings::IniFormat, this);
|
||||||
|
for (const auto& key : m_settings->allKeys()) {
|
||||||
|
settings2->setValue(key, m_settings->value(key));
|
||||||
|
}
|
||||||
|
delete m_settings;
|
||||||
|
m_settings = settings2;
|
||||||
|
}
|
||||||
|
|
|
@ -89,6 +89,7 @@ public slots:
|
||||||
void setOption(const char* key, const QVariant& value);
|
void setOption(const char* key, const QVariant& value);
|
||||||
void setQtOption(const QString& key, const QVariant& value, const QString& group = QString());
|
void setQtOption(const QString& key, const QVariant& value, const QString& group = QString());
|
||||||
|
|
||||||
|
void makePortable();
|
||||||
void write();
|
void write();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -642,6 +642,10 @@ void Window::setupMenu(QMenuBar* menubar) {
|
||||||
|
|
||||||
fileMenu->addSeparator();
|
fileMenu->addSeparator();
|
||||||
|
|
||||||
|
addControlledAction(fileMenu, fileMenu->addAction(tr("Make portable"), m_config, SLOT(makePortable())), "makePortable");
|
||||||
|
|
||||||
|
fileMenu->addSeparator();
|
||||||
|
|
||||||
QAction* loadState = new QAction(tr("&Load state"), fileMenu);
|
QAction* loadState = new QAction(tr("&Load state"), fileMenu);
|
||||||
loadState->setShortcut(tr("F10"));
|
loadState->setShortcut(tr("F10"));
|
||||||
connect(loadState, &QAction::triggered, [this]() { this->openStateWindow(LoadSave::LOAD); });
|
connect(loadState, &QAction::triggered, [this]() { this->openStateWindow(LoadSave::LOAD); });
|
||||||
|
|
|
@ -39,6 +39,7 @@ struct VFile {
|
||||||
void (*unmap)(struct VFile* vf, void* memory, size_t size);
|
void (*unmap)(struct VFile* vf, void* memory, size_t size);
|
||||||
void (*truncate)(struct VFile* vf, size_t size);
|
void (*truncate)(struct VFile* vf, size_t size);
|
||||||
ssize_t (*size)(struct VFile* vf);
|
ssize_t (*size)(struct VFile* vf);
|
||||||
|
bool (*sync)(struct VFile* vf, const void* buffer, size_t size);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VDirEntry {
|
struct VDirEntry {
|
||||||
|
|
|
@ -30,6 +30,7 @@ static void* _vfdMap(struct VFile* vf, size_t size, int flags);
|
||||||
static void _vfdUnmap(struct VFile* vf, void* memory, size_t size);
|
static void _vfdUnmap(struct VFile* vf, void* memory, size_t size);
|
||||||
static void _vfdTruncate(struct VFile* vf, size_t size);
|
static void _vfdTruncate(struct VFile* vf, size_t size);
|
||||||
static ssize_t _vfdSize(struct VFile* vf);
|
static ssize_t _vfdSize(struct VFile* vf);
|
||||||
|
static bool _vfdSync(struct VFile* vf, const void* buffer, size_t size);
|
||||||
|
|
||||||
struct VFile* VFileOpenFD(const char* path, int flags) {
|
struct VFile* VFileOpenFD(const char* path, int flags) {
|
||||||
if (!path) {
|
if (!path) {
|
||||||
|
@ -66,6 +67,7 @@ struct VFile* VFileFromFD(int fd) {
|
||||||
vfd->d.unmap = _vfdUnmap;
|
vfd->d.unmap = _vfdUnmap;
|
||||||
vfd->d.truncate = _vfdTruncate;
|
vfd->d.truncate = _vfdTruncate;
|
||||||
vfd->d.size = _vfdSize;
|
vfd->d.size = _vfdSize;
|
||||||
|
vfd->d.sync = _vfdSync;
|
||||||
|
|
||||||
return &vfd->d;
|
return &vfd->d;
|
||||||
}
|
}
|
||||||
|
@ -166,3 +168,10 @@ static ssize_t _vfdSize(struct VFile* vf) {
|
||||||
}
|
}
|
||||||
return stat.st_size;
|
return stat.st_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool _vfdSync(struct VFile* vf, const void* buffer, size_t size) {
|
||||||
|
UNUSED(buffer);
|
||||||
|
UNUSED(size);
|
||||||
|
struct VFileFD* vfd = (struct VFileFD*) vf;
|
||||||
|
return fsync(vfd->fd) == 0;
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ static void* _vffMap(struct VFile* vf, size_t size, int flags);
|
||||||
static void _vffUnmap(struct VFile* vf, void* memory, size_t size);
|
static void _vffUnmap(struct VFile* vf, void* memory, size_t size);
|
||||||
static void _vffTruncate(struct VFile* vf, size_t size);
|
static void _vffTruncate(struct VFile* vf, size_t size);
|
||||||
static ssize_t _vffSize(struct VFile* vf);
|
static ssize_t _vffSize(struct VFile* vf);
|
||||||
|
static bool _vffSync(struct VFile* vf, const void* buffer, size_t size);
|
||||||
|
|
||||||
struct VFile* VFileFOpen(const char* path, const char* mode) {
|
struct VFile* VFileFOpen(const char* path, const char* mode) {
|
||||||
if (!path && !mode) {
|
if (!path && !mode) {
|
||||||
|
@ -57,6 +58,7 @@ struct VFile* VFileFromFILE(FILE* file) {
|
||||||
vff->d.unmap = _vffUnmap;
|
vff->d.unmap = _vffUnmap;
|
||||||
vff->d.truncate = _vffTruncate;
|
vff->d.truncate = _vffTruncate;
|
||||||
vff->d.size = _vffSize;
|
vff->d.size = _vffSize;
|
||||||
|
vff->d.sync = _vffSync;
|
||||||
|
|
||||||
return &vff->d;
|
return &vff->d;
|
||||||
}
|
}
|
||||||
|
@ -140,3 +142,14 @@ static ssize_t _vffSize(struct VFile* vf) {
|
||||||
fseek(vff->file, pos, SEEK_SET);
|
fseek(vff->file, pos, SEEK_SET);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool _vffSync(struct VFile* vf, const void* buffer, size_t size) {
|
||||||
|
struct VFileFILE* vff = (struct VFileFILE*) vf;
|
||||||
|
if (buffer && size) {
|
||||||
|
long pos = ftell(vff->file);
|
||||||
|
fseek(vff->file, 0, SEEK_SET);
|
||||||
|
fwrite(buffer, size, 1, vff->file);
|
||||||
|
fseek(vff->file, pos, SEEK_SET);
|
||||||
|
}
|
||||||
|
return fflush(vff->file) == 0;
|
||||||
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ static void* _vf7zMap(struct VFile* vf, size_t size, int flags);
|
||||||
static void _vf7zUnmap(struct VFile* vf, void* memory, size_t size);
|
static void _vf7zUnmap(struct VFile* vf, void* memory, size_t size);
|
||||||
static void _vf7zTruncate(struct VFile* vf, size_t size);
|
static void _vf7zTruncate(struct VFile* vf, size_t size);
|
||||||
static ssize_t _vf7zSize(struct VFile* vf);
|
static ssize_t _vf7zSize(struct VFile* vf);
|
||||||
|
static bool _vf7zSync(struct VFile* vf, const void* buffer, size_t size);
|
||||||
|
|
||||||
static bool _vd7zClose(struct VDir* vd);
|
static bool _vd7zClose(struct VDir* vd);
|
||||||
static void _vd7zRewind(struct VDir* vd);
|
static void _vd7zRewind(struct VDir* vd);
|
||||||
|
@ -291,6 +292,7 @@ struct VFile* _vd7zOpenFile(struct VDir* vd, const char* path, int mode) {
|
||||||
vf->d.unmap = _vf7zUnmap;
|
vf->d.unmap = _vf7zUnmap;
|
||||||
vf->d.truncate = _vf7zTruncate;
|
vf->d.truncate = _vf7zTruncate;
|
||||||
vf->d.size = _vf7zSize;
|
vf->d.size = _vf7zSize;
|
||||||
|
vf->d.sync = _vf7zSync;
|
||||||
|
|
||||||
return &vf->d;
|
return &vf->d;
|
||||||
}
|
}
|
||||||
|
@ -308,4 +310,11 @@ const char* _vde7zName(struct VDirEntry* vde) {
|
||||||
return vde7z->utf8;
|
return vde7z->utf8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _vf7zSync(struct VFile* vf, const void* memory, size_t size) {
|
||||||
|
UNUSED(vf);
|
||||||
|
UNUSED(memory);
|
||||||
|
UNUSED(size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,6 +43,7 @@ static void* _vfzMap(struct VFile* vf, size_t size, int flags);
|
||||||
static void _vfzUnmap(struct VFile* vf, void* memory, size_t size);
|
static void _vfzUnmap(struct VFile* vf, void* memory, size_t size);
|
||||||
static void _vfzTruncate(struct VFile* vf, size_t size);
|
static void _vfzTruncate(struct VFile* vf, size_t size);
|
||||||
static ssize_t _vfzSize(struct VFile* vf);
|
static ssize_t _vfzSize(struct VFile* vf);
|
||||||
|
static bool _vfzSync(struct VFile* vf, const void* buffer, size_t size);
|
||||||
|
|
||||||
static bool _vdzClose(struct VDir* vd);
|
static bool _vdzClose(struct VDir* vd);
|
||||||
static void _vdzRewind(struct VDir* vd);
|
static void _vdzRewind(struct VDir* vd);
|
||||||
|
@ -289,6 +290,7 @@ struct VFile* _vdzOpenFile(struct VDir* vd, const char* path, int mode) {
|
||||||
vfz->d.unmap = _vfzUnmap;
|
vfz->d.unmap = _vfzUnmap;
|
||||||
vfz->d.truncate = _vfzTruncate;
|
vfz->d.truncate = _vfzTruncate;
|
||||||
vfz->d.size = _vfzSize;
|
vfz->d.size = _vfzSize;
|
||||||
|
vfz->d.sync = _vfzSync;
|
||||||
|
|
||||||
return &vfz->d;
|
return &vfz->d;
|
||||||
}
|
}
|
||||||
|
@ -302,4 +304,11 @@ const char* _vdezName(struct VDirEntry* vde) {
|
||||||
return s.name;
|
return s.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _vfzSync(struct VFile* vf, const void* memory, size_t size) {
|
||||||
|
UNUSED(vf);
|
||||||
|
UNUSED(memory);
|
||||||
|
UNUSED(size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue