mirror of
https://github.com/joel16/VitaShell.git
synced 2024-11-26 21:30:45 +00:00
Merge pull request #310 from VitaSmith/VitaSmith
Add DLC refresh + restore license from Sqlite DB
This commit is contained in:
commit
048b822e9f
@ -156,6 +156,7 @@ target_link_libraries(VitaShell
|
||||
SceNpDrm_stub
|
||||
SceRegistryMgr_stub
|
||||
SceShellSvc_stub
|
||||
SceSqlite_stub
|
||||
SceSsl_stub
|
||||
SceSysmodule_stub
|
||||
ScePgf_stub
|
||||
|
BIN
db/licenses.db
Normal file
BIN
db/licenses.db
Normal file
Binary file not shown.
18
db/readme.txt
Normal file
18
db/readme.txt
Normal file
@ -0,0 +1,18 @@
|
||||
This directory contains an example of the type of database one can use to
|
||||
store personal licenses, so that VitaShell can automatically restore them
|
||||
when reinstalling content from PKG data.
|
||||
|
||||
As opposed to this sample, which does not contain any usable data, your
|
||||
CONTENT_ID columns should contain valid content id for the PS Vita app,
|
||||
game or DLC you own, and the RIF columns should contain a 512-byte .rif
|
||||
blob that includes your AID, a CONTENT_ID that matches the one from the
|
||||
first column as well as your personal license data.
|
||||
|
||||
To edit this database manually, you can use the Windows/Linux/MacOS
|
||||
compatible DB Browser for SQLite (http://sqlitebrowser.org/) to drag and
|
||||
drop your .rif files and edit the relevant CONTENT_ID fields.
|
||||
|
||||
Or you can wait until someone writes an application that automates that
|
||||
process or you... ;)
|
||||
|
||||
This database should be copied to ux0:license/
|
11
init.c
11
init.c
@ -252,6 +252,15 @@ static void finishVita2dLib() {
|
||||
font = NULL;
|
||||
}
|
||||
|
||||
static int initSQLite() {
|
||||
SceSqliteMallocMethods mf = {
|
||||
(void* (*) (int)) malloc,
|
||||
(void* (*) (void*, int)) realloc,
|
||||
free
|
||||
};
|
||||
return sceSqliteConfigMallocMethods(&mf);
|
||||
}
|
||||
|
||||
static void initNet() {
|
||||
static char memory[16 * 1024];
|
||||
|
||||
@ -356,6 +365,7 @@ void initVitaShell() {
|
||||
sceSysmoduleLoadModule(SCE_SYSMODULE_PHOTO_EXPORT);
|
||||
sceSysmoduleLoadModule(SCE_SYSMODULE_NET);
|
||||
sceSysmoduleLoadModule(SCE_SYSMODULE_HTTPS);
|
||||
sceSysmoduleLoadModule(SCE_SYSMODULE_SQLITE);
|
||||
|
||||
// Init
|
||||
vitaAudioInit(0x40);
|
||||
@ -363,6 +373,7 @@ void initVitaShell() {
|
||||
initSceAppUtil();
|
||||
initNet();
|
||||
initQR();
|
||||
initSQLite();
|
||||
|
||||
// Init power tick thread
|
||||
initPowerTickThread();
|
||||
|
1
main.h
1
main.h
@ -38,6 +38,7 @@
|
||||
#include <psp2/rtc.h>
|
||||
#include <psp2/registrymgr.h>
|
||||
#include <psp2/shellutil.h>
|
||||
#include <psp2/sqlite.h>
|
||||
#include <psp2/sysmodule.h>
|
||||
#include <psp2/system_param.h>
|
||||
#include <psp2/touch.h>
|
||||
|
366
refresh.c
366
refresh.c
@ -1,6 +1,7 @@
|
||||
/*
|
||||
VitaShell
|
||||
Copyright (C) 2015-2017, TheFloW
|
||||
Copyright (C) 2017, VitaSmith
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -26,41 +27,85 @@
|
||||
#include "message_dialog.h"
|
||||
#include "language.h"
|
||||
#include "utils.h"
|
||||
#include "sqlite3.h"
|
||||
|
||||
int isCustomHomebrew() {
|
||||
uint32_t work[512/4];
|
||||
|
||||
if (ReadFile("ux0:temp/game/sce_sys/package/work.bin", work, sizeof(work)) != sizeof(work))
|
||||
// Note: The promotion process is *VERY* sensitive to the directories used below
|
||||
// Don't change them unless you know what you are doing!
|
||||
#define APP_TEMP "ux0:temp/app"
|
||||
#define DLC_TEMP "ux0:temp/addcont"
|
||||
#define DB_PATH "ux0:/license/licenses.db"
|
||||
|
||||
#define RIF_SIZE 512
|
||||
#define MAX_QUERY_LENGTH 128
|
||||
#define MAX_DLC_PER_TITLE 1024
|
||||
|
||||
int isCustomHomebrew(const char* path)
|
||||
{
|
||||
uint32_t work[RIF_SIZE/4];
|
||||
|
||||
if (ReadFile(path, work, sizeof(work)) != sizeof(work))
|
||||
return 0;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < sizeof(work) / sizeof(uint32_t); i++)
|
||||
|
||||
for (int i = 0; i < sizeof(work) / sizeof(uint32_t); i++)
|
||||
if (work[i] != 0)
|
||||
return 0;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int refreshApp(const char *name) {
|
||||
char app_path[MAX_PATH_LENGTH], param_path[MAX_PATH_LENGTH], license_path[MAX_PATH_LENGTH];
|
||||
int res;
|
||||
// Query a rif from an sqlite database. Returned data must be freed by the caller.
|
||||
uint8_t* query_rif(const char* db_path, const char* content_id)
|
||||
{
|
||||
int rc, rif_size = 0;
|
||||
sqlite3 *db = NULL;
|
||||
sqlite3_stmt *stmt;
|
||||
char query[MAX_QUERY_LENGTH];
|
||||
uint8_t *rif = NULL;
|
||||
|
||||
// Path
|
||||
snprintf(app_path, MAX_PATH_LENGTH, "ux0:app/%s", name);
|
||||
snprintf(param_path, MAX_PATH_LENGTH, "ux0:app/%s/sce_sys/param.sfo", name);
|
||||
rc = sqlite3_open_v2(db_path, &db, SQLITE_OPEN_READONLY, NULL);
|
||||
if (rc != SQLITE_OK)
|
||||
return NULL;
|
||||
|
||||
snprintf(query, sizeof(query), "SELECT RIF FROM Licenses WHERE CONTENT_ID = '%s';", content_id);
|
||||
|
||||
rc = sqlite3_prepare_v2(db, query, -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK)
|
||||
return NULL;
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc == SQLITE_ROW)
|
||||
rif_size = sqlite3_column_bytes(stmt, 0);
|
||||
if (rif_size != RIF_SIZE)
|
||||
return NULL;
|
||||
|
||||
rif = malloc(rif_size);
|
||||
if (rif != NULL)
|
||||
memcpy(rif, sqlite3_column_blob(stmt, 0), rif_size);
|
||||
|
||||
sqlite3_close(db);
|
||||
return rif;
|
||||
}
|
||||
|
||||
int refreshNeeded(const char *app_path)
|
||||
{
|
||||
char sfo_path[MAX_PATH_LENGTH];
|
||||
// TODO: Check app vs dlc from SFO
|
||||
int res, is_app = (app_path[6] == 'p');
|
||||
|
||||
// Read param.sfo
|
||||
snprintf(sfo_path, MAX_PATH_LENGTH, "%s/sce_sys/param.sfo", app_path);
|
||||
void *sfo_buffer = NULL;
|
||||
int sfo_size = allocateReadFile(param_path, &sfo_buffer);
|
||||
int sfo_size = allocateReadFile(sfo_path, &sfo_buffer);
|
||||
if (sfo_size < 0) {
|
||||
if (sfo_buffer)
|
||||
free(sfo_buffer);
|
||||
return sfo_size;
|
||||
}
|
||||
|
||||
// Get titleid
|
||||
char titleid[12];
|
||||
// Get title and content ids
|
||||
char titleid[12], contentid[50];
|
||||
getSfoString(sfo_buffer, "TITLE_ID", titleid, sizeof(titleid));
|
||||
getSfoString(sfo_buffer, "CONTENT_ID", contentid, sizeof(contentid));
|
||||
|
||||
// Free sfo buffer
|
||||
free(sfo_buffer);
|
||||
@ -74,49 +119,193 @@ int refreshApp(const char *name) {
|
||||
|
||||
// Check if bounded rif file exits
|
||||
_sceNpDrmGetRifName(rif_name, 0, aid);
|
||||
snprintf(license_path, MAX_PATH_LENGTH, "ux0:license/app/%s/%s", titleid, rif_name);
|
||||
if (checkFileExist(license_path))
|
||||
if (is_app)
|
||||
snprintf(sfo_path, MAX_PATH_LENGTH, "ux0:license/app/%s/%s", titleid, rif_name);
|
||||
else
|
||||
snprintf(sfo_path, MAX_PATH_LENGTH, "ux0:license/addcont/%s/%s/%s", titleid, &contentid[20], rif_name);
|
||||
if (checkFileExist(sfo_path))
|
||||
return 0;
|
||||
|
||||
// Check if fixed rif file exits
|
||||
_sceNpDrmGetFixedRifName(rif_name, 0, 0);
|
||||
snprintf(license_path, MAX_PATH_LENGTH, "ux0:license/app/%s/%s", titleid, rif_name);
|
||||
if (checkFileExist(license_path))
|
||||
if (is_app)
|
||||
snprintf(sfo_path, MAX_PATH_LENGTH, "ux0:license/app/%s/%s", titleid, rif_name);
|
||||
else
|
||||
snprintf(sfo_path, MAX_PATH_LENGTH, "ux0:license/addcont/%s/%s/%s", titleid, &contentid[20], rif_name);
|
||||
if (checkFileExist(sfo_path))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Clean
|
||||
removePath("ux0:temp/game", NULL);
|
||||
sceIoMkdir("ux0:temp", 0006);
|
||||
|
||||
// Rename app
|
||||
res = sceIoRename(app_path, "ux0:temp/game");
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
// Remove work.bin for custom homebrews
|
||||
if (isCustomHomebrew())
|
||||
sceIoRemove("ux0:temp/game/sce_sys/package/work.bin");
|
||||
|
||||
// Promote app
|
||||
res = promoteApp("ux0:temp/game");
|
||||
|
||||
// Rename back if it failed
|
||||
if (res < 0) {
|
||||
sceIoRename("ux0:temp/game", app_path);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Return success
|
||||
return 1;
|
||||
}
|
||||
|
||||
int refresh_thread(SceSize args, void *argp) {
|
||||
int refreshApp(const char *app_path)
|
||||
{
|
||||
char work_bin_path[MAX_PATH_LENGTH];
|
||||
int res;
|
||||
|
||||
snprintf(work_bin_path, MAX_PATH_LENGTH, "%s/sce_sys/package/work.bin", app_path);
|
||||
|
||||
// Remove work.bin for custom homebrews
|
||||
if (isCustomHomebrew(work_bin_path)) {
|
||||
sceIoRemove(work_bin_path);
|
||||
} else if (!checkFileExist(work_bin_path)) {
|
||||
// If available, restore work.bin from licenses.db
|
||||
void *sfo_buffer = NULL;
|
||||
char sfo_path[MAX_PATH_LENGTH], contentid[50];
|
||||
snprintf(sfo_path, MAX_PATH_LENGTH, "%s/sce_sys/param.sfo", app_path);
|
||||
int sfo_size = allocateReadFile(sfo_path, &sfo_buffer);
|
||||
if (sfo_size > 0) {
|
||||
getSfoString(sfo_buffer, "CONTENT_ID", contentid, sizeof(contentid));
|
||||
uint8_t* rif = query_rif(DB_PATH, contentid);
|
||||
if (rif != NULL) {
|
||||
int fh = sceIoOpen(work_bin_path, SCE_O_WRONLY | SCE_O_CREAT, 0777);
|
||||
if (fh > 0) {
|
||||
sceIoWrite(fh, rif, RIF_SIZE);
|
||||
sceIoClose(fh);
|
||||
}
|
||||
free(rif);
|
||||
}
|
||||
}
|
||||
free(sfo_buffer);
|
||||
}
|
||||
|
||||
// Promote app/dlc
|
||||
res = promoteApp(app_path);
|
||||
return (res < 0) ? res : 1;
|
||||
}
|
||||
|
||||
int parse_dir_with_callback(const char* path, void(*callback)(void*, const char*, const char*), void* data)
|
||||
{
|
||||
SceUID dfd = sceIoDopen(path);
|
||||
if (dfd >= 0) {
|
||||
int res = 0;
|
||||
|
||||
do {
|
||||
SceIoDirent dir;
|
||||
memset(&dir, 0, sizeof(SceIoDirent));
|
||||
|
||||
res = sceIoDread(dfd, &dir);
|
||||
if (res > 0) {
|
||||
if (SCE_S_ISDIR(dir.d_stat.st_mode)) {
|
||||
callback(data, path, dir.d_name);
|
||||
if (cancelHandler()) {
|
||||
closeWaitDialog();
|
||||
setDialogStep(DIALOG_STEP_CANCELLED);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (res > 0);
|
||||
sceIoDclose(dfd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int refresh_pass;
|
||||
int count;
|
||||
int processed;
|
||||
int refreshed;
|
||||
} refresh_data_t;
|
||||
|
||||
typedef struct {
|
||||
refresh_data_t *refresh_data;
|
||||
char* list[MAX_DLC_PER_TITLE];
|
||||
int list_size;
|
||||
} dlc_data_t;
|
||||
|
||||
void app_callback(void* data, const char* dir, const char* subdir)
|
||||
{
|
||||
refresh_data_t *refresh_data = (refresh_data_t*)data;
|
||||
char path[MAX_PATH_LENGTH];
|
||||
|
||||
if (strcmp(subdir, vitashell_titleid) == 0)
|
||||
return;
|
||||
|
||||
if (refresh_data->refresh_pass) {
|
||||
snprintf(path, MAX_PATH_LENGTH, "%s/%s", dir, subdir);
|
||||
if (refreshNeeded(path)) {
|
||||
// Move the directory to temp for installation
|
||||
removePath(APP_TEMP, NULL);
|
||||
sceIoRename(path, APP_TEMP);
|
||||
if (refreshApp(APP_TEMP) == 1)
|
||||
refresh_data->refreshed++;
|
||||
else
|
||||
// Restore folder on error
|
||||
sceIoRename(APP_TEMP, path);
|
||||
}
|
||||
SetProgress(++refresh_data->processed, refresh_data->count);
|
||||
} else {
|
||||
refresh_data->count++;
|
||||
}
|
||||
}
|
||||
|
||||
void dlc_callback_inner(void* data, const char* dir, const char* subdir)
|
||||
{
|
||||
dlc_data_t *dlc_data = (dlc_data_t*)data;
|
||||
char path[MAX_PATH_LENGTH];
|
||||
|
||||
// Ignore "sce_sys" and "sce_pfs" directories
|
||||
if (strncmp(subdir, "sce_", 4) == 0)
|
||||
return;
|
||||
|
||||
if (dlc_data->refresh_data->refresh_pass) {
|
||||
snprintf(path, MAX_PATH_LENGTH, "%s/%s", dir, subdir);
|
||||
if (dlc_data->list_size < MAX_DLC_PER_TITLE)
|
||||
dlc_data->list[dlc_data->list_size++] = strdup(path);
|
||||
} else {
|
||||
dlc_data->refresh_data->count++;
|
||||
}
|
||||
}
|
||||
|
||||
void dlc_callback_outer(void* data, const char* dir, const char* subdir)
|
||||
{
|
||||
refresh_data_t *refresh_data = (refresh_data_t*)data;
|
||||
dlc_data_t dlc_data;
|
||||
dlc_data.refresh_data = refresh_data;
|
||||
dlc_data.list_size = 0;
|
||||
char path[MAX_PATH_LENGTH];
|
||||
|
||||
// Get the title's dlc subdirectories
|
||||
int len = snprintf(path, sizeof(path), "%s/%s", dir, subdir);
|
||||
parse_dir_with_callback(path, dlc_callback_inner, &dlc_data);
|
||||
|
||||
if (refresh_data->refresh_pass) {
|
||||
// For dlc, the process happens in two phases to avoid promotion errors:
|
||||
// 1. Move all dlc that require refresh out of addcont/title_id
|
||||
// 2. Refresh the moved dlc_data
|
||||
for (int i = 0; i < dlc_data.list_size; i++) {
|
||||
if (refreshNeeded(dlc_data.list[i])) {
|
||||
snprintf(path, MAX_PATH_LENGTH, DLC_TEMP "/%s", &dlc_data.list[i][len + 1]);
|
||||
removePath(path, NULL);
|
||||
sceIoRename(dlc_data.list[i], path);
|
||||
} else {
|
||||
free(dlc_data.list[i]);
|
||||
dlc_data.list[i] = NULL;
|
||||
SetProgress(++refresh_data->processed, refresh_data->count);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that the dlc we need are out of addcont/title_id, refresh them
|
||||
for (int i = 0; i < dlc_data.list_size; i++) {
|
||||
if (dlc_data.list[i] != NULL) {
|
||||
snprintf(path, MAX_PATH_LENGTH, DLC_TEMP "/%s", &dlc_data.list[i][len + 1]);
|
||||
if (refreshApp(path) == 1)
|
||||
refresh_data->refreshed++;
|
||||
else
|
||||
sceIoRename(path, dlc_data.list[i]);
|
||||
SetProgress(++refresh_data->processed, refresh_data->count);
|
||||
free(dlc_data.list[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int refresh_thread(SceSize args, void *argp)
|
||||
{
|
||||
SceUID thid = -1;
|
||||
SceUID dfd = -1;
|
||||
int folders = 0;
|
||||
int count = 0;
|
||||
int items = 0;
|
||||
refresh_data_t refresh_data = { 0, 0, 0, 0 };
|
||||
|
||||
// Lock power timers
|
||||
powerLock();
|
||||
@ -125,70 +314,31 @@ int refresh_thread(SceSize args, void *argp) {
|
||||
sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 0);
|
||||
sceKernelDelayThread(DIALOG_WAIT); // Needed to see the percentage
|
||||
|
||||
// Get number of folders
|
||||
dfd = sceIoDopen("ux0:app");
|
||||
if (dfd >= 0) {
|
||||
int res = 0;
|
||||
// Get the app count
|
||||
if (parse_dir_with_callback("ux0:app", app_callback, &refresh_data) < 0)
|
||||
goto EXIT;
|
||||
|
||||
do {
|
||||
SceIoDirent dir;
|
||||
memset(&dir, 0, sizeof(SceIoDirent));
|
||||
|
||||
res = sceIoDread(dfd, &dir);
|
||||
if (res > 0) {
|
||||
if (SCE_S_ISDIR(dir.d_stat.st_mode)) {
|
||||
if (strcmp(dir.d_name, vitashell_titleid) == 0)
|
||||
continue;
|
||||
|
||||
// Count
|
||||
folders++;
|
||||
|
||||
if (cancelHandler()) {
|
||||
closeWaitDialog();
|
||||
setDialogStep(DIALOG_STEP_CANCELLED);
|
||||
goto EXIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (res > 0);
|
||||
|
||||
sceIoDclose(dfd);
|
||||
}
|
||||
// Get the dlc count
|
||||
if (parse_dir_with_callback("ux0:addcont", dlc_callback_outer, &refresh_data) < 0)
|
||||
goto EXIT;
|
||||
|
||||
// Update thread
|
||||
thid = createStartUpdateThread(folders, 0);
|
||||
thid = createStartUpdateThread(refresh_data.count, 0);
|
||||
|
||||
dfd = sceIoDopen("ux0:app");
|
||||
if (dfd >= 0) {
|
||||
int res = 0;
|
||||
// Make sure we have the temp directories we need
|
||||
sceIoMkdir("ux0:temp", 0006);
|
||||
sceIoMkdir("ux0:temp/addcont", 0006);
|
||||
refresh_data.refresh_pass = 1;
|
||||
|
||||
do {
|
||||
SceIoDirent dir;
|
||||
memset(&dir, 0, sizeof(SceIoDirent));
|
||||
// Refresh apps
|
||||
if (parse_dir_with_callback("ux0:app", app_callback, &refresh_data) < 0)
|
||||
goto EXIT;
|
||||
|
||||
res = sceIoDread(dfd, &dir);
|
||||
if (res > 0) {
|
||||
if (SCE_S_ISDIR(dir.d_stat.st_mode)) {
|
||||
if (strcmp(dir.d_name, vitashell_titleid) == 0)
|
||||
continue;
|
||||
// Refresh dlc
|
||||
if (parse_dir_with_callback("ux0:addcont", dlc_callback_outer, &refresh_data) < 0)
|
||||
goto EXIT;
|
||||
|
||||
// Refresh app
|
||||
if (refreshApp(dir.d_name) == 1)
|
||||
items++;
|
||||
|
||||
SetProgress(++count, folders);
|
||||
|
||||
if (cancelHandler()) {
|
||||
closeWaitDialog();
|
||||
setDialogStep(DIALOG_STEP_CANCELLED);
|
||||
goto EXIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (res > 0);
|
||||
|
||||
sceIoDclose(dfd);
|
||||
}
|
||||
sceIoRmdir("ux0:temp/addcont");
|
||||
|
||||
// Set progress to 100%
|
||||
sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 100);
|
||||
@ -197,7 +347,7 @@ int refresh_thread(SceSize args, void *argp) {
|
||||
// Close
|
||||
closeWaitDialog();
|
||||
|
||||
infoDialog(language_container[REFRESHED], items);
|
||||
infoDialog(language_container[REFRESHED], refresh_data.refreshed);
|
||||
|
||||
EXIT:
|
||||
if (thid >= 0)
|
||||
@ -207,4 +357,4 @@ EXIT:
|
||||
powerUnlock();
|
||||
|
||||
return sceKernelExitDeleteThread(0);
|
||||
}
|
||||
}
|
||||
|
93
sqlite3.h
Normal file
93
sqlite3.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
** 2001 September 15
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This header was intentionally truncated from the original version to
|
||||
** only include the elements needed by this application.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef _SQLITE3_H_
|
||||
#define _SQLITE3_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_EXTERN
|
||||
# define SQLITE_EXTERN extern
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_API
|
||||
# define SQLITE_API
|
||||
#endif
|
||||
|
||||
#define SQLITE_OK 0 /* Successful result */
|
||||
#define SQLITE_ERROR 1 /* SQL error or missing database */
|
||||
#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
|
||||
#define SQLITE_PERM 3 /* Access permission denied */
|
||||
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
|
||||
#define SQLITE_BUSY 5 /* The database file is locked */
|
||||
#define SQLITE_LOCKED 6 /* A table in the database is locked */
|
||||
#define SQLITE_NOMEM 7 /* A malloc() failed */
|
||||
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
|
||||
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
|
||||
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
|
||||
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
|
||||
#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */
|
||||
#define SQLITE_FULL 13 /* Insertion failed because database is full */
|
||||
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
|
||||
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
|
||||
#define SQLITE_EMPTY 16 /* Database is empty */
|
||||
#define SQLITE_SCHEMA 17 /* The database schema changed */
|
||||
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
|
||||
#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
|
||||
#define SQLITE_MISMATCH 20 /* Data type mismatch */
|
||||
#define SQLITE_MISUSE 21 /* Library used incorrectly */
|
||||
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
|
||||
#define SQLITE_AUTH 23 /* Authorization denied */
|
||||
#define SQLITE_FORMAT 24 /* Auxiliary database format error */
|
||||
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
|
||||
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
|
||||
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
|
||||
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
|
||||
|
||||
#define SQLITE_OPEN_READONLY 0x00000001
|
||||
#define SQLITE_OPEN_READWRITE 0x00000002
|
||||
#define SQLITE_OPEN_CREATE 0x00000004
|
||||
#define SQLITE_OPEN_URI 0x00000040
|
||||
#define SQLITE_OPEN_NOMUTEX 0x00008000
|
||||
#define SQLITE_OPEN_FULLMUTEX 0x00010000
|
||||
#define SQLITE_OPEN_SHAREDCACHE 0x00020000
|
||||
#define SQLITE_OPEN_PRIVATECACHE 0x00040000
|
||||
|
||||
typedef struct sqlite3 sqlite3;
|
||||
typedef struct sqlite3_stmt sqlite3_stmt;
|
||||
|
||||
SQLITE_API int sqlite3_errcode(sqlite3 *db);
|
||||
SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
|
||||
SQLITE_API const char *sqlite3_errmsg(sqlite3*);
|
||||
SQLITE_API void *sqlite3_malloc(int);
|
||||
SQLITE_API void *sqlite3_realloc(void*, int);
|
||||
SQLITE_API void sqlite3_free(void*);
|
||||
SQLITE_API int sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs);
|
||||
SQLITE_API int sqlite3_close(sqlite3 *);
|
||||
SQLITE_API int sqlite3_exec(sqlite3*, const char *sql, int (*callback)(void*,int,char**,char**), void *, char **errmsg);
|
||||
SQLITE_API int sqlite3_prepare_v2(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail);
|
||||
SQLITE_API int sqlite3_step(sqlite3_stmt*);
|
||||
SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
|
||||
SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user