Skip to content

Commit

Permalink
add formats
Browse files Browse the repository at this point in the history
  • Loading branch information
bucanero committed Dec 11, 2024
1 parent 402f975 commit 1460a69
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 33 deletions.
3 changes: 3 additions & 0 deletions include/saves.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,9 @@ int vmc_export_psv(const char* save, const char* out_path);
int vmc_export_psu(const char* path, const char* output);
int vmc_import_psv(const char *input);
int vmc_import_psu(const char *input);
int vmc_import_xps(const char *input);
int vmc_import_max(const char *input);
int vmc_import_cbs(const char *input);

uint8_t* loadVmcIcon(const char *save, const char* icon);
int sjis2ascii(uint8_t* bData);
Expand Down
12 changes: 12 additions & 0 deletions source/exec_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,18 @@ static void import_save2vmc(const char* src, int type)
ret = vmc_import_psu(src);
break;

case FILE_TYPE_XPS:
ret = vmc_import_xps(src);
break;

case FILE_TYPE_MAX:
ret = vmc_import_max(src);
break;

case FILE_TYPE_CBS:
ret = vmc_import_cbs(src);
break;

default:
break;
}
Expand Down
167 changes: 167 additions & 0 deletions source/import_ps2.c
Original file line number Diff line number Diff line change
Expand Up @@ -842,3 +842,170 @@ int exportCBS(const char *save, const char* cbs_path, const char* title)

return 1;
}

int vmc_import_max(const char *save)
{
int r, fd;
maxEntry_t *entry;
maxHeader_t header;
char dstName[256];

if (!isMAXFile(save))
return 0;

FILE *f = fopen(save, "rb");
if(!f)
return 0;

fread(&header, 1, sizeof(maxHeader_t), f);

r = mcio_mcMkDir(header.dirName);
if (r < 0)
LOG("Error: can't create directory '%s'... (%d)", header.dirName, r);
else
mcio_mcClose(r);

// Get compressed file entries
uint8_t *compressed = malloc(header.compressedSize);

fseek(f, sizeof(maxHeader_t) - 4, SEEK_SET); // Seek to beginning of LZARI stream.
uint32_t ret = fread(compressed, 1, header.compressedSize, f);
fclose(f);
if(ret != header.compressedSize)
{
LOG("Compressed size: actual=%d, expected=%d\n", ret, header.compressedSize);
free(compressed);
return 0;
}

uint8_t *decompressed = malloc(header.decompressedSize);
ret = unlzari(compressed, header.compressedSize, decompressed, header.decompressedSize);
free(compressed);

// As with other save formats, decompressedSize isn't acccurate.
if(ret == 0)
{
LOG("Decompression failed.\n");
free(decompressed);
return 0;
}

LOG("Save contents:\n");
// Write the file's data
for(uint32_t offset = 0; header.numFiles > 0; header.numFiles--)
{
entry = (maxEntry_t*) &decompressed[offset];
offset += sizeof(maxEntry_t);
LOG(" %8d bytes : %s", entry->length, entry->name);
update_progress_bar(offset, header.decompressedSize, entry->name);

snprintf(dstName, sizeof(dstName), "%s/%s", header.dirName, entry->name);
fd = mcio_mcOpen(dstName, sceMcFileCreateFile | sceMcFileAttrWriteable | sceMcFileAttrFile);
if (fd < 0)
return 0;

r = mcio_mcWrite(fd, &decompressed[offset], entry->length);
mcio_mcClose(fd);

if (r != (int)entry->length)
return 0;

offset = roundUp(offset + entry->length + 8, 16) - 8;
}

free(decompressed);

return 1;
}

int vmc_import_cbs(const char *save)
{
int r, fd;
uint8_t *cbsData;
uint8_t *compressed;
uint8_t *decompressed;
cbsHeader_t header;
cbsEntry_t entryHeader;
uLong decompressedSize;
size_t cbsLen;
char dstName[256];
struct io_dirent mcEntry;

if(!isCBSFile(save))
return 0;

if(read_buffer(save, &cbsData, &cbsLen) < 0)
return 0;

memcpy(&header, cbsData, sizeof(cbsHeader_t));
r = mcio_mcMkDir(header.name);
if (r < 0)
LOG("Error: can't create directory '%s'... (%d)", header.name, r);
else
mcio_mcClose(r);

// Get data for file entries
compressed = cbsData + sizeof(cbsHeader_t);
// Some tools create .CBS saves with an incorrect compressed size in the header.
// It can't be trusted!
cbsCrypt(compressed, cbsLen - sizeof(cbsHeader_t));
decompressedSize = header.decompressedSize;
decompressed = malloc(decompressedSize);
r = uncompress(decompressed, &decompressedSize, compressed, cbsLen - sizeof(cbsHeader_t));
free(cbsData);

if(r != Z_OK)
{
// Compression failed.
LOG("Decompression failed! (Z_ERR = %d)", r);
free(decompressed);
return 0;
}

LOG("Save contents:\n");

// Write the file's data
for(uint32_t offset = 0; offset < (decompressedSize - sizeof(cbsEntry_t)); offset += entryHeader.length)
{
/* Entry header can't be read directly because it might not be 32-bit aligned.
GCC will likely emit an lw instruction for reading the 32-bit variables in the
struct which will halt the processor if it tries to load from an address
that's misaligned. */
memcpy(&entryHeader, &decompressed[offset], sizeof(cbsEntry_t));
offset += sizeof(cbsEntry_t);
LOG(" %8d bytes : %s", entryHeader.length, entryHeader.name);
update_progress_bar(offset + sizeof(cbsEntry_t), decompressedSize, entryHeader.name);

snprintf(dstName, sizeof(dstName), "%s/%s", header.name, entryHeader.name);
fd = mcio_mcOpen(dstName, sceMcFileCreateFile | sceMcFileAttrWriteable | sceMcFileAttrFile);
if (fd < 0)
{
free(decompressed);
return 0;
}

r = mcio_mcWrite(fd, &decompressed[offset], entryHeader.length);
mcio_mcClose(fd);

if (r != (int)entryHeader.length)
{
free(decompressed);
return 0;
}

mcio_mcStat(dstName, &mcEntry);
memcpy(&mcEntry.stat.ctime, &entryHeader.created, sizeof(struct sceMcStDateTime));
memcpy(&mcEntry.stat.mtime, &entryHeader.modified, sizeof(struct sceMcStDateTime));
mcEntry.stat.mode = entryHeader.mode;
mcio_mcSetStat(dstName, &mcEntry);
}
free(decompressed);

mcio_mcStat(header.name, &mcEntry);
memcpy(&mcEntry.stat.ctime, &header.created, sizeof(struct sceMcStDateTime));
memcpy(&mcEntry.stat.mtime, &header.modified, sizeof(struct sceMcStDateTime));
mcEntry.stat.mode = header.mode;
mcio_mcSetStat(header.name, &mcEntry);

return 1;
}
125 changes: 92 additions & 33 deletions source/psv_resign.c
Original file line number Diff line number Diff line change
Expand Up @@ -483,43 +483,14 @@ int vmc_import_psv(const char *input)
struct io_dirent entry;
ps2_MainDirInfo_t *ps2md;
ps2_FileInfo_t *ps2fi;

FILE *fh = fopen(input, "rb");
if (fh == NULL)
return 0;

fread(filepath, 1, 4, fh);
if (memcmp(PSV_MAGIC, filepath, 4) != 0) {
LOG("Not a .PSV file");
fclose(fh);
return 0;
}

fseek(fh, 0, SEEK_END);
int filesize = ftell(fh);
if (!filesize) {
fclose(fh);
return 0;
}
fseek(fh, 0, SEEK_SET);
uint8_t *p;
size_t filesize;

LOG("Reading file: '%s'...", input);

uint8_t *p = malloc(filesize);
if (p == NULL) {
if (read_buffer(input, &p, &filesize) < 0)
return 0;
}

r = fread(p, 1, filesize, fh);
if (r != filesize) {
fclose(fh);
free(p);
return 0;
}

fclose(fh);

if (p[0x3C] != 0x02) {
if (filesize < 0x200 || memcmp(PSV_MAGIC, p, 4) != 0 || p[0x3C] != 0x02) {
LOG("Not a PS2 save file");
free(p);
return 0;
Expand Down Expand Up @@ -663,6 +634,94 @@ int vmc_import_psu(const char *input)
return 1;
}

int vmc_import_xps(const char *save)
{
int r, fd;
FILE *xpsFile;
char path[256];
uint8_t *data;
xpsEntry_t entry;
struct io_dirent dirEntry, mcEntry;

xpsFile = fopen(save, "rb");
if(!xpsFile)
return 0;

fread(path, 1, 0x20, xpsFile);
if (memcmp(&path[4], "SharkPortSave\0\0\0", 16) != 0)
{
fclose(xpsFile);
return 0;
}

// Skip the variable size header
fread(&r, 1, sizeof(int), xpsFile);
fseek(xpsFile, r, SEEK_CUR);
fread(&r, 1, sizeof(int), xpsFile);
fseek(xpsFile, r, SEEK_CUR);
fread(&r, 1, sizeof(int), xpsFile);
fread(&r, 1, sizeof(int), xpsFile);

// Read main directory entry
fread(&entry, 1, sizeof(xpsEntry_t), xpsFile);

r = mcio_mcMkDir(entry.name);
if (r < 0)
LOG("Error: can't create directory '%s'... (%d)", entry.name, r);
else
mcio_mcClose(r);

// Root dir
memset(&mcEntry, 0, sizeof(struct io_dirent));
memset(&dirEntry, 0, sizeof(struct io_dirent));
memcpy(&dirEntry.stat.ctime, &entry.created, sizeof(struct sceMcStDateTime));
memcpy(&dirEntry.stat.mtime, &entry.modified, sizeof(struct sceMcStDateTime));
memcpy(dirEntry.name, entry.name, sizeof(entry.name));
dirEntry.stat.mode = ES16(entry.mode);
dirEntry.stat.size = entry.length;

LOG("Save contents:");
// Copy each file entry
for(int numFiles = entry.length - 2; numFiles > 0; numFiles--)
{
fread(&entry, 1, sizeof(xpsEntry_t), xpsFile);
LOG(" %8d bytes : %s", entry.length, entry.name);
update_progress_bar(dirEntry.stat.size - numFiles, dirEntry.stat.size, entry.name);

snprintf(path, sizeof(path), "%s/%s", dirEntry.name, entry.name);
fd = mcio_mcOpen(path, sceMcFileCreateFile | sceMcFileAttrWriteable | sceMcFileAttrFile);
if (fd < 0)
{
fclose(xpsFile);
return 0;
}

data = malloc(entry.length);
fread(data, 1, entry.length, xpsFile);

r = mcio_mcWrite(fd, data, entry.length);
mcio_mcClose(fd);
free(data);

if (r != (int)entry.length)
{
fclose(xpsFile);
return 0;
}

mcio_mcStat(path, &mcEntry);
memcpy(&mcEntry.stat.ctime, &entry.created, sizeof(struct sceMcStDateTime));
memcpy(&mcEntry.stat.mtime, &entry.modified, sizeof(struct sceMcStDateTime));
mcEntry.stat.mode = ES16(entry.mode);
mcio_mcSetStat(path, &mcEntry);
}

fclose(xpsFile);
mcio_mcSetStat(dirEntry.name, &dirEntry);

return 1;
}

int vmc_export_psv(const char* save, const char* out_path)
{
FILE *psvFile;
Expand Down

0 comments on commit 1460a69

Please sign in to comment.