// Copyright 2018 SciresM
#include <string.h>
#include "service_guard.h"
#include "runtime/hosversion.h"
#include "services/fsldr.h"

static Service g_fsldrSrv;

NX_GENERATE_SERVICE_GUARD(fsldr);

NX_INLINE Result _fsldrSetCurrentProcess(void);

Result _fsldrInitialize(void) {
    Result rc = smGetService(&g_fsldrSrv, "fsp-ldr");

    if (R_SUCCEEDED(rc)) {
        rc = serviceConvertToDomain(&g_fsldrSrv);
    }

    if (R_SUCCEEDED(rc) && hosversionAtLeast(4,0,0)) {
        rc = _fsldrSetCurrentProcess();
    }

    return rc;
}

void _fsldrCleanup(void) {
    serviceClose(&g_fsldrSrv);
}

Service* fsldrGetServiceSession(void) {
    return &g_fsldrSrv;
}

Result fsldrOpenCodeFileSystem(FsCodeInfo* out_code_info, u64 tid, const char *path, FsFileSystem* out) {
    memset(out_code_info, 0, sizeof(*out_code_info));

    char send_path[FS_MAX_PATH]={0};
    strncpy(send_path, path, FS_MAX_PATH-1);

    if (hosversionAtLeast(10,0,0)) {
        serviceAssumeDomain(&g_fsldrSrv);
        return serviceDispatchIn(&g_fsldrSrv, 0, tid,
            .buffer_attrs = {
                SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out,
                SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_In,
            },
            .buffers = {
                { out_code_info,  sizeof(*out_code_info) },
                { send_path,  FS_MAX_PATH },
            },
            .out_num_objects = 1,
            .out_objects = &out->s,
        );
    } else {
        serviceAssumeDomain(&g_fsldrSrv);
        return serviceDispatchIn(&g_fsldrSrv, 0, tid,
            .buffer_attrs = {
                SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_In,
            },
            .buffers = {
                { send_path,  FS_MAX_PATH },
            },
            .out_num_objects = 1,
            .out_objects = &out->s,
        );
    }

}

Result fsldrIsArchivedProgram(u64 pid, bool *out) {
    serviceAssumeDomain(&g_fsldrSrv);
    u8 tmp=0;
    Result rc = serviceDispatchInOut(&g_fsldrSrv, 1, pid, tmp);
    if (R_SUCCEEDED(rc) && out) *out = tmp & 1;
    return rc;
}

Result _fsldrSetCurrentProcess(void) {
    u64 pid_placeholder = 0;
    serviceAssumeDomain(&g_fsldrSrv);
    return serviceDispatchIn(&g_fsldrSrv, 2, pid_placeholder, .in_send_pid = true);
}