1 /*
2  * Copyright (C) 2024 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 #define MLOG_TAG "Scanner"
16 
17 #include "ringtone_scanner_db.h"
18 
19 #include "result_set_utils.h"
20 #include "rdb_errno.h"
21 #include "ringtone_errno.h"
22 #include "ringtone_file_utils.h"
23 #include "ringtone_log.h"
24 #include "ringtone_rdbstore.h"
25 
26 namespace OHOS {
27 namespace Media {
28 using namespace std;
29 using namespace OHOS::NativeRdb;
30 using namespace OHOS::DataShare;
GetFileBasicInfo(const string & path,unique_ptr<RingtoneMetadata> & ptr)31 int32_t RingtoneScannerDb::GetFileBasicInfo(const string &path, unique_ptr<RingtoneMetadata> &ptr)
32 {
33     vector<string> columns = {};
34     string whereClause = RINGTONE_COLUMN_DATA + " = ?";
35     vector<string> args = { path };
36 
37     Uri uri("");
38     RingtoneDataCommand cmd(uri, RINGTONE_TABLE, RingtoneOperationType::QUERY);
39     cmd.GetAbsRdbPredicates()->SetWhereClause(whereClause);
40     cmd.GetAbsRdbPredicates()->SetWhereArgs(args);
41 
42     shared_ptr<NativeRdb::ResultSet> resultSet;
43     int32_t ret = GetFileSet(cmd, columns, resultSet);
44     if (ret != E_OK) {
45         RINGTONE_ERR_LOG("Update operation failed. ret=%{public}d", ret);
46         return E_DB_FAIL;
47     }
48 
49     return FillMetadata(resultSet, ptr);
50 }
51 
GetVibrateFileBasicInfo(const string & path,unique_ptr<VibrateMetadata> & ptr)52 int32_t RingtoneScannerDb::GetVibrateFileBasicInfo(const string &path, unique_ptr<VibrateMetadata> &ptr)
53 {
54     vector<string> columns = {
55         VIBRATE_COLUMN_VIBRATE_ID, VIBRATE_COLUMN_SIZE, VIBRATE_COLUMN_DATE_MODIFIED, VIBRATE_COLUMN_TITLE,
56         VIBRATE_COLUMN_DATE_ADDED
57     };
58     string whereClause = VIBRATE_COLUMN_DATA + " = ?";
59     vector<string> args = { path };
60 
61     Uri uri("");
62     RingtoneDataCommand cmd(uri, VIBRATE_TABLE, RingtoneOperationType::QUERY);
63     cmd.GetAbsRdbPredicates()->SetWhereClause(whereClause);
64     cmd.GetAbsRdbPredicates()->SetWhereArgs(args);
65 
66     shared_ptr<NativeRdb::ResultSet> resultSet;
67     int32_t ret = GetFileSet(cmd, columns, resultSet);
68     if (ret != E_OK) {
69         RINGTONE_ERR_LOG("Update operation failed. ret=%{public}d", ret);
70         return E_DB_FAIL;
71     }
72 
73     return FillVibrateMetadata(resultSet, ptr);
74 }
75 
QueryRingtoneRdb(const string & whereClause,vector<string> & whereArgs,const vector<string> & columns,shared_ptr<NativeRdb::ResultSet> & resultSet,const string & tableName)76 int32_t RingtoneScannerDb::QueryRingtoneRdb(const string &whereClause, vector<string> &whereArgs,
77     const vector<string> &columns, shared_ptr<NativeRdb::ResultSet> &resultSet, const string &tableName)
78 {
79     auto rawRdb = RingtoneRdbStore::GetInstance()->GetRaw();
80     if (rawRdb == nullptr) {
81         RINGTONE_ERR_LOG("get raw rdb failed");
82         return E_RDB;
83     }
84 
85     AbsRdbPredicates absRdbPredicates(tableName);
86     absRdbPredicates.SetWhereClause(whereClause);
87     absRdbPredicates.SetWhereArgs(whereArgs);
88     resultSet = rawRdb->Query(absRdbPredicates, columns);
89     if (resultSet == nullptr) {
90         RINGTONE_ERR_LOG("return nullptr when query rdb");
91         return E_RDB;
92     }
93 
94     return E_OK;
95 }
96 
UpdateRingtoneRdb(ValuesBucket & values,const string & whereClause,vector<string> & whereArgs,const string & tableName)97 int32_t RingtoneScannerDb::UpdateRingtoneRdb(ValuesBucket &values, const string &whereClause,
98     vector<string> &whereArgs, const string &tableName)
99 {
100     auto rawRdb = RingtoneRdbStore::GetInstance()->GetRaw();
101     if (rawRdb == nullptr) {
102         RINGTONE_ERR_LOG("get raw rdb failed");
103         return E_RDB;
104     }
105     int32_t updateCount = 0;
106     int32_t result = rawRdb->Update(updateCount, tableName, values, whereClause, whereArgs);
107     if (result != NativeRdb::E_OK) {
108         RINGTONE_ERR_LOG("Update operation failed. Result %{public}d. Updated %{public}d", result, updateCount);
109         return E_DB_FAIL;
110     }
111     return updateCount;
112 }
113 
FillMetadata(const shared_ptr<NativeRdb::ResultSet> & resultSet,unique_ptr<RingtoneMetadata> & ptr)114 int32_t RingtoneScannerDb::FillMetadata(const shared_ptr<NativeRdb::ResultSet> &resultSet,
115     unique_ptr<RingtoneMetadata> &ptr)
116 {
117     std::vector<std::string> columnNames;
118     int32_t err = resultSet->GetAllColumnNames(columnNames);
119     if (err != NativeRdb::E_OK) {
120         RINGTONE_ERR_LOG("failed to get all column names");
121         return E_RDB;
122     }
123 
124     for (const auto &col : columnNames) {
125         ExtractMetaFromColumn(resultSet, ptr, col);
126     }
127 
128     return E_OK;
129 }
130 
FillVibrateMetadata(const shared_ptr<NativeRdb::ResultSet> & resultSet,unique_ptr<VibrateMetadata> & ptr)131 int32_t RingtoneScannerDb::FillVibrateMetadata(const shared_ptr<NativeRdb::ResultSet> &resultSet,
132     unique_ptr<VibrateMetadata> &ptr)
133 {
134     std::vector<std::string> columnNames;
135     int32_t err = resultSet->GetAllColumnNames(columnNames);
136     if (err != NativeRdb::E_OK) {
137         RINGTONE_ERR_LOG("failed to get all column names");
138         return E_RDB;
139     }
140 
141     for (const auto &col : columnNames) {
142         ExtractVibrateMetaFromColumn(resultSet, ptr, col);
143     }
144 
145     return E_OK;
146 }
147 
ExtractMetaFromColumn(const shared_ptr<NativeRdb::ResultSet> & resultSet,unique_ptr<RingtoneMetadata> & metadata,const std::string & col)148 void RingtoneScannerDb::ExtractMetaFromColumn(const shared_ptr<NativeRdb::ResultSet> &resultSet,
149     unique_ptr<RingtoneMetadata> &metadata, const std::string &col)
150 {
151     RingtoneResultSetDataType dataType = RingtoneResultSetDataType::DATA_TYPE_NULL;
152     RingtoneMetadata::RingtoneMetadataFnPtr requestFunc = nullptr;
153     auto itr = metadata->memberFuncMap_.find(col);
154     if (itr != metadata->memberFuncMap_.end()) {
155         dataType = itr->second.first;
156         requestFunc = itr->second.second;
157     } else {
158         RINGTONE_ERR_LOG("invalid column name %{private}s", col.c_str());
159         return;
160     }
161 
162     std::variant<int32_t, std::string, int64_t, double> data =
163         ResultSetUtils::GetValFromColumn<const shared_ptr<NativeRdb::ResultSet>>(col, resultSet, dataType);
164 
165     // Use the function pointer from map and pass data to fn ptr
166     if (requestFunc != nullptr) {
167         (metadata.get()->*requestFunc)(data);
168     }
169 }
170 
ExtractVibrateMetaFromColumn(const shared_ptr<NativeRdb::ResultSet> & resultSet,unique_ptr<VibrateMetadata> & metadata,const std::string & col)171 void RingtoneScannerDb::ExtractVibrateMetaFromColumn(const shared_ptr<NativeRdb::ResultSet> &resultSet,
172     unique_ptr<VibrateMetadata> &metadata, const std::string &col)
173 {
174     RingtoneResultSetDataType dataType = RingtoneResultSetDataType::DATA_TYPE_NULL;
175     VibrateMetadata::VibrateMetadataFnPtr requestFunc = nullptr;
176     auto itr = metadata->memberFuncMap_.find(col);
177     if (itr != metadata->memberFuncMap_.end()) {
178         dataType = itr->second.first;
179         requestFunc = itr->second.second;
180     } else {
181         RINGTONE_ERR_LOG("invalid column name %{private}s", col.c_str());
182         return;
183     }
184 
185     std::variant<int32_t, std::string, int64_t, double> data =
186         ResultSetUtils::GetValFromColumn<const shared_ptr<NativeRdb::ResultSet>>(col, resultSet, dataType);
187 
188     // Use the function pointer from map and pass data to fn ptr
189     if (requestFunc != nullptr) {
190         (metadata.get()->*requestFunc)(data);
191     }
192 }
193 
GetFileSet(RingtoneDataCommand & cmd,const vector<string> & columns,shared_ptr<NativeRdb::ResultSet> & resultSet)194 int32_t RingtoneScannerDb::GetFileSet(RingtoneDataCommand &cmd, const vector<string> &columns,
195     shared_ptr<NativeRdb::ResultSet> &resultSet)
196 {
197     auto rawRdb = RingtoneRdbStore::GetInstance()->GetRaw();
198     if (rawRdb == nullptr) {
199         RINGTONE_ERR_LOG("get raw rdb failed");
200         return E_RDB;
201     }
202     resultSet = rawRdb->Query(*cmd.GetAbsRdbPredicates(), columns);
203     if (resultSet == nullptr) {
204         RINGTONE_ERR_LOG("return nullptr when query rdb");
205         return E_RDB;
206     }
207 
208     int32_t rowCount = 0;
209     int32_t ret = resultSet->GetRowCount(rowCount);
210     if (ret != NativeRdb::E_OK) {
211         RINGTONE_ERR_LOG("failed to get row count");
212         return E_RDB;
213     }
214     if (rowCount == 0) {
215         return E_OK;
216     }
217 
218     ret = resultSet->GoToFirstRow();
219     if (ret != NativeRdb::E_OK) {
220         RINGTONE_ERR_LOG("failed to go to first row");
221         return E_RDB;
222     }
223     return E_OK;
224 }
225 
InsertDateAdded(const RingtoneMetadata & metadata,ValuesBucket & outValues)226 static void InsertDateAdded(const RingtoneMetadata &metadata, ValuesBucket &outValues)
227 {
228     int64_t dateAdded = metadata.GetDateAdded();
229     if (dateAdded == 0) {
230         int64_t dateTaken = metadata.GetDateTaken();
231         if (dateTaken == 0) {
232             int64_t dateModified = metadata.GetDateModified();
233             if (dateModified == 0) {
234                 dateAdded = RingtoneFileUtils::UTCTimeMilliSeconds();
235                 RINGTONE_WARN_LOG("Invalid dateAdded time, use current time instead: %{public}" PRId64, dateAdded);
236             } else {
237                 dateAdded = dateModified;
238                 RINGTONE_WARN_LOG("Invalid dateAdded time, use dateModified instead: %{public}" PRId64, dateAdded);
239             }
240         } else {
241             dateAdded = dateTaken * MSEC_TO_SEC;
242             RINGTONE_WARN_LOG("Invalid dateAdded time, use dateTaken instead: %{public}" PRId64, dateAdded);
243         }
244     }
245     outValues.PutLong(RINGTONE_COLUMN_DATE_ADDED, dateAdded);
246 }
247 
InsertVibrateDateAdded(const VibrateMetadata & metadata,ValuesBucket & outValues)248 static void InsertVibrateDateAdded(const VibrateMetadata &metadata, ValuesBucket &outValues)
249 {
250     int64_t dateAdded = metadata.GetDateAdded();
251     if (dateAdded == 0) {
252         int64_t dateTaken = metadata.GetDateTaken();
253         if (dateTaken == 0) {
254             int64_t dateModified = metadata.GetDateModified();
255             if (dateModified == 0) {
256                 dateAdded = RingtoneFileUtils::UTCTimeMilliSeconds();
257                 RINGTONE_WARN_LOG("Invalid dateAdded time, use current time instead: %{public}" PRId64, dateAdded);
258             } else {
259                 dateAdded = dateModified;
260                 RINGTONE_WARN_LOG("Invalid dateAdded time, use dateModified instead: %{public}" PRId64, dateAdded);
261             }
262         } else {
263             dateAdded = dateTaken * MSEC_TO_SEC;
264             RINGTONE_WARN_LOG("Invalid dateAdded time, use dateTaken instead: %{public}" PRId64, dateAdded);
265         }
266     }
267     outValues.PutLong(VIBRATE_COLUMN_DATE_ADDED, dateAdded);
268 }
269 
SetValuesFromMetaData(const RingtoneMetadata & metadata,ValuesBucket & values,bool isInsert)270 static void SetValuesFromMetaData(const RingtoneMetadata &metadata, ValuesBucket &values, bool isInsert)
271 {
272     values.PutString(RINGTONE_COLUMN_DATA, metadata.GetData());
273     values.PutLong(RINGTONE_COLUMN_SIZE, metadata.GetSize());
274     values.PutString(RINGTONE_COLUMN_DISPLAY_NAME, metadata.GetDisplayName());
275     values.PutString(RINGTONE_COLUMN_TITLE, metadata.GetTitle());
276     values.PutInt(RINGTONE_COLUMN_MEDIA_TYPE, metadata.GetMediaType());
277     values.PutInt(RINGTONE_COLUMN_TONE_TYPE, metadata.GetToneType());
278     values.PutString(RINGTONE_COLUMN_MIME_TYPE, metadata.GetMimeType());
279     values.PutInt(RINGTONE_COLUMN_SOURCE_TYPE, metadata.GetSourceType());
280     values.PutLong(RINGTONE_COLUMN_DATE_MODIFIED, metadata.GetDateModified());
281     values.PutLong(RINGTONE_COLUMN_DATE_TAKEN, metadata.GetDateTaken());
282     values.PutInt(RINGTONE_COLUMN_DURATION, metadata.GetDuration());
283     values.PutInt(RINGTONE_COLUMN_SHOT_TONE_TYPE, metadata.GetShotToneType());
284     values.PutInt(RINGTONE_COLUMN_SHOT_TONE_SOURCE_TYPE, metadata.GetShotToneSourceType());
285     values.PutInt(RINGTONE_COLUMN_NOTIFICATION_TONE_TYPE, metadata.GetNotificationToneType());
286     values.PutInt(RINGTONE_COLUMN_NOTIFICATION_TONE_SOURCE_TYPE, metadata.GetNotificationToneSourceType());
287     values.PutInt(RINGTONE_COLUMN_RING_TONE_TYPE, metadata.GetRingToneType());
288     values.PutInt(RINGTONE_COLUMN_RING_TONE_SOURCE_TYPE, metadata.GetRingToneSourceType());
289     values.PutInt(RINGTONE_COLUMN_ALARM_TONE_TYPE, metadata.GetAlarmToneType());
290     values.PutInt(RINGTONE_COLUMN_ALARM_TONE_SOURCE_TYPE, metadata.GetAlarmToneSourceType());
291 
292     if (isInsert) {
293         InsertDateAdded(metadata, values);
294         return;
295     }
296 }
297 
SetValuesFromVibrateMetaData(const VibrateMetadata & metadata,ValuesBucket & values,bool isInsert)298 static void SetValuesFromVibrateMetaData(const VibrateMetadata &metadata, ValuesBucket &values, bool isInsert)
299 {
300     values.PutString(VIBRATE_COLUMN_DATA, metadata.GetData());
301     values.PutLong(VIBRATE_COLUMN_SIZE, metadata.GetSize());
302     values.PutString(VIBRATE_COLUMN_DISPLAY_NAME, metadata.GetDisplayName());
303     values.PutString(VIBRATE_COLUMN_TITLE, metadata.GetTitle());
304     values.PutString(VIBRATE_COLUMN_DISPLAY_LANGUAGE, metadata.GetDisplayLanguage());
305     values.PutInt(VIBRATE_COLUMN_VIBRATE_TYPE, metadata.GetVibrateType());
306     values.PutInt(VIBRATE_COLUMN_SOURCE_TYPE, metadata.GetSourceType());
307     values.PutLong(VIBRATE_COLUMN_DATE_MODIFIED, metadata.GetDateModified());
308     values.PutLong(VIBRATE_COLUMN_DATE_TAKEN, metadata.GetDateTaken());
309     values.PutInt(VIBRATE_COLUMN_PLAY_MODE, metadata.GetPlayMode());
310 
311     if (isInsert) {
312         InsertVibrateDateAdded(metadata, values);
313     }
314 }
315 
UpdateMetadata(const RingtoneMetadata & metadata,string & tableName)316 int32_t RingtoneScannerDb::UpdateMetadata(const RingtoneMetadata &metadata, string &tableName)
317 {
318     int32_t updateCount = 0;
319     ValuesBucket values;
320     string whereClause = RINGTONE_COLUMN_TONE_ID + " = ?";
321     vector<string> whereArgs = { to_string(metadata.GetToneId()) };
322 
323     SetValuesFromMetaData(metadata, values, false);
324 
325     tableName = RINGTONE_TABLE;
326     auto rawRdb = RingtoneRdbStore::GetInstance()->GetRaw();
327     if (rawRdb == nullptr) {
328         RINGTONE_ERR_LOG("get raw rdb failed");
329         return E_RDB;
330     }
331     int32_t result = rawRdb->Update(updateCount, tableName, values, whereClause, whereArgs);
332     if (result != NativeRdb::E_OK || updateCount <= 0) {
333         RINGTONE_ERR_LOG("Update operation failed. Result %{public}d. Updated %{public}d", result, updateCount);
334         return E_DB_FAIL;
335     }
336     return updateCount;
337 }
338 
UpdateVibrateMetadata(const VibrateMetadata & metadata,string & tableName)339 int32_t RingtoneScannerDb::UpdateVibrateMetadata(const VibrateMetadata &metadata, string &tableName)
340 {
341     int32_t updateCount = 0;
342     ValuesBucket values;
343     string whereClause = VIBRATE_COLUMN_VIBRATE_ID + " = ?";
344     vector<string> whereArgs = { to_string(metadata.GetVibrateId()) };
345 
346     SetValuesFromVibrateMetaData(metadata, values, false);
347 
348     tableName = VIBRATE_TABLE;
349     auto rawRdb = RingtoneRdbStore::GetInstance()->GetRaw();
350     if (rawRdb == nullptr) {
351         RINGTONE_ERR_LOG("get raw rdb failed");
352         return E_RDB;
353     }
354     int32_t result = rawRdb->Update(updateCount, tableName, values, whereClause, whereArgs);
355     if (result != NativeRdb::E_OK || updateCount <= 0) {
356         RINGTONE_ERR_LOG("Update operation failed. Result %{public}d. Updated %{public}d", result, updateCount);
357         return E_DB_FAIL;
358     }
359     return updateCount;
360 }
361 
InsertMetadata(const RingtoneMetadata & metadata,string & tableName)362 int32_t RingtoneScannerDb::InsertMetadata(const RingtoneMetadata &metadata, string &tableName)
363 {
364     ValuesBucket values;
365     int32_t rowNum = 0;
366     tableName = RINGTONE_TABLE;
367 
368     SetValuesFromMetaData(metadata, values, true);
369     if (!InsertData(values, tableName, rowNum)) {
370         return E_DB_FAIL;
371     }
372 
373     return rowNum;
374 }
375 
InsertVibrateMetadata(const VibrateMetadata & metadata,string & tableName)376 int32_t RingtoneScannerDb::InsertVibrateMetadata(const VibrateMetadata &metadata, string &tableName)
377 {
378     ValuesBucket values;
379     int32_t rowNum = 0;
380     tableName = VIBRATE_TABLE;
381 
382     SetValuesFromVibrateMetaData(metadata, values, true);
383     if (!InsertData(values, tableName, rowNum)) {
384         return E_DB_FAIL;
385     }
386 
387     return rowNum;
388 }
389 
InsertData(const ValuesBucket values,const string & tableName,int32_t & rowNum)390 bool RingtoneScannerDb::InsertData(const ValuesBucket values, const string &tableName, int32_t &rowNum)
391 {
392     auto rawRdb = RingtoneRdbStore::GetInstance()->GetRaw();
393     if (rawRdb == nullptr) {
394         RINGTONE_ERR_LOG("get raw rdb failed");
395         return E_RDB;
396     }
397 
398     int64_t nRow = static_cast<int64_t>(rowNum);
399     int32_t result = rawRdb->Insert(nRow, tableName, values);
400     if (nRow <= 0) {
401         RINGTONE_ERR_LOG("Ringtone library Insert functionality is failed, rowNum %{public}ld", (long) nRow);
402         return false;
403     }
404 
405     if (result != NativeRdb::E_OK) {
406         RINGTONE_ERR_LOG("Ringtone library Insert functionality is failed, return %{public}d", result);
407         return false;
408     }
409 
410     if (nRow < std::numeric_limits<int32_t>::min() || nRow > std::numeric_limits<int32_t>::max()) {
411         return false;
412     }
413     rowNum = static_cast<int32_t>(nRow);
414 
415     return true;
416 }
417 } // namespace Media
418 } // namespace OHOS
419