367 lines
13 KiB
C++
367 lines
13 KiB
C++
#include "TjdUiAppEbookModel.h"
|
||
#include "TjdUiAppEbookPresenter.h"
|
||
#include "cJSON.h"
|
||
#include "fs_user_common.h"
|
||
#include "sys_config.h"
|
||
#include <dirent.h>
|
||
#include <fcntl.h>
|
||
#include <fstream>
|
||
#include <iostream>
|
||
#include <sstream>
|
||
#include <sys/stat.h>
|
||
#include <sys/types.h>
|
||
#include <unistd.h>
|
||
|
||
using namespace OHOS;
|
||
|
||
#define ENABLE_PRINT_INFO 1
|
||
#define ENABLE_DEBUG 1
|
||
|
||
#if ENABLE_PRINT_INFO
|
||
#define static_print_info(...) sys_ui_log_i(__VA_ARGS__) // 一般信息打印宏控制
|
||
#define static_print_warn(...) sys_ui_log_w(__VA_ARGS__) // 警告信息打印一般常开
|
||
#define static_print_error(...) sys_ui_log_e(__VA_ARGS__) // 错误信息打印一般常开
|
||
#if ENABLE_PRINT_INFO
|
||
#define static_print_debug(...) sys_ui_log_d(__VA_ARGS__) // 调试信息打印
|
||
#else
|
||
#define static_print_debug(...)
|
||
#endif
|
||
#else
|
||
#define static_print_info(...)
|
||
#define static_print_warn(...)
|
||
#define static_print_error(...)
|
||
#endif
|
||
|
||
namespace TJD {
|
||
// 辅助函数:从cJSON对象中获取字符串字段
|
||
const char *get_cjson_string(cJSON *object, const char *key)
|
||
{
|
||
cJSON *value = cJSON_GetObjectItemCaseSensitive(object, key);
|
||
if (value != NULL && cJSON_IsString(value)) {
|
||
return value->valuestring;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
// 辅助函数:在cJSON数组中查找具有指定ID的对象
|
||
cJSON *find_book_by_id(cJSON *array, int id)
|
||
{
|
||
int arraySize = cJSON_GetArraySize(array);
|
||
for (int i = 0; i < arraySize; i++) {
|
||
cJSON *book = cJSON_GetArrayItem(array, i);
|
||
if (cJSON_IsObject(book) && cJSON_HasObjectItem(book, "id")) {
|
||
int book_id = cJSON_GetObjectItemCaseSensitive(book, "id")->valueint;
|
||
if (book_id == id) {
|
||
return book;
|
||
}
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
// 辅助函数:从cJSON数组中删除具有指定ID的对象,并删除对应文件
|
||
void delete_and_renumber_books(cJSON **books, int id_to_delete)
|
||
{
|
||
cJSON *new_array = cJSON_CreateArray();
|
||
int new_id = 0;
|
||
cJSON *book;
|
||
|
||
cJSON_ArrayForEach(book, *books)
|
||
{
|
||
int book_id = cJSON_GetObjectItemCaseSensitive(book, "id")->valueint;
|
||
if (book_id == id_to_delete) {
|
||
const char *book_name = cJSON_GetObjectItemCaseSensitive(book, "name")->valuestring;
|
||
if (book_name) {
|
||
std::string path = TJD_FS_DIR_BOOK + std::string("/");
|
||
std::string file_path = path + std::string(book_name) + ".txt";
|
||
static_print_info("delete file:%s", file_path.c_str());
|
||
int ret;
|
||
if ((ret = std::remove(file_path.c_str())) != 0) {
|
||
static_print_error("file delete fail: %d", ret);
|
||
return;
|
||
}
|
||
std::string file_bin_path = path + std::string(book_name) + ".bin";
|
||
if ((ret = std::remove(file_bin_path.c_str())) != 0) {
|
||
static_print_error("file delete fail: %d", ret);
|
||
}
|
||
}
|
||
continue; // 跳过当前循环迭代,不添加这本书到新数组中
|
||
}
|
||
|
||
// 更新ID并添加到新数组中
|
||
cJSON_DeleteItemFromObject(book, "id");
|
||
cJSON_AddItemToObject(book, "id", cJSON_CreateNumber(new_id++));
|
||
cJSON_AddItemToArray(new_array, cJSON_Duplicate(book, 1));
|
||
}
|
||
|
||
// 用新数组替换旧数组
|
||
cJSON_Delete(*books);
|
||
*books = new_array;
|
||
}
|
||
|
||
// 写入页数到bin文件
|
||
void TjdUiAppEbookModel::WriteEbookSizesToBinFile(std::string name, const std::vector<uint32_t> &sizes,
|
||
const char *path)
|
||
{
|
||
std::string filename = path;
|
||
filename += "/" + name + ".bin";
|
||
std::ofstream file(filename, std::ios::out | std::ios::binary | std::ios::app);
|
||
if (!file.is_open()) {
|
||
static_print_error("Failed to open file for writing");
|
||
return;
|
||
}
|
||
for (const auto &size : sizes) {
|
||
file.write(reinterpret_cast<const char *>(&size), sizeof(size));
|
||
}
|
||
file.close();
|
||
}
|
||
|
||
// 加载页数buf从bin文件
|
||
std::vector<uint32_t> TjdUiAppEbookModel::ReadEbookSizesFromBinFile(std::string name, const char *path,
|
||
size_t startElement, size_t count)
|
||
{
|
||
std::string filename = path;
|
||
filename += "/" + name + ".bin";
|
||
std::ifstream file(filename, std::ios::in | std::ios::binary);
|
||
if (!file.is_open()) {
|
||
static_print_error("Failed to open file for reading");
|
||
return {};
|
||
}
|
||
|
||
// 定位到起始位置
|
||
file.seekg(startElement * sizeof(uint32_t), std::ios::beg);
|
||
|
||
std::vector<uint32_t> readSizes;
|
||
uint32_t tempSize;
|
||
while (count-- > 0 && file.read(reinterpret_cast<char *>(&tempSize), sizeof(tempSize))) {
|
||
readSizes.push_back(tempSize);
|
||
}
|
||
|
||
file.close();
|
||
return readSizes;
|
||
}
|
||
|
||
// 加载书籍列表从 JSON 文件
|
||
bool TjdUiAppEbookModel::LoadBooksFromJson(const char *filename, std::list<EbookItem> &books)
|
||
{
|
||
std::ifstream file(filename);
|
||
std::stringstream buffer;
|
||
buffer << file.rdbuf();
|
||
std::string json_string = buffer.str();
|
||
|
||
cJSON *json = cJSON_Parse(json_string.c_str());
|
||
if (!json || !cJSON_IsArray(json)) {
|
||
static_print_error("Error parsing JSON");
|
||
return false;
|
||
}
|
||
|
||
cJSON *item;
|
||
cJSON_ArrayForEach(item, json)
|
||
{
|
||
cJSON *id_json = cJSON_GetObjectItemCaseSensitive(item, "id");
|
||
cJSON *name_json = cJSON_GetObjectItemCaseSensitive(item, "name");
|
||
cJSON *curChapter_json = cJSON_GetObjectItemCaseSensitive(item, "curChapter");
|
||
cJSON *curPage_json = cJSON_GetObjectItemCaseSensitive(item, "curPage");
|
||
cJSON *loadOver_json = cJSON_GetObjectItemCaseSensitive(item, "loadOver");
|
||
if (cJSON_IsNumber(id_json) && cJSON_IsString(name_json) && cJSON_IsNumber(curChapter_json) &&
|
||
cJSON_IsNumber(curPage_json) && cJSON_IsBool(loadOver_json)) {
|
||
books.emplace_back(static_cast<uint8_t>(id_json->valueint), name_json->valuestring,
|
||
static_cast<uint32_t>(curChapter_json->valueint),
|
||
static_cast<uint32_t>(curPage_json->valueint),
|
||
static_cast<bool>(loadOver_json->valueint));
|
||
}
|
||
}
|
||
|
||
cJSON_Delete(json);
|
||
return true;
|
||
}
|
||
|
||
// 将书籍列表保存到 JSON 文件
|
||
void TjdUiAppEbookModel::SaveBooksToJson(const char *filename, const std::list<EbookItem> &books)
|
||
{
|
||
cJSON *json = cJSON_CreateArray();
|
||
|
||
for (const auto &book : books) {
|
||
static_print_debug("book.id:%02d book.name:%s", book.id, book.name.c_str());
|
||
cJSON *book_json = cJSON_CreateObject();
|
||
cJSON_AddItemToObject(book_json, "id", cJSON_CreateNumber(book.id));
|
||
cJSON_AddItemToObject(book_json, "name", cJSON_CreateString(book.name.c_str()));
|
||
cJSON_AddItemToObject(book_json, "curChapter", cJSON_CreateNumber(book.curChapter));
|
||
cJSON_AddItemToObject(book_json, "curPage", cJSON_CreateNumber(book.curPage));
|
||
cJSON_AddItemToObject(book_json, "loadOver", cJSON_CreateBool(book.loadOver));
|
||
cJSON_AddItemToArray(json, book_json);
|
||
}
|
||
|
||
char *rendered = cJSON_Print(json);
|
||
std::ofstream file(filename);
|
||
|
||
if (!file.is_open()) {
|
||
static_print_error("Error: Unable to open file for writing: %s", filename);
|
||
cJSON_Delete(json);
|
||
free(rendered);
|
||
return;
|
||
}
|
||
|
||
static_print_info("File opened successfully. Writing JSON to file...");
|
||
static_print_debug("%s", rendered);
|
||
file << rendered;
|
||
file.close();
|
||
static_print_info("JSON written to file successfully.");
|
||
|
||
cJSON_Delete(json);
|
||
free(rendered);
|
||
}
|
||
|
||
// 扫描 txt 文件并更新书籍列表
|
||
void TjdUiAppEbookModel::ScanAndUpdateBooks(const char *dirname, std::list<EbookItem> &books)
|
||
{
|
||
DIR *d;
|
||
std::string dir = dirname;
|
||
struct dirent *dirp;
|
||
struct stat fileInfo;
|
||
|
||
d = opendir(dir.c_str());
|
||
if (d) {
|
||
uint8_t next_id = books.empty() ? 0 : books.back().id + 1;
|
||
|
||
while ((dirp = readdir(d)) != nullptr) {
|
||
std::string filename = dirp->d_name;
|
||
std::string fullpath = dir + "/" + filename;
|
||
|
||
if (stat(fullpath.c_str(), &fileInfo) == 0 && S_ISREG(fileInfo.st_mode) && fileInfo.st_size > 0) {
|
||
size_t pos = filename.rfind('.');
|
||
if (pos != std::string::npos && filename.substr(pos + 1) == "txt") {
|
||
std::string name = filename.substr(0, pos);
|
||
bool exists = false;
|
||
for (const auto &book : books) {
|
||
if (book.name == name) {
|
||
exists = true;
|
||
break;
|
||
}
|
||
}
|
||
if (!exists) {
|
||
books.emplace_back(next_id++, name, 1, 1, false);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
closedir(d);
|
||
}
|
||
}
|
||
|
||
// 删除指定ID的书籍和对应的文件
|
||
bool TjdUiAppEbookModel::deleteBookById(const char *jsonFilePath, int id)
|
||
{
|
||
std::ifstream json_file(jsonFilePath);
|
||
if (!json_file.is_open()) {
|
||
static_print_error("Failed to open file: %s", jsonFilePath);
|
||
return false;
|
||
}
|
||
|
||
std::string json_str((std::istreambuf_iterator<char>(json_file)), std::istreambuf_iterator<char>());
|
||
json_file.close();
|
||
|
||
if (json_str.empty()) {
|
||
static_print_error("json has no content.");
|
||
return false;
|
||
}
|
||
|
||
cJSON *json = cJSON_Parse(json_str.c_str());
|
||
if (!cJSON_IsArray(json)) {
|
||
static_print_error("json is not Array");
|
||
cJSON_Delete(json);
|
||
return false;
|
||
}
|
||
|
||
static_print_debug("delete before...");
|
||
static_print_debug("%s", cJSON_Print(json));
|
||
|
||
delete_and_renumber_books(&json, id);
|
||
|
||
const char *output = cJSON_Print(json);
|
||
std::ofstream out_file(jsonFilePath);
|
||
if (out_file.is_open()) {
|
||
static_print_debug("delete after...");
|
||
static_print_debug("%s", output);
|
||
out_file << output;
|
||
out_file.close();
|
||
} else {
|
||
static_print_error("Failed to open file: %s", jsonFilePath);
|
||
free((void *)output);
|
||
cJSON_Delete(json);
|
||
return false;
|
||
}
|
||
|
||
free((void *)output);
|
||
cJSON_Delete(json);
|
||
|
||
return true;
|
||
}
|
||
|
||
void TjdUiAppEbookModel::SaveItemBookToJson(const char *filename, const EbookItem itemToUpdate)
|
||
{
|
||
std::ifstream file(filename);
|
||
if (!file.is_open()) {
|
||
static_print_error("Unable to open file: %s", filename);
|
||
return;
|
||
}
|
||
|
||
std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||
file.close();
|
||
|
||
cJSON *root = cJSON_Parse(fileContent.c_str());
|
||
if (root == nullptr || !cJSON_IsArray(root)) {
|
||
static_print_error("Parsing JSON failed or the JSON root is not an array.");
|
||
if (root != nullptr)
|
||
cJSON_Delete(root);
|
||
return;
|
||
}
|
||
|
||
int arraySize = cJSON_GetArraySize(root);
|
||
for (int i = 0; i < arraySize; ++i) {
|
||
cJSON *item = cJSON_GetArrayItem(root, i);
|
||
if (item != nullptr && cJSON_IsObject(item)) {
|
||
cJSON *itemId = cJSON_GetObjectItem(item, "id");
|
||
if (itemId != nullptr && cJSON_IsNumber(itemId) && itemId->valueint == itemToUpdate.id) {
|
||
// 找到匹配的项,更新字段
|
||
cJSON_SetNumberValue(cJSON_GetObjectItem(item, "curPage"), itemToUpdate.curPage);
|
||
cJSON *boolField = cJSON_GetObjectItem(item, "loadOver");
|
||
if (cJSON_IsBool(boolField)) {
|
||
cJSON_DeleteItemFromObject(item, "loadOver"); // 先删除旧的字段
|
||
cJSON_AddItemToObject(item, "loadOver", cJSON_CreateBool(itemToUpdate.loadOver));
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 将修改后的JSON写回文件
|
||
char *jsonString = cJSON_Print(root);
|
||
if (jsonString == nullptr) {
|
||
static_print_error("Cannot convert JSON to a string.");
|
||
cJSON_Delete(root);
|
||
return;
|
||
}
|
||
|
||
std::ofstream outFile(filename);
|
||
if (!outFile.is_open()) {
|
||
static_print_error("Unable to open file for writing: %s", filename);
|
||
free(jsonString);
|
||
cJSON_Delete(root);
|
||
return;
|
||
}
|
||
|
||
outFile << jsonString;
|
||
outFile.close();
|
||
|
||
free(jsonString);
|
||
cJSON_Delete(root);
|
||
}
|
||
|
||
TjdUiAppEbookModel &TjdUiAppEbookModel::GetInstance(void)
|
||
{
|
||
static TjdUiAppEbookModel instance;
|
||
return instance;
|
||
}
|
||
|
||
} // namespace TJD
|