* Copyright (c) Huawei Device Co., Ltd. 2026-2026. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "pole.h"
#include "storage.h"
#include "stream.h"
namespace OHOS {
namespace ObjectEditor {
Storage::Storage(const char *filename)
{
io_ = std::make_unique<StorageIO>(filename);
}
Storage::Storage(const std::string &oeid)
{
io_ = std::make_unique<StorageIO>(oeid);
}
Storage::~Storage() = default;
int Storage::Result() const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (!io_) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "io is null");
return Storage::UnknownError;
}
return io_->Result();
}
void Storage::ListEntries(std::vector<const DirEntry *> &result) const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (!io_) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "io is null");
return;
}
io_->ListEntries(result);
}
bool Storage::EnterDirectory(const std::string &directory)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (!io_) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "io is null");
return false;
}
return io_->EnterDirectory(directory);
}
void Storage::LeaveDirectory()
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (!io_) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "io is null");
return;
}
io_->LeaveDirectory();
}
DirEntry *Storage::GetStorage(const std::string &path, bool create)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
OBJECT_EDITOR_LOGD(ObjectEditorDomain::DOCUMENT, "path: %{private}s, create: %{public}d",
path.c_str(), create);
if (!io_ || path.empty()) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "io is null or path is empty");
return nullptr;
}
std::string normalized = path;
if (normalized.front() != '/') {
normalized.insert(0, "/");
}
while (normalized.size() > 1 && normalized.back() == '/') {
normalized.pop_back();
}
if (normalized == "/") {
return io_->GetRootEntry();
}
if (DirEntry *entry = io_->Entry(normalized, false)) {
return entry->IsDir() ? entry : nullptr;
}
if (!create) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "create is false, path: %{private}s", normalized.c_str());
return nullptr;
}
const auto pos = normalized.find_last_of('/');
const std::string parentPath = (pos == std::string::npos || pos == 0) ? std::string("/") :
normalized.substr(0, pos);
DirEntry *parent = io_->Entry(parentPath, false);
if (!parent || !parent->IsDir()) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "parent is not dir, path: %{private}s", parentPath.c_str());
return nullptr;
}
DirEntry *created = io_->Entry(normalized, true);
if (!created) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "create entry failed, path: %{private}s", normalized.c_str());
return nullptr;
}
created->SetType(1);
created->SetChild(DIR_ENTRY_END);
created->SetSize(0);
created->SetStart(DIR_ENTRY_END);
if (created->Type() == DirEntry::EntryType::DIR) {
created->SetCreationTime(GetCurrentFileTime());
}
return created->IsDir() ? created : nullptr;
}
void Storage::Path(std::string &result) const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (!io_) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "io is null");
return;
}
io_->Path(result);
}
Stream *Storage::GetStream(const std::string &name, bool create, bool reuse)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
OBJECT_EDITOR_LOGD(ObjectEditorDomain::DOCUMENT, "name: %{private}s, create: %{public}d, reuse: %{public}d",
name.c_str(), create, reuse);
if (!io_ || !name.length()) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "io is null or name is empty");
return nullptr;
}
std::string fullName = name;
if (name[0] != '/') {
std::string currentPath;
Path(currentPath);
if (currentPath.empty() || currentPath == "/") {
fullName.insert(fullName.begin(), '/');
} else if (currentPath.back() == '/') {
fullName.insert(0, currentPath);
} else {
fullName.insert(0, currentPath + "/");
}
}
if (reuse) {
for (const auto &stream : streams_) {
if (stream && stream->Path() == fullName) {
return stream.get();
}
}
}
DirEntry *entry = io_->Entry(fullName, create);
if (!entry || !entry->IsFile()) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "entry is not file, path: %{private}s", fullName.c_str());
return nullptr;
}
auto impl = std::make_unique<StreamImpl>(io_.get(), fullName);
auto stream = std::make_unique<Stream>(impl.get());
impl.release();
streams_.push_back(std::move(stream));
return streams_.back().get();
}
DirEntry *Storage::GetRootEntry()
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
return io_ ? io_->GetRootEntry() : nullptr;
}
DirEntry *Storage::GetEntry(const std::string &path, bool create)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
return io_ ? io_->Entry(path, create) : nullptr;
}
bool Storage::Flush()
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
return io_ ? io_->Flush() : false;
}
bool Storage::IsDirty() const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
return io_ ? io_->IsDirty() : false;
}
bool Storage::ReadRawCd(size_t offset, uint8_t *buf, size_t len, size_t *outRead)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (buf == nullptr || outRead == nullptr) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "buf or outRead is null");
return false;
}
return io_ ? io_->ReadRawCd(offset, buf, len, outRead) : false;
}
bool Storage::SaveToFile(const char *filename)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
return io_ ? io_->SaveToFile(filename, true) : false;
}
void Storage::Debug()
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (!io_) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "io is null");
return;
}
io_->Debug();
}
bool Storage::DeleteEntry(const std::string &path)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (io_) {
bool result = io_->DeleteEntry(path);
if (result) {
streams_.remove_if([&](const std::unique_ptr<Stream> &stream) {
return stream && stream->Path() == path;
});
}
return result;
}
return false;
}
const CLSID &Storage::Clsid() const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (!io_ || io_->GetHeader() == nullptr) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "io is null or header is null");
static CLSID empty{};
return empty;
}
return io_->GetHeader()->Clsid();
}
uint32_t Storage::TransactionSignature() const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (!io_ || io_->GetHeader() == nullptr) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "io is null or header is null");
return 0;
}
return io_->GetHeader()->TransactionSignature();
}
Stream::~Stream()
{
delete impl;
}
const std::string &Stream::Path() const
{
return impl ? impl->Path() : StreamImpl::nullPath;
}
StreamPos Stream::Tell() const
{
return impl ? static_cast<StreamPos>(impl->Tell()) : 0;
}
bool Stream::Eof() const
{
return impl ? impl->Eof() : true;
}
bool Stream::Fail() const
{
return impl ? impl->Fail() : true;
}
void Stream::Seek(StreamPos newPos)
{
if (impl) {
impl->Seek(newPos);
}
}
StreamPos Stream::Size() const
{
return impl ? impl->Size() : 0;
}
int Stream::Getch()
{
return impl ? impl->Getch() : 0;
}
std::streamsize Stream::Read(Byte *data, std::streamsize maxlen)
{
if (!impl || !data || maxlen == 0) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "impl or data or maxlen is null");
return 0;
}
return impl->Read(data, maxlen);
}
std::streamsize Stream::ReadBufferUntilNull(std::vector<Byte> &buffer)
{
if (!impl) {
OBJECT_EDITOR_LOGE(ObjectEditorDomain::DOCUMENT, "impl is null");
return 0;
}
return impl->ReadBufferUntilNull(buffer);
}
Stream &Stream::Write(const Byte *data, uint32_t len)
{
if (impl && data && len > 0) {
impl->Write(data, len);
}
return *this;
}
}
}