1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "file_utils.h"
17 
18 #include <fcntl.h>
19 #include <sys/sendfile.h>
20 #include <sys/stat.h>
21 
22 #include "media_log.h"
23 #include "media_file_utils.h"
24 #include "database_adapter.h"
25 #include "result_set_utils.h"
26 #include "media_column.h"
27 #include "image_packer.h"
28 #include "medialibrary_errno.h"
29 #include "medialibrary_tracer.h"
30 #include "medialibrary_type_const.h"
31 #include "medialibrary_operation.h"
32 #include "medialibrary_object_utils.h"
33 #include "picture.h"
34 #include "image_type.h"
35 
36 using namespace std;
37 
38 namespace OHOS {
39 namespace Media {
40 const std::string MIME_TYPE_HEIF = "image/heif";
41 const std::string MIME_TYPE_HEIC = "image/heic";
FileUtils()42 FileUtils::FileUtils() {}
43 
~FileUtils()44 FileUtils::~FileUtils() {}
45 
DeleteFile(const string & fileName)46 int FileUtils::DeleteFile(const string &fileName)
47 {
48     int ret = remove(fileName.c_str());
49     if (ret < 0) {
50         MEDIA_ERR_LOG("DeleteFile fail, ret: %{public}d, errno: %{public}d", ret, errno);
51     }
52     return ret;
53 }
54 
IsFileExist(const string & fileName)55 bool FileUtils::IsFileExist(const string &fileName)
56 {
57     struct stat statInfo {};
58     return ((stat(fileName.c_str(), &statInfo)) == E_SUCCESS);
59 }
60 
SaveImage(const string & filePath,void * output,size_t writeSize)61 int32_t FileUtils::SaveImage(const string &filePath, void *output, size_t writeSize)
62 {
63     const mode_t fileMode = 0644;
64     MediaLibraryTracer tracer;
65     tracer.Start("FileUtils::SaveImage");
66     string filePathTemp = filePath + ".high";
67     int fd = open(filePathTemp.c_str(), O_CREAT|O_WRONLY|O_TRUNC, fileMode);
68     if (fd < 0) {
69         MEDIA_ERR_LOG("fd.Get() < 0 fd %{public}d errno: %{public}d", fd, errno);
70         return E_ERR;
71     }
72     MEDIA_DEBUG_LOG("filePath: %{private}s, fd: %{public}d", filePath.c_str(), fd);
73 
74     int ret = write(fd, output, writeSize);
75     close(fd);
76     if (ret < 0) {
77         MEDIA_ERR_LOG("write fail, ret: %{public}d, errno: %{public}d", ret, errno);
78         DeleteFile(filePathTemp);
79         return ret;
80     }
81 
82     ret = rename(filePathTemp.c_str(), filePath.c_str());
83     if (ret < 0) {
84         MEDIA_ERR_LOG("rename fail, ret: %{public}d, errno: %{public}d", ret, errno);
85         DeleteFile(filePathTemp);
86         return ret;
87     }
88 
89     return ret;
90 }
91 
SavePicture(const string & imageId,std::shared_ptr<Media::Picture> & picture,bool isEdited,bool isLowQualityPicture)92 int32_t FileUtils::SavePicture(const string &imageId, std::shared_ptr<Media::Picture> &picture,
93     bool isEdited, bool isLowQualityPicture)
94 {
95     MediaLibraryTracer tracer;
96     // 通过imageid获取fileid 获取uri
97     if (picture == nullptr) {
98         return -1;
99     }
100     MEDIA_INFO_LOG("photoid: %{public}s", imageId.c_str());
101     MediaLibraryCommand cmd(OperationObject::FILESYSTEM_PHOTO, OperationType::QUERY);
102     string where = PhotoColumn::PHOTO_ID + " = ? ";
103     vector<string> whereArgs { imageId };
104     cmd.GetAbsRdbPredicates()->SetWhereClause(where);
105     cmd.GetAbsRdbPredicates()->SetWhereArgs(whereArgs);
106     vector<string> columns { MediaColumn::MEDIA_ID, MediaColumn::MEDIA_FILE_PATH, PhotoColumn::PHOTO_EDIT_TIME,
107         PhotoColumn::PHOTO_SUBTYPE, MediaColumn::MEDIA_MIME_TYPE};
108     tracer.Start("Query");
109     auto resultSet = DatabaseAdapter::Query(cmd, columns);
110     if (resultSet == nullptr || resultSet->GoToFirstRow() != E_OK) {
111         tracer.Finish();
112         MEDIA_INFO_LOG("result set is empty");
113         return -1;
114     }
115     tracer.Finish();
116     string path = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
117     int fileId = GetInt32Val(MediaColumn::MEDIA_ID, resultSet);
118     string sourcePath = isEdited ? MediaLibraryAssetOperations::GetEditDataSourcePath(path) : path;
119     //查询是否编辑 编辑目录下
120     string mime_type = GetStringVal(MediaColumn::MEDIA_MIME_TYPE, resultSet);
121     resultSet->Close();
122     if (mime_type == "") {
123         mime_type = "image/jpeg";
124     }
125     size_t sizeHeic = -1;
126     size_t pos = sourcePath.find_last_of('.');
127     string pathPos = sourcePath.substr(0, pos);
128     string pathHeic = pathPos + ".heic";
129     MediaFileUtils::GetFileSize(pathHeic, sizeHeic);
130     size_t sizeJpeg = -1;
131     string pathJpeg = pathPos + ".jpeg";
132     MediaFileUtils::GetFileSize(pathJpeg, sizeJpeg);
133 
134     if (isLowQualityPicture && (sizeHeic > 0 || sizeJpeg > 0)) {
135         return -1;
136     }
137 
138     int ret = DealPicture(mime_type, sourcePath, picture, !isLowQualityPicture);
139     return ret;
140 }
141 
SavePicture(const string & path,std::shared_ptr<Media::Picture> & picture,const std::string & mime_type,bool isHighQualityPicture)142 int32_t FileUtils::SavePicture(const string &path, std::shared_ptr<Media::Picture> &picture,
143     const std::string &mime_type, bool isHighQualityPicture)
144 {
145     MEDIA_INFO_LOG("SavePicture width %{public}d, heigh %{public}d, mime_type %{public}sd",
146         picture->GetMainPixel()->GetWidth(), picture->GetMainPixel()->GetHeight(), mime_type.c_str());
147     return DealPicture(mime_type, path, picture, isHighQualityPicture);
148 }
149 
DealPicture(const std::string & mime_type,const std::string & path,std::shared_ptr<Media::Picture> & picture,bool isHighQualityPicture)150 int32_t FileUtils::DealPicture(const std::string &mime_type, const std::string &path,
151     std::shared_ptr<Media::Picture> &picture, bool isHighQualityPicture)
152 {
153     MEDIA_DEBUG_LOG("DealPicture %{public}s", path.c_str());
154     if (picture == nullptr) {
155         return -1;
156     }
157     Media::ImagePacker imagePacker;
158     Media::PackOption packOption;
159     packOption.format = (mime_type == MIME_TYPE_HEIC) ? MIME_TYPE_HEIF : mime_type;
160     packOption.needsPackProperties = true;
161     packOption.desiredDynamicRange = EncodeDynamicRange::AUTO;
162     packOption.isEditScene = false;
163     size_t lastSlash = path.rfind('/');
164     CHECK_AND_RETURN_RET_LOG(lastSlash != string::npos && path.size() > (lastSlash + 1), E_INVALID_VALUES,
165         "Failed to check outputPath: %{public}s", path.c_str());
166     string tempInternal = isHighQualityPicture ? "high_" :"low_";
167     string tempOutputPath = path.substr(0, lastSlash) + tempInternal + path.substr(lastSlash + 1);
168     int32_t ret = MediaFileUtils::CreateAsset(tempOutputPath);
169     CHECK_AND_RETURN_RET_LOG(ret == E_SUCCESS, E_HAS_FS_ERROR,
170         "Failed to create temp filters file %{private}s", tempOutputPath.c_str());
171     imagePacker.StartPacking(tempOutputPath, packOption);
172     imagePacker.AddPicture(*(picture));
173     imagePacker.FinalizePacking();
174     size_t size = -1;
175     MediaFileUtils::GetFileSize(tempOutputPath, size);
176     MEDIA_DEBUG_LOG("SavePicture end {public}%zu", size);
177     if (size == 0) {
178         CHECK_AND_PRINT_LOG(MediaFileUtils::DeleteFile(tempOutputPath),
179             "Failed to delete temp filters file, errno: %{public}d", errno);
180         return E_OK;
181     }
182     ret = rename(tempOutputPath.c_str(), path.c_str());
183     if (MediaFileUtils::IsFileExists(tempOutputPath)) {
184         MEDIA_INFO_LOG("file: %{public}s exists and needs to be deleted", tempOutputPath.c_str());
185         if (!MediaFileUtils::DeleteFile(tempOutputPath)) {
186             MEDIA_ERR_LOG("delete file: %{public}s failed", tempOutputPath.c_str());
187         }
188     }
189     return ret;
190 }
191 
SaveVideo(const std::string & filePath,bool isEdited)192 int32_t FileUtils::SaveVideo(const std::string &filePath, bool isEdited)
193 {
194     string tempPath = filePath.substr(0, filePath.rfind('.')) + "_tmp" + filePath.substr(filePath.rfind('.'));
195     string targetPath = filePath;
196     if (isEdited) {
197         targetPath = MediaLibraryAssetOperations::GetEditDataSourcePath(filePath);
198     }
199 
200     if (!IsFileExist(filePath)) {
201         MEDIA_INFO_LOG("file not exist: %{public}s", filePath.c_str());
202     }
203 
204     if (!IsFileExist(tempPath)) {
205         MEDIA_INFO_LOG("file not exist: %{public}s", tempPath.c_str());
206     }
207 
208     MEDIA_INFO_LOG("video rename targetPath: %{public}s, tempPath: %{public}s", targetPath.c_str(), tempPath.c_str());
209     return rename(tempPath.c_str(), targetPath.c_str());
210 }
211 
DeleteTempVideoFile(const std::string & filePath)212 int32_t FileUtils::DeleteTempVideoFile(const std::string &filePath)
213 {
214     MEDIA_INFO_LOG("filePath: %{public}s", filePath.c_str());
215     string tempPath = filePath.substr(0, filePath.rfind('.')) + "_tmp" + filePath.substr(filePath.rfind('.'));
216     if (IsFileExist(tempPath)) {
217         return DeleteFile(tempPath);
218     }
219     return E_OK;
220 }
221 } // namespace Media
222 } // namespace OHOS