Ejemplo n.º 1
0
static Result task_data_op_check_running(data_op_data* data, u32 index, u32* srcHandle, u32* dstHandle) {
    Result res = 0;

    if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
        res = R_APP_CANCELLED;
    } else {
        bool suspended = svcWaitSynchronization(task_get_suspend_event(), 0) != 0;
        if(suspended) {
            if(data->op == DATAOP_COPY && srcHandle != NULL && dstHandle != NULL && data->suspendTransfer != NULL && R_SUCCEEDED(res)) {
                res = data->suspendTransfer(data->data, index, srcHandle, dstHandle);
            }

            if(data->suspend != NULL && R_SUCCEEDED(res)) {
                res = data->suspend(data->data, index);
            }
        }

        svcWaitSynchronization(task_get_pause_event(), U64_MAX);

        if(suspended) {
            if(data->restore != NULL && R_SUCCEEDED(res)) {
                res = data->restore(data->data, index);
            }

            if(data->op == DATAOP_COPY && srcHandle != NULL && dstHandle != NULL && data->restoreTransfer != NULL && R_SUCCEEDED(res)) {
                res = data->restoreTransfer(data->data, index, srcHandle, dstHandle);
            }
        }
    }

    return res;
}
Ejemplo n.º 2
0
static Result task_populate_pending_titles_from(populate_pending_titles_data* data, FS_MediaType mediaType) {
    Result res = 0;

    u32 pendingTitleCount = 0;
    if(R_SUCCEEDED(res = AM_GetPendingTitleCount(&pendingTitleCount, mediaType, AM_STATUS_MASK_INSTALLING | AM_STATUS_MASK_AWAITING_FINALIZATION))) {
        u64* pendingTitleIds = (u64*) calloc(pendingTitleCount, sizeof(u64));
        if(pendingTitleIds != NULL) {
            if(R_SUCCEEDED(res = AM_GetPendingTitleList(&pendingTitleCount, pendingTitleCount, mediaType, AM_STATUS_MASK_INSTALLING | AM_STATUS_MASK_AWAITING_FINALIZATION, pendingTitleIds))) {
                qsort(pendingTitleIds, pendingTitleCount, sizeof(u64), util_compare_u64);

                AM_PendingTitleEntry* pendingTitleInfos = (AM_PendingTitleEntry*) calloc(pendingTitleCount, sizeof(AM_PendingTitleEntry));
                if(pendingTitleInfos != NULL) {
                    if(R_SUCCEEDED(res = AM_GetPendingTitleInfo(pendingTitleCount, mediaType, pendingTitleIds, pendingTitleInfos))) {
                        for(u32 i = 0; i < pendingTitleCount && i < data->max; i++) {
                            if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
                                break;
                            }

                            pending_title_info* pendingTitleInfo = (pending_title_info*) calloc(1, sizeof(pending_title_info));
                            if(pendingTitleInfo != NULL) {
                                pendingTitleInfo->mediaType = mediaType;
                                pendingTitleInfo->titleId = pendingTitleIds[i];
                                pendingTitleInfo->version = pendingTitleInfos[i].version;

                                list_item* item = &data->items[*data->count];
                                snprintf(item->name, NAME_MAX, "%016llX", pendingTitleIds[i]);
                                if(mediaType == MEDIATYPE_NAND) {
                                    item->rgba = COLOR_NAND;
                                } else if(mediaType == MEDIATYPE_SD) {
                                    item->rgba = COLOR_SD;
                                }

                                item->data = pendingTitleInfo;

                                (*data->count)++;
                            }
                        }
                    }

                    free(pendingTitleInfos);
                } else {
                    res = MAKERESULT(RL_PERMANENT, RS_INVALIDSTATE, 254, RD_OUT_OF_MEMORY);
                }
            }

            free(pendingTitleIds);
        } else {
            res = MAKERESULT(RL_PERMANENT, RS_INVALIDSTATE, 254, RD_OUT_OF_MEMORY);
        }
    }

    return res;
}
Ejemplo n.º 3
0
static Result task_populate_ext_save_data_from(populate_ext_save_data_data* data, FS_MediaType mediaType) {
    Result res = 0;

    u32 extSaveDataCount = 0;
    u64* extSaveDataIds = (u64*) calloc(data->max, sizeof(u64));
    if(extSaveDataIds != NULL) {
        if(R_SUCCEEDED(res = FSUSER_EnumerateExtSaveData(&extSaveDataCount, data->max, mediaType, 8, mediaType == MEDIATYPE_NAND, (u8*) extSaveDataIds))) {
            qsort(extSaveDataIds, extSaveDataCount, sizeof(u64), util_compare_u64);

            SMDH smdh;
            for(u32 i = 0; i < extSaveDataCount && i < data->max; i++) {
                if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
                    break;
                }

                ext_save_data_info* extSaveDataInfo = (ext_save_data_info*) calloc(1, sizeof(ext_save_data_info));
                if(extSaveDataInfo != NULL) {
                    extSaveDataInfo->mediaType = mediaType;
                    extSaveDataInfo->extSaveDataId = extSaveDataIds[i];
                    extSaveDataInfo->shared = mediaType == MEDIATYPE_NAND;

                    list_item* item = &data->items[*data->count];

                    FS_ExtSaveDataInfo info = {.mediaType = mediaType, .saveId = extSaveDataIds[i]};
                    u32 smdhBytesRead = 0;
                    if(R_SUCCEEDED(FSUSER_ReadExtSaveDataIcon(&smdhBytesRead, info, sizeof(SMDH), (u8*) &smdh)) && smdhBytesRead == sizeof(SMDH)) {
                        u8 systemLanguage = CFG_LANGUAGE_EN;
                        CFGU_GetSystemLanguage(&systemLanguage);

                        utf16_to_utf8((uint8_t*) item->name, smdh.titles[systemLanguage].shortDescription, NAME_MAX);

                        extSaveDataInfo->hasSmdh = true;
                        utf16_to_utf8((uint8_t*) extSaveDataInfo->smdhInfo.shortDescription, smdh.titles[systemLanguage].shortDescription, sizeof(extSaveDataInfo->smdhInfo.shortDescription));
                        utf16_to_utf8((uint8_t*) extSaveDataInfo->smdhInfo.longDescription, smdh.titles[systemLanguage].longDescription, sizeof(extSaveDataInfo->smdhInfo.longDescription));
                        utf16_to_utf8((uint8_t*) extSaveDataInfo->smdhInfo.publisher, smdh.titles[systemLanguage].publisher, sizeof(extSaveDataInfo->smdhInfo.publisher));
                        extSaveDataInfo->smdhInfo.texture = screen_load_texture_tiled_auto(smdh.largeIcon, sizeof(smdh.largeIcon), 48, 48, GPU_RGB565, false);
                    } else {
                        extSaveDataInfo->hasSmdh = false;
                    }

                    bool empty = strlen(item->name) == 0;
                    if(!empty) {
                        empty = true;

                        char* curr = item->name;
                        while(*curr) {
                            if(*curr != ' ') {
                                empty = false;
                                break;
                            }

                            curr++;
                        }
                    }

                    if(empty) {
                        snprintf(item->name, NAME_MAX, "%016llX", extSaveDataIds[i]);
                    }

                    if(mediaType == MEDIATYPE_NAND) {
                        item->rgba = COLOR_NAND;
                    } else if(mediaType == MEDIATYPE_SD) {
                        item->rgba = COLOR_SD;
                    }

                    item->data = extSaveDataInfo;

                    (*data->count)++;
                }
            }
        }

        free(extSaveDataIds);
    } else {
Ejemplo n.º 4
0
static void task_populate_titledb_thread(void* arg) {
    populate_titledb_data* data = (populate_titledb_data*) arg;

    Result res = 0;

    linked_list titles;
    linked_list_init(&titles);

    json_t* root = NULL;
    if(R_SUCCEEDED(res = http_download_json("https://api.titledb.com/v1/entry?nested=true"
                                                    "&only=id&only=name&only=author&only=headline&only=category"
                                                    "&only=cia.id&only=cia.mtime&only=cia.version&only=cia.size&only=cia.titleid"
                                                    "&only=tdsx.id&only=tdsx.mtime&only=tdsx.version&only=tdsx.size&only=tdsx.smdh.id",
                                            &root, 1024 * 1024))) {
        if(json_is_array(root)) {
            for(u32 i = 0; i < json_array_size(root) && R_SUCCEEDED(res); i++) {
                svcWaitSynchronization(task_get_pause_event(), U64_MAX);
                if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
                    break;
                }

                json_t* entry = json_array_get(root, i);
                if(json_is_object(entry)) {
                    list_item* item = (list_item*) calloc(1, sizeof(list_item));
                    if(item != NULL) {
                        titledb_info* titledbInfo = (titledb_info*) calloc(1, sizeof(titledb_info));
                        if(titledbInfo != NULL) {
                            titledbInfo->id = (u32) json_object_get_integer(entry, "id", 0);
                            string_copy(titledbInfo->category, json_object_get_string(entry, "category", "Unknown"), sizeof(titledbInfo->category));
                            string_copy(titledbInfo->meta.shortDescription, json_object_get_string(entry, "name", ""), sizeof(titledbInfo->meta.shortDescription));
                            string_copy(titledbInfo->meta.publisher, json_object_get_string(entry, "author", ""), sizeof(titledbInfo->meta.publisher));

                            json_t* headline = json_object_get(entry, "headline");
                            if(json_is_string(headline)) {
                                const char* val = json_string_value(headline);

                                if(json_string_length(headline) > sizeof(titledbInfo->headline) - 1) {
                                    snprintf(titledbInfo->headline, sizeof(titledbInfo->headline), "%.508s...", val);
                                } else {
                                    string_copy(titledbInfo->headline, val, sizeof(titledbInfo->headline));
                                }
                            } else {
                                titledbInfo->headline[0] = '\0';
                            }

                            json_t* cias = json_object_get(entry, "cia");
                            if(json_is_array(cias)) {
                                for(u32 j = 0; j < json_array_size(cias); j++) {
                                    json_t* cia = json_array_get(cias, j);
                                    if(json_is_object(cia)) {
                                        const char* mtime = json_object_get_string(cia, "mtime", "Unknown");
                                        if(!titledbInfo->cia.exists || task_populate_titledb_compare_dates(mtime, titledbInfo->cia.mtime, sizeof(titledbInfo->cia.mtime)) >= 0) {
                                            titledbInfo->cia.exists = true;

                                            titledbInfo->cia.id = (u32) json_object_get_integer(cia, "id", 0);
                                            string_copy(titledbInfo->cia.mtime, mtime, sizeof(titledbInfo->cia.mtime));
                                            string_copy(titledbInfo->cia.version, json_object_get_string(cia, "version", "Unknown"), sizeof(titledbInfo->cia.version));
                                            titledbInfo->cia.size = (u32) json_object_get_integer(cia, "size", 0);
                                            titledbInfo->cia.titleId = strtoull(json_object_get_string(cia, "titleid", "0"), NULL, 16);
                                        }
                                    }
                                }
                            }

                            json_t* tdsxs = json_object_get(entry, "tdsx");
                            if(json_is_array(tdsxs)) {
                                for(u32 j = 0; j < json_array_size(tdsxs); j++) {
                                    json_t* tdsx = json_array_get(tdsxs, j);
                                    if(json_is_object(tdsx)) {
                                        const char* mtime = json_object_get_string(tdsx, "mtime", "Unknown");
                                        if(!titledbInfo->tdsx.exists || task_populate_titledb_compare_dates(mtime, titledbInfo->tdsx.mtime, sizeof(titledbInfo->tdsx.mtime)) >= 0) {
                                            titledbInfo->tdsx.exists = true;

                                            titledbInfo->tdsx.id = (u32) json_object_get_integer(tdsx, "id", 0);
                                            string_copy(titledbInfo->tdsx.mtime, mtime, sizeof(titledbInfo->tdsx.mtime));
                                            string_copy(titledbInfo->tdsx.version, json_object_get_string(tdsx, "version", "Unknown"), sizeof(titledbInfo->tdsx.version));
                                            titledbInfo->tdsx.size = (u32) json_object_get_integer(tdsx, "size", 0);

                                            json_t* smdh = json_object_get(tdsx, "smdh");
                                            if(json_is_object(smdh)) {
                                                titledbInfo->tdsx.smdh.exists = true;

                                                titledbInfo->tdsx.smdh.id = (u32) json_object_get_integer(smdh, "id", 0);
                                            }
                                        }
                                    }
                                }
                            }

                            char* latestTime = "Unknown";
                            if(titledbInfo->cia.exists && titledbInfo->tdsx.exists) {
                                if(task_populate_titledb_compare_dates(titledbInfo->cia.mtime, titledbInfo->tdsx.mtime, sizeof(titledbInfo->cia.mtime)) >= 0) {
                                    latestTime = titledbInfo->cia.mtime;
                                } else {
                                    latestTime = titledbInfo->tdsx.mtime;
                                }
                            } else if(titledbInfo->cia.exists) {
                                latestTime = titledbInfo->cia.mtime;
                            } else if(titledbInfo->tdsx.exists) {
                                latestTime = titledbInfo->tdsx.mtime;
                            }

                            string_copy(titledbInfo->mtime, latestTime, sizeof(titledbInfo->mtime));

                            if((titledbInfo->cia.exists || titledbInfo->tdsx.exists) && (data->filter == NULL || data->filter(data->userData, titledbInfo))) {
                                string_copy(item->name, titledbInfo->meta.shortDescription, LIST_ITEM_NAME_MAX);
                                item->data = titledbInfo;

                                task_populate_titledb_update_status(item);

                                linked_list_add_sorted(&titles, item, data->userData, data->compare);
                            } else {
                                free(titledbInfo);
                                free(item);
                            }
                        } else {
                            free(item);

                            res = R_APP_OUT_OF_MEMORY;
                        }
                    } else {
                        res = R_APP_OUT_OF_MEMORY;
                    }
                }
            }

            linked_list_iter iter;
            linked_list_iterate(&titles, &iter);

            while(linked_list_iter_has_next(&iter)) {
                list_item* item = linked_list_iter_next(&iter);

                if(R_SUCCEEDED(res)) {
                    linked_list_add(data->items, item);
                } else {
                    task_free_titledb(item);
                    linked_list_iter_remove(&iter);
                }
            }
        } else {
            res = R_APP_BAD_DATA;
        }

        json_decref(root);
    }

    data->itemsListed = true;

    if(R_SUCCEEDED(res)) {
        linked_list_iter iter;
        linked_list_iterate(&titles, &iter);

        while(linked_list_iter_has_next(&iter)) {
            svcWaitSynchronization(task_get_pause_event(), U64_MAX);

            Handle events[2] = {data->resumeEvent, data->cancelEvent};
            s32 index = 0;
            svcWaitSynchronizationN(&index, events, 2, false, U64_MAX);

            if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
                break;
            }

            list_item* item = (list_item*) linked_list_iter_next(&iter);
            titledb_info* titledbInfo = (titledb_info*) item->data;

            char url[128];
            if(titledbInfo->cia.exists) {
                snprintf(url, sizeof(url), "https://3ds.titledb.com/v1/cia/%lu/icon_l.bin", titledbInfo->cia.id);
            } else if(titledbInfo->tdsx.exists && titledbInfo->tdsx.smdh.exists) {
                snprintf(url, sizeof(url), "https://3ds.titledb.com/v1/smdh/%lu/icon_l.bin", titledbInfo->tdsx.smdh.id);
            } else {
                continue;
            }

            u8 icon[0x1200];
            u32 iconSize = 0;
            if(R_SUCCEEDED(http_download(url, &iconSize, &icon, sizeof(icon))) && iconSize == sizeof(icon)) {
                titledbInfo->meta.texture = screen_allocate_free_texture();
                screen_load_texture_tiled(titledbInfo->meta.texture, icon, sizeof(icon), 48, 48, GPU_RGB565, false);
            }
        }
    }

    linked_list_destroy(&titles);

    svcCloseHandle(data->resumeEvent);
    svcCloseHandle(data->cancelEvent);

    data->result = res;
    data->finished = true;
}
Ejemplo n.º 5
0
static void task_capture_cam_thread(void* arg) {
    capture_cam_data* data = (capture_cam_data*) arg;

    Handle events[EVENT_COUNT] = {0};
    events[EVENT_CANCEL] = data->cancelEvent;

    Result res = 0;

    u32 bufferSize = data->width * data->height * sizeof(u16);
    u16* buffer = (u16*) calloc(1, bufferSize);
    if(buffer != NULL) {
        if(R_SUCCEEDED(res = camInit())) {
            u32 cam = data->camera == CAMERA_OUTER ? SELECT_OUT1 : SELECT_IN1;

            if(R_SUCCEEDED(res = CAMU_SetSize(cam, SIZE_CTR_TOP_LCD, CONTEXT_A))
               && R_SUCCEEDED(res = CAMU_SetOutputFormat(cam, OUTPUT_RGB_565, CONTEXT_A))
               && R_SUCCEEDED(res = CAMU_SetFrameRate(cam, FRAME_RATE_30))
               && R_SUCCEEDED(res = CAMU_SetNoiseFilter(cam, true))
               && R_SUCCEEDED(res = CAMU_SetAutoExposure(cam, true))
               && R_SUCCEEDED(res = CAMU_SetAutoWhiteBalance(cam, true))
               && R_SUCCEEDED(res = CAMU_Activate(cam))) {
                u32 transferUnit = 0;

                if(R_SUCCEEDED(res = CAMU_GetBufferErrorInterruptEvent(&events[EVENT_BUFFER_ERROR], PORT_CAM1))
                   && R_SUCCEEDED(res = CAMU_SetTrimming(PORT_CAM1, true))
                   && R_SUCCEEDED(res = CAMU_SetTrimmingParamsCenter(PORT_CAM1, data->width, data->height, 400, 240))
                   && R_SUCCEEDED(res = CAMU_GetMaxBytes(&transferUnit, data->width, data->height))
                   && R_SUCCEEDED(res = CAMU_SetTransferBytes(PORT_CAM1, transferUnit, data->width, data->height))
                   && R_SUCCEEDED(res = CAMU_ClearBuffer(PORT_CAM1))
                   && R_SUCCEEDED(res = CAMU_SetReceiving(&events[EVENT_RECV], buffer, PORT_CAM1, bufferSize, (s16) transferUnit))
                   && R_SUCCEEDED(res = CAMU_StartCapture(PORT_CAM1))) {
                    bool cancelRequested = false;
                    while(!task_is_quit_all() && !cancelRequested && R_SUCCEEDED(res)) {
                        svcWaitSynchronization(task_get_pause_event(), U64_MAX);

                        s32 index = 0;
                        if(R_SUCCEEDED(res = svcWaitSynchronizationN(&index, events, EVENT_COUNT, false, U64_MAX))) {
                            switch(index) {
                                case EVENT_CANCEL:
                                    cancelRequested = true;
                                    break;
                                case EVENT_RECV:
                                    svcCloseHandle(events[EVENT_RECV]);
                                    events[EVENT_RECV] = 0;

                                    svcWaitSynchronization(data->mutex, U64_MAX);
                                    memcpy(data->buffer, buffer, bufferSize);
                                    GSPGPU_FlushDataCache(data->buffer, bufferSize);
                                    svcReleaseMutex(data->mutex);

                                    res = CAMU_SetReceiving(&events[EVENT_RECV], buffer, PORT_CAM1, bufferSize, (s16) transferUnit);
                                    break;
                                case EVENT_BUFFER_ERROR:
                                    svcCloseHandle(events[EVENT_RECV]);
                                    events[EVENT_RECV] = 0;

                                    if(R_SUCCEEDED(res = CAMU_ClearBuffer(PORT_CAM1))
                                       && R_SUCCEEDED(res = CAMU_SetReceiving(&events[EVENT_RECV], buffer, PORT_CAM1, bufferSize, (s16) transferUnit))) {
                                        res = CAMU_StartCapture(PORT_CAM1);
                                    }

                                    break;
                                default:
                                    break;
                            }
                        }
                    }

                    CAMU_StopCapture(PORT_CAM1);

                    bool busy = false;
                    while(R_SUCCEEDED(CAMU_IsBusy(&busy, PORT_CAM1)) && busy) {
                        svcSleepThread(1000000);
                    }

                    CAMU_ClearBuffer(PORT_CAM1);
                }

                CAMU_Activate(SELECT_NONE);
            }

            camExit();
        }

        free(buffer);
    } else {
        res = R_APP_OUT_OF_MEMORY;
    }

    for(int i = 0; i < EVENT_COUNT; i++) {
        if(events[i] != 0) {
            svcCloseHandle(events[i]);
            events[i] = 0;
        }
    }

    svcCloseHandle(data->mutex);

    data->result = res;
    data->finished = true;
}
Ejemplo n.º 6
0
static void task_populate_files_thread(void* arg) {
    populate_files_data* data = (populate_files_data*) arg;

    Result res = 0;

    list_item* baseItem = NULL;
    if(R_SUCCEEDED(res = task_create_file_item(&baseItem, data->archive, data->path))) {
        file_info* baseInfo = (file_info*) baseItem->data;
        if(baseInfo->attributes & FS_ATTRIBUTE_DIRECTORY) {
            strncpy(baseItem->name, "<current directory>", LIST_ITEM_NAME_MAX);
        } else {
            strncpy(baseItem->name, "<current file>", LIST_ITEM_NAME_MAX);
        }

        linked_list queue;
        linked_list_init(&queue);

        linked_list_add(&queue, baseItem);

        bool quit = false;
        while(!quit && R_SUCCEEDED(res) && linked_list_size(&queue) > 0) {
            u32 tail = linked_list_size(&queue) - 1;
            list_item* currItem = (list_item*) linked_list_get(&queue, tail);
            file_info* curr = (file_info*) currItem->data;
            linked_list_remove_at(&queue, tail);

            if(data->includeBase || currItem != baseItem) {
                linked_list_add(data->items, currItem);
            }

            if(curr->attributes & FS_ATTRIBUTE_DIRECTORY) {
                FS_Path* fsPath = util_make_path_utf8(curr->path);
                if(fsPath != NULL) {
                    Handle dirHandle = 0;
                    if(R_SUCCEEDED(res = FSUSER_OpenDirectory(&dirHandle, curr->archive, *fsPath))) {
                        u32 entryCount = 0;
                        FS_DirectoryEntry* entries = (FS_DirectoryEntry*) calloc(MAX_FILES, sizeof(FS_DirectoryEntry));
                        if(entries != NULL) {
                            if(R_SUCCEEDED(res = FSDIR_Read(dirHandle, &entryCount, MAX_FILES, entries)) && entryCount > 0) {
                                qsort(entries, entryCount, sizeof(FS_DirectoryEntry), task_populate_files_compare_directory_entries);

                                for(u32 i = 0; i < entryCount && R_SUCCEEDED(res); i++) {
                                    svcWaitSynchronization(task_get_pause_event(), U64_MAX);
                                    if(task_is_quit_all() || svcWaitSynchronization(data->cancelEvent, 0) == 0) {
                                        quit = true;
                                        break;
                                    }

                                    char name[FILE_NAME_MAX] = {'\0'};
                                    utf16_to_utf8((uint8_t*) name, entries[i].name, FILE_NAME_MAX - 1);

                                    if(data->filter == NULL || data->filter(data->filterData, name, entries[i].attributes)) {
                                        char path[FILE_PATH_MAX] = {'\0'};
                                        snprintf(path, FILE_PATH_MAX, "%s%s", curr->path, name);

                                        list_item* item = NULL;
                                        if(R_SUCCEEDED(res = task_create_file_item(&item, curr->archive, path))) {
                                            if(data->recursive && (((file_info*) item->data)->attributes & FS_ATTRIBUTE_DIRECTORY)) {
                                                linked_list_add(&queue, item);
                                            } else {
                                                linked_list_add(data->items, item);
                                            }
                                        }
                                    }
                                }
                            }

                            free(entries);
                        } else {
                            res = R_FBI_OUT_OF_MEMORY;
                        }

                        FSDIR_Close(dirHandle);
                    }

                    util_free_path_utf8(fsPath);
                } else {
                    res = R_FBI_OUT_OF_MEMORY;
                }
            }
        }

        if(!data->includeBase) {
            task_free_file(baseItem);
        }
    }

    svcCloseHandle(data->cancelEvent);

    data->result = res;
    data->finished = true;
}