1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <android/persistable_bundle.h>
19 #include <log/log.h>
20 #include <utils/String8.h>
21 
22 //  take a vector and put the contents into a buffer.
23 //  return the size of the contents.
24 //  This may not put all of the contents into the buffer if the buffer is not
25 //  large enough.
26 template <typename T>
getVecInternal(const std::vector<T> & inVec,T * _Nullable buffer,int32_t bufferSizeBytes)27 int32_t getVecInternal(const std::vector<T>& inVec, T* _Nullable buffer, int32_t bufferSizeBytes) {
28     LOG_ALWAYS_FATAL_IF(inVec.size() > INT32_MAX,
29                         "The size of the APersistableBundle has gotten too large!");
30     LOG_ALWAYS_FATAL_IF(
31             bufferSizeBytes < 0,
32             "The buffer size in bytes can not be larger than INT32_MAX and can not be negative.");
33     int32_t num = inVec.size();
34     int32_t numAvailable = bufferSizeBytes / sizeof(T);
35     int32_t numFill = numAvailable < num ? numAvailable : num;
36 
37     if (numFill > 0 && buffer) {
38         for (int32_t i = 0; i < numFill; i++) {
39             buffer[i] = inVec[i];
40         }
41     }
42     return num * sizeof(T);
43 }
44 
45 //  take a vector or a set of String16 and put the contents into a char** buffer.
46 //  return the size of the contents.
47 //  This may not put all of the contents into the buffer if the buffer is not
48 //  large enough.
49 //  The strings are duped with a user supplied callback
50 template <typename T>
getStringsInternal(const T & strings,char * _Nullable * _Nullable buffer,int32_t bufferSizeBytes,APersistableBundle_stringAllocator stringAllocator,void * _Nullable context)51 int32_t getStringsInternal(const T& strings, char* _Nullable* _Nullable buffer,
52                            int32_t bufferSizeBytes,
53                            APersistableBundle_stringAllocator stringAllocator,
54                            void* _Nullable context) {
55     LOG_ALWAYS_FATAL_IF(strings.size() > INT32_MAX,
56                         "The size of the APersistableBundle has gotten too large!");
57     LOG_ALWAYS_FATAL_IF(
58             bufferSizeBytes < 0,
59             "The buffer size in bytes can not be larger than INT32_MAX and can not be negative.");
60     int32_t num = strings.size();
61     int32_t numAvailable = bufferSizeBytes / sizeof(char*);
62     int32_t numFill = numAvailable < num ? numAvailable : num;
63     if (!stringAllocator) {
64         return APERSISTABLEBUNDLE_ALLOCATOR_FAILED;
65     }
66 
67     if (numFill > 0 && buffer) {
68         int32_t i = 0;
69         for (const auto& val : strings) {
70             android::String8 tmp8 = android::String8(val);
71             buffer[i] = stringAllocator(tmp8.bytes() + 1, context);
72             if (buffer[i] == nullptr) {
73                 return APERSISTABLEBUNDLE_ALLOCATOR_FAILED;
74             }
75             strncpy(buffer[i], tmp8.c_str(), tmp8.bytes() + 1);
76             i++;
77             if (i > numFill - 1) {
78                 // buffer is too small to keep going or this is the end of the
79                 // set
80                 break;
81             }
82         }
83     }
84     return num * sizeof(char*);
85 }
86