mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 21:27:52 -04:00
e630b50690
* temp * split up kprint, other than format * start kmachine * split kmachine * split kscheme * split klink * split klisten * split remaining * jak2 ckernel gets to nokernel loop
347 lines
7.4 KiB
C++
347 lines
7.4 KiB
C++
#include "fileio.h"
|
|
|
|
#include <cstring>
|
|
|
|
#include "common/common_types.h"
|
|
#include "common/util/Assert.h"
|
|
|
|
#include "game/kernel/common/Ptr.h"
|
|
#include "game/kernel/common/kmalloc.h"
|
|
#include "game/kernel/common/kprint.h"
|
|
#include "game/sce/sif_ee.h"
|
|
|
|
using namespace ee;
|
|
|
|
// buffer for file paths. This might be static char buffer[512]. Maybe 633 is the line number?
|
|
char buffer_633[512];
|
|
|
|
void fileio_init_globals() {
|
|
memset(buffer_633, 0, 512);
|
|
}
|
|
|
|
/*!
|
|
* Return pointer to null terminator of string.
|
|
* const is for losers.
|
|
* DONE, EXACT
|
|
*/
|
|
char* strend(char* str) {
|
|
while (*str)
|
|
str++;
|
|
return str;
|
|
}
|
|
|
|
/*!
|
|
* An implementation of Huffman decoding.
|
|
* In this limited decoder, your data must have lower two bits equal to zero.
|
|
* @param loc_ptr pointer to pointer to data to read (will be modified to point to next word)
|
|
* @return decoded word
|
|
* UNUSED, EXACT
|
|
*/
|
|
u32 ReadHufWord(u8** loc_ptr) {
|
|
u8* loc = *loc_ptr; // pointer to data to read
|
|
u32 value = *(u32*)loc; // read word
|
|
u8* next_loc = loc + 1; // next data to read
|
|
u32 length = value & 3; // length of word is stored in lower two bits.
|
|
switch (length) {
|
|
case 0: // already all set.
|
|
break;
|
|
|
|
case 1:
|
|
value = (value & 0xfc) | (loc[1] << 8);
|
|
next_loc = loc + 2;
|
|
break;
|
|
|
|
case 2:
|
|
value = (value & 0xfc) | (loc[1] << 8) | (loc[2] << 0x10);
|
|
next_loc = loc + 3;
|
|
break;
|
|
|
|
case 3:
|
|
value = (value & 0xfc) | (loc[1] << 8) | (loc[2] << 0x10) | (loc[3] << 0x18);
|
|
next_loc = loc + 4;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(false);
|
|
}
|
|
|
|
// update location pointer
|
|
*loc_ptr = next_loc;
|
|
return value;
|
|
}
|
|
|
|
/*!
|
|
* Copy a string from src to dst. The null terminator is copied too.
|
|
* This is identical to normal strcpy.
|
|
* DONE, EXACT
|
|
*/
|
|
void kstrcpy(char* dst, const char* src) {
|
|
char* dst_ptr = dst;
|
|
const char* src_ptr = src;
|
|
|
|
while (*src_ptr != 0) {
|
|
*dst_ptr = *src_ptr;
|
|
src_ptr++;
|
|
dst_ptr++;
|
|
}
|
|
*dst_ptr = 0;
|
|
}
|
|
|
|
/*!
|
|
* Copy a string from src to dst, making all letters upper case.
|
|
* The null terminator is copied too.
|
|
* DONE, EXACT
|
|
*/
|
|
void kstrcpyup(char* dst, const char* src) {
|
|
while (*src) {
|
|
char c = *src;
|
|
if (c >= 'a' && c <= 'z') { // A-Z,a-z
|
|
c -= 0x20;
|
|
}
|
|
*dst = c;
|
|
dst++;
|
|
src++;
|
|
}
|
|
*dst = 0;
|
|
}
|
|
|
|
/*!
|
|
* Concatenate two strings. Src is added to dest.
|
|
* The new string is null terminated. No bounds checking is done.
|
|
* DONE, EXACT
|
|
*/
|
|
void kstrcat(char* dest, const char* src) {
|
|
// seek to end of first string
|
|
while (*dest) {
|
|
dest++;
|
|
}
|
|
// copy second string
|
|
while (*src) {
|
|
*dest = *src;
|
|
src++;
|
|
dest++;
|
|
}
|
|
// null terminate
|
|
*dest = 0;
|
|
}
|
|
|
|
/*!
|
|
* Concatenate two strings with a maximum length for the resulting string
|
|
* The maximum length should be larger than the length of the original string.
|
|
* The resulting string will be truncated when it reaches the given length.
|
|
* The null terminator is added, but doesn't count toward the length.
|
|
* DONE, EXACT
|
|
*/
|
|
void kstrncat(char* dest, const char* src, s32 count) {
|
|
// seek to null terminator of first string, count length
|
|
s32 i = 0;
|
|
while (*dest) {
|
|
dest++;
|
|
i++;
|
|
}
|
|
|
|
// append second string, not exceeding length
|
|
while (*src && (i < count)) {
|
|
*dest = *src;
|
|
src++;
|
|
dest++;
|
|
i++;
|
|
}
|
|
|
|
// null terminate
|
|
*dest = 0;
|
|
}
|
|
|
|
/*!
|
|
* Insert the pad char at the beginning of a string, count times.
|
|
* DONE, EXACT
|
|
*/
|
|
char* kstrinsert(char* str, char pad, s32 count) {
|
|
// shift string+null terminator to the right.
|
|
s32 len = strlen(str);
|
|
while (len > -1) {
|
|
str[len + count] = str[len];
|
|
len--;
|
|
}
|
|
|
|
// pad
|
|
len = 0;
|
|
while (len < count) {
|
|
str[len++] = pad;
|
|
}
|
|
return str;
|
|
}
|
|
|
|
/*!
|
|
* Get filename from path.
|
|
* This function is renamed to basename_goal so it doesn't conflict with "basename" that is
|
|
* already defined on my computer.
|
|
* For example:
|
|
* a/b/c.e will return c.e
|
|
* a\b\c.e will return c.e
|
|
* asdf.asdf will return asdf.asdf
|
|
* DONE, EXACT
|
|
*/
|
|
char* basename_goal(char* s) {
|
|
char* input = s;
|
|
char* pt = s;
|
|
|
|
// seek to end
|
|
for (;;) {
|
|
char c = *pt;
|
|
if (c) {
|
|
pt++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Original code, has memory bug.
|
|
// back up...
|
|
for (;;) {
|
|
if (pt < input) {
|
|
return input;
|
|
}
|
|
pt--;
|
|
char c = *pt;
|
|
// until we hit a slash.
|
|
if (c == '\\' || c == '/') { // slashes
|
|
return pt + 1; // and return one past
|
|
}
|
|
}
|
|
*/
|
|
|
|
// back up...
|
|
for (;;) {
|
|
if (pt <= input) {
|
|
return input;
|
|
}
|
|
pt--;
|
|
char c = *pt;
|
|
// until we hit a slash.
|
|
if (c == '\\' || c == '/') { // slashes
|
|
return pt + 1; // and return one past
|
|
}
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Does the file exist? No. It doesn't.
|
|
* @return 0 always, even if the file exists.
|
|
* DONE, EXACT, UNUSED
|
|
*/
|
|
u32 FileExists(const char* name) {
|
|
(void)name;
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
* Does nothing. Likely is supposed to delete a file.
|
|
* @param name
|
|
* DONE, EXACT, UNUSED
|
|
*/
|
|
void FileDelete(const char* name) {
|
|
(void)name;
|
|
}
|
|
|
|
/*!
|
|
* Does nothing. Likely is supposed to copy a file.
|
|
* @param a
|
|
* @param b
|
|
* DONE, EXACT, UNUSED
|
|
*/
|
|
void FileCopy(const char* a, const char* b) {
|
|
(void)a;
|
|
(void)b;
|
|
}
|
|
|
|
/*!
|
|
* Determine the file length in bytes.
|
|
* DONE, EXACT
|
|
*/
|
|
s32 FileLength(char* filename) {
|
|
s32 fd = sceOpen(filename, SCE_RDONLY);
|
|
if (fd < 0) {
|
|
MsgErr("dkernel: file length !open \'%s\' (%d)\n", filename, fd);
|
|
sceClose(fd);
|
|
return 0xfffffffb;
|
|
} else {
|
|
s32 rv = sceLseek(fd, 0, SCE_SEEK_END);
|
|
sceClose(fd);
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Load a file into memory
|
|
* @param name : file name
|
|
* @param heap : heap to allocate into, if memory is null
|
|
* @param memory : memory to load into. If null, allocates on the given kheap (with 64 extra bytes)
|
|
* @param malloc_flags : flags for the kmalloc
|
|
* @param size_out : file size is written here, if it's not null
|
|
* @return pointer to file data
|
|
* DONE, EXACT
|
|
*/
|
|
Ptr<u8> FileLoad(char* name, Ptr<kheapinfo> heap, Ptr<u8> memory, u32 malloc_flags, s32* size_out) {
|
|
s32 fd = sceOpen(name, SCE_RDONLY);
|
|
if (fd < 0) {
|
|
MsgErr("dkernel: file read !open \'%s\' (%d)\n", name, fd);
|
|
sceClose(fd);
|
|
return Ptr<u8>(0xfffffffb);
|
|
}
|
|
|
|
// determine size
|
|
s32 initial_pos = sceLseek(fd, 0, SCE_SEEK_CUR);
|
|
s32 size = sceLseek(fd, 0, SCE_SEEK_END);
|
|
sceLseek(fd, initial_pos, SCE_SEEK_SET);
|
|
|
|
if (size > 0) {
|
|
if (memory.offset == 0) {
|
|
memory = kmalloc(heap, size + 0x40, malloc_flags, name);
|
|
}
|
|
if (memory.offset == 0) {
|
|
MsgErr("dkernel: mem full for file read: '%s' (%d bytes)\n", name, size);
|
|
return Ptr<u8>(0xfffffffd);
|
|
}
|
|
|
|
s32 read_amount = sceRead(fd, memory.c(), size);
|
|
if (read_amount == size) {
|
|
sceClose(fd);
|
|
if (size_out)
|
|
*size_out = size;
|
|
return memory;
|
|
} else {
|
|
MsgErr("dkernel: can't read full file (%d of %d): '%s'\n", read_amount, size, name);
|
|
sceClose(fd);
|
|
return Ptr<u8>(0xfffffffb);
|
|
}
|
|
} else {
|
|
return Ptr<u8>(0);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Write a file.
|
|
* DONE, EXACT
|
|
*/
|
|
s32 FileSave(char* name, u8* data, s32 size) {
|
|
s32 fd = sceOpen(name, SCE_WRONLY | SCE_TRUNC | SCE_CREAT);
|
|
if (fd < 0) {
|
|
MsgErr("dkernel: file write !open '%s'\n", name);
|
|
sceClose(fd);
|
|
return 0xfffffffa;
|
|
}
|
|
|
|
if (size != 0) {
|
|
s32 written = sceWrite(fd, data, size);
|
|
if (written != size) {
|
|
MsgErr("dkernel: can't write full file '%s'\n", name);
|
|
sceClose(fd);
|
|
return 0xfffffffa;
|
|
}
|
|
}
|
|
|
|
sceClose(fd);
|
|
return 0;
|
|
}
|