#include "TjdUiAppEbookModel.h" #include "TjdUiAppEbookPresenter.h" #include "cJSON.h" #include "fs_user_common.h" #include "sys_config.h" #include #include #include #include #include #include #include #include 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 &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(&size), sizeof(size)); } file.close(); } // 加载页数buf从bin文件 std::vector 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 readSizes; uint32_t tempSize; while (count-- > 0 && file.read(reinterpret_cast(&tempSize), sizeof(tempSize))) { readSizes.push_back(tempSize); } file.close(); return readSizes; } // 加载书籍列表从 JSON 文件 bool TjdUiAppEbookModel::LoadBooksFromJson(const char *filename, std::list &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(id_json->valueint), name_json->valuestring, static_cast(curChapter_json->valueint), static_cast(curPage_json->valueint), static_cast(loadOver_json->valueint)); } } cJSON_Delete(json); return true; } // 将书籍列表保存到 JSON 文件 void TjdUiAppEbookModel::SaveBooksToJson(const char *filename, const std::list &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 &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(json_file)), std::istreambuf_iterator()); 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(file)), std::istreambuf_iterator()); 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