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 
16 #ifndef FRAMEWORKS_INNERKITSIMPL_ACCESSOR_INCLUDE_METADATA_STREAM_H
17 #define FRAMEWORKS_INNERKITSIMPL_ACCESSOR_INCLUDE_METADATA_STREAM_H
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <fstream>
22 #include <string>
23 #include <vector>
24 
25 #include "image_log.h"
26 #include "image_utils.h"
27 
28 namespace OHOS {
29 namespace Media {
30 enum SeekPos {
31     BEGIN,
32     CURRENT,
33     END
34 };
35 
36 using byte = uint8_t;
37 
38 constexpr int METADATA_STREAM_INVALID_FD = -1;
39 const std::string METADATA_STREAM_INVALID_PATH = "";
40 
41 enum class OpenMode {
42     Read,     // Read mode
43     ReadWrite // Read-write mode
44 };
45 
46 /**
47  * Considering that the size of exif fields often exceeds 4K and is less than 32K,
48  * we set the increment of memory to 32K each time to minimize memory allocation.
49  */
50 constexpr int METADATA_STREAM_PAGE_SIZE = 4096 * 8;
51 constexpr int METADATA_STREAM_ERROR_BUFFER_SIZE = 255;
52 
53 /**
54  * Considering that the circuitry of solid-state storage is of a low-speed multi-concurrent form,
55  * we use a larger read/write buffer to activate the potential for concurrent read/write operations of the circuit,
56  * thereby increasing I/O throughput.
57  */
58 constexpr int METADATA_STREAM_COPY_FROM_BUFFER_SIZE = 4096 * 32;
59 
60 /**
61  * @class MetadataStream
62  * @brief A class for handling image streams.
63  *
64  * This class provides methods for reading from and seeking within an image stream.
65  * The maximum file size that can be handled depends on the system and compiler:
66  * - On a 32-bit system, the maximum file size is 2GB.
67  * - On a 64-bit system, the maximum file size depends on whether 'long' is compiled as 32-bit or 64-bit.
68  * If 'long' is 32-bit, the maximum file size is 2GB.
69  * If 'long' is 64-bit, the maximum file size is 8ZB (Zettabytes).
70  */
71 class MetadataStream {
72 public:
~MetadataStream()73     virtual ~MetadataStream() {}
74 
75     /* *
76      * Open the image stream with a specific mode.
77      * For FileMetadataStream, OpenMode::ReadWrite and OpenMode::Read have distinct behaviors.
78      * For BufferMetadataStream, only OpenMode::ReadWrite is applicable. If OpenMode::Read is
79      * passed, it will be ignored as there is no specific read-only mode implemented.
80      * @param mode The mode to open the image stream.
81      * @return true if it opens successfully, false otherwise.
82      */
83     virtual bool Open(OpenMode mode = OpenMode::ReadWrite) = 0;
84 
85     /* *
86      * Check if the image stream is open.
87      * For FileMetadataStream, this function is meaningful and checks if the file is open.
88      * For BufferMetadataStream, this function always returns true.
89      * @return true if it is open, false otherwise.
90      */
91     virtual bool IsOpen() = 0;
92 
93     /* *
94      * Flush the image stream. For FileMetadataStream, this function is used to clear the buffer and
95      * write the buffered data into the file. This operation ensures that all modifications are
96      * written to the file, so other FileMetadataStream objects opening the same file can see these
97      * modifications. For BufferMetadataStream, this function may not have a specific use as it might
98      * only operate data in memory and does not involve any file operations. However, it could still
99      * be used to trigger certain behaviors, such as notifying other objects that data has been
100      * modified, or releasing resources that are no longer needed.
101      * @return true if it flushes successfully, false otherwise
102      */
103     virtual bool Flush() = 0;
104 
105     /* *
106      * @brief Writes data to the image stream.
107      * @param data The data to be written.
108      * @param size The size of the data. The maximum size that can be written
109      * at once depends on the implementation. On 32-bit systems and above,
110      * a safe value is 2GB.
111      * @return The actual size of the data written. Returns -1 if an error
112      * occurred during writing.
113      */
114     virtual ssize_t Write(byte *data, ssize_t size) = 0;
115 
116     /* *
117      * Read data from the image stream
118      * @param buf The buffer to store the data read
119      * @param size The size of the data to be read
120      * @return The actual size of the data read, or -1 if an error occurred
121      */
122     virtual ssize_t Read(byte *buf, ssize_t size) = 0;
123 
124     /* *
125      * @brief Reads a byte from the image stream and moves the pointer to the next position.
126      * @return The byte read from the stream as a uint8_t. Returns -1 if an error occurred.
127      */
128     virtual int ReadByte() = 0;
129 
130     /* *
131      * Seek a specific position in the image stream
132      * @param offset The offset
133      * @param pos The starting position of the offset (from the head, current
134      * position, or tail)
135      * @return The new position. Returns -1 if an error occurred during seeking.
136      */
137     virtual long Seek(long offset, SeekPos pos) = 0;
138 
139     /* *
140      * Get the current position in the image stream
141      * @return The current position
142      */
143     virtual long Tell() = 0;
144 
145     /* *
146      * Check if the end of the image stream has been reached
147      * @return true if the end has been reached, false otherwise
148      */
149     virtual bool IsEof() = 0;
150 
151     /* *
152      * Create a memory map
153      * @param isWriteable If true, the created memory map will be writable;
154      * otherwise, the created memory map will be read-only.
155      * @return If the memory map is created successfully, return a pointer to
156      * the memory map; otherwise, return nullptr.
157      */
158     virtual byte *GetAddr(bool isWriteable = false) = 0;
159 
160     /* *
161      * Copy the entire content from the source MetadataStream to the current
162      * MetadataStream. After the copy operation, the current position of both the source
163      * MetadataStream and the current MetadataStream will be at their respective ends.
164      * @param src The source MetadataStream, this function will read data from this
165      * MetadataStream.
166      * @return true if the copy is successful, false otherwise.
167      */
168     virtual bool CopyFrom(MetadataStream &src) = 0;
169 
170     /* *
171      * Get the size of the MetadataStream
172      * @return The size of the MetadataStream
173      */
174     virtual ssize_t GetSize() = 0;
175 
176     /* *
177      * Get the size of the original file
178      * @return The size of the original file
179      */
GetOriginalSize()180     virtual size_t GetOriginalSize()
181     {
182         if (originalFd_ == METADATA_STREAM_INVALID_FD && originalPath_.empty()) {
183             return GetSize();
184         }
185 
186         size_t size = 0;
187         if (originalFd_ != METADATA_STREAM_INVALID_FD) {
188             ImageUtils::GetFileSize(originalFd_, size);
189         } else if (!originalPath_.empty()) {
190             ImageUtils::GetFileSize(originalPath_, size);
191         }
192         return size;
193     }
194 
195     /* *
196      * Check if the original file has been changed
197      * @return true if the original file has been changed, false otherwise
198      */
IsFileChanged()199     virtual bool IsFileChanged()
200     {
201         if (isFileChanged_) {
202             return isFileChanged_;
203         }
204         if (GetOriginalSize() < static_cast<size_t>(GetSize())) {
205             IMAGE_LOGE("MetadataStream:: Original file has been changed");
206             isFileChanged_ = true;
207         }
208         return isFileChanged_;
209     }
210 
211 protected:
212     /* *
213      * Original file path
214      */
215     std::string originalPath_ = METADATA_STREAM_INVALID_PATH;
216 
217     /* *
218      * Original file fd number
219      */
220     int originalFd_ = METADATA_STREAM_INVALID_FD;
221 
222     /* *
223      * Whether original file is changed
224      */
225     bool isFileChanged_ = false;
226 
227 private:
228     /* *
229      * Close the image stream
230      */
231     virtual void Close() = 0;
232 };
233 } // namespace Media
234 } // namespace OHOS
235 #endif // FRAMEWORKS_INNERKITSIMPL_ACCESSOR_INCLUDE_METADATA_STREAM_H
236