1 /*
2 * Copyright (c) 2021 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 "raw_maker.h"
17
18 #include <cerrno>
19 #include <string>
20
21 #include <gslogger.h>
22 #include <securec.h>
23 #include <zlib.h>
24
25 namespace OHOS {
26 namespace {
27 DEFINE_HILOG_LABEL("RawMaker");
28 } // namespace
29
SetFilename(const std::string & filename)30 void RawMaker::SetFilename(const std::string &filename)
31 {
32 if (firstFrame) {
33 this->filename = filename;
34 }
35 if (this->filename != filename) {
36 GSLOG2HI(ERROR) << "RawMaker::SetFilename now filename is different to first frame filename";
37 }
38 }
39
SetWidth(uint32_t width)40 void RawMaker::SetWidth(uint32_t width)
41 {
42 if (firstFrame) {
43 this->width = width;
44 }
45 if (this->width != width) {
46 GSLOG2HI(ERROR) << "RawMaker::SetWidth now width is different to first frame width";
47 }
48 size = static_cast<int32_t>(width * height * 0x4);
49 }
50
SetHeight(uint32_t height)51 void RawMaker::SetHeight(uint32_t height)
52 {
53 if (firstFrame) {
54 this->height = height;
55 }
56 if (this->height != height) {
57 GSLOG2HI(ERROR) << "RawMaker::SetHeight now height is different to first frame height";
58 }
59 size = static_cast<int32_t>(width * height * 0x4);
60 }
61
SetHeaderType(RawHeaderType type)62 void RawMaker::SetHeaderType(RawHeaderType type)
63 {
64 this->type = type;
65 if (type != RAW_HEADER_TYPE_NONE) {
66 GSLOG2HI(ERROR) << "RawMaker::SetHeaderType now type is not RAW_HEADER_TYPE_NONE";
67 }
68 }
69
WriteNextData(const uint8_t * addr)70 int32_t RawMaker::WriteNextData(const uint8_t *addr)
71 {
72 int32_t ret = 0;
73 if (firstFrame) {
74 ret = DoFirstFrame();
75 writing.offset = 0;
76 writing.length = size;
77 } else {
78 CompareWithLastFrame(addr);
79 }
80
81 ofs.open(filename, std::ofstream::app | std::ofstream::binary | std::ofstream::out);
82 if (errno) {
83 GSLOG2HI(ERROR) << "open " << filename << ", because " << strerror(errno);
84 return errno;
85 }
86
87 if (writing.length == 0) {
88 ret = PrepareInNone();
89 } else if (type == RAW_HEADER_TYPE_RAW) {
90 ret = PrepareInRaw(addr);
91 } else if (type == RAW_HEADER_TYPE_COMPRESSED) {
92 ret = PrepareInCompress(addr);
93 }
94
95 if (ret) {
96 GSLOG2SO(ERROR) << "failed at prepare";
97 ofs.close();
98 return ret;
99 }
100
101 WriteData();
102 ofs.close();
103 return 0;
104 }
105
PrepareInNone()106 int32_t RawMaker::PrepareInNone()
107 {
108 writing.type = RAW_HEADER_TYPE_NONE;
109 writing.offset = 0;
110 writing.length = 0;
111 writing.compressedLength = 0;
112 writing.data = nullptr;
113 return 0;
114 }
115
PrepareInRaw(const uint8_t * addr)116 int32_t RawMaker::PrepareInRaw(const uint8_t *addr)
117 {
118 writing.type = RAW_HEADER_TYPE_RAW;
119 writing.compressedLength = writing.length;
120 writing.data = addr + writing.offset;
121 return UpdateLastFrame(addr);
122 }
123
PrepareInCompress(const uint8_t * addr)124 int32_t RawMaker::PrepareInCompress(const uint8_t *addr)
125 {
126 writing.type = RAW_HEADER_TYPE_COMPRESSED;
127
128 uLongf clen = compressBound(writing.length);
129 compressed = std::make_unique<uint8_t[]>(clen);
130 auto ret = compress(compressed.get(), &clen, addr + writing.offset, writing.length);
131 if (ret != Z_OK) {
132 GSLOG2HI(ERROR) << "compress failed with " << ret;
133 return ret;
134 }
135
136 writing.compressedLength = static_cast<int32_t>(clen);
137 writing.data = compressed.get();
138 return UpdateLastFrame(addr);
139 }
140
UpdateLastFrame(const uint8_t * addr)141 int32_t RawMaker::UpdateLastFrame(const uint8_t *addr)
142 {
143 auto dst = lastFrame.get() + writing.offset;
144 auto dstlen = size - writing.offset;
145 auto src = writing.data;
146 auto srclen = writing.length;
147 auto ret = memcpy_s(dst, dstlen, src, srclen);
148 if (ret) {
149 GSLOG2HI(ERROR) << "memcpy_s failed with <" << strerror(errno) << ">"
150 << ", params: " << "dstlen(" << dstlen << "), srclen(" << srclen << ")";
151 return ret;
152 }
153 return 0;
154 }
155
WriteData()156 int32_t RawMaker::WriteData()
157 {
158 WriteInt32(writing.type);
159 WriteInt32(writing.offset);
160 WriteInt32(writing.length);
161 WriteInt32(writing.compressedLength);
162 ofs.write(reinterpret_cast<const char *>(writing.data), writing.compressedLength);
163
164 int32_t align = writing.compressedLength % 0x4;
165 while (align) {
166 align = (align + 1) % 0x4;
167 ofs.write("\0", 1);
168 }
169 return 0;
170 }
171
WriteInt32(int32_t integer)172 void RawMaker::WriteInt32(int32_t integer)
173 {
174 ofs.write(reinterpret_cast<const char *>(&integer), sizeof(integer));
175 }
176
CompareWithLastFrame(const uint8_t * addr)177 void RawMaker::CompareWithLastFrame(const uint8_t *addr)
178 {
179 writing.length = 0;
180 writing.offset = size;
181 for (int32_t i = 0; i < size; i++) {
182 if (addr[i] != lastFrame[i]) {
183 writing.offset = i;
184 break;
185 }
186 }
187
188 for (int32_t i = size - 1; i >= writing.offset; i++) {
189 if (addr[i] != lastFrame[i]) {
190 writing.length = i - writing.offset + 1;
191 break;
192 }
193 }
194 }
195
DoFirstFrame()196 int32_t RawMaker::DoFirstFrame()
197 {
198 firstFrame = false;
199 ofs.open(filename, std::ofstream::trunc | std::ofstream::binary | std::ofstream::out);
200 if (errno) {
201 GSLOG2HI(ERROR) << "open " << filename << ", because " << strerror(errno);
202 return errno;
203 }
204
205 lastFrame = std::make_unique<uint8_t[]>(static_cast<uint32_t>(size));
206 ofs.write("RAW.dif2", 0x8);
207 WriteInt32(static_cast<int32_t>(width));
208 WriteInt32(height);
209 ofs.close();
210 return 0;
211 }
212 } // namespace OHOS
213