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 #include "config.h"
17 #include "exif-mnote-data-huawei.h"
18 #include "mnote-huawei-entry.h"
19 #include "mnote-huawei-tag.h"
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <math.h>
25
26 #include <libexif/exif-format.h>
27 #include <libexif/exif-utils.h>
28 #include <libexif/i18n.h>
29
30 char *
mnote_huawei_entry_get_value(MnoteHuaweiEntry * e,char * v,unsigned int maxlen)31 mnote_huawei_entry_get_value(MnoteHuaweiEntry *e, char *v, unsigned int maxlen)
32 {
33 if (!v)
34 return NULL;
35
36 memset(v, 0, maxlen);
37 int write_pos = 0;
38 ExifLong data = 0;
39
40 if (e->format == EXIF_FORMAT_ASCII) {
41 snprintf(v, maxlen, _("%s"), e->data);
42 return v;
43 }
44
45 if (e->tag == MNOTE_MICRO_VIDEO_PRESENTATION_TIMESTAMP_US) {
46 for (int i = 0; i < e->components && write_pos < maxlen; i++) {
47 int offset = i * exif_format_get_size(e->format);
48 ExifRational r = exif_get_rational(e->data + offset, e->order);
49 if (r.denominator == 0) {
50 write_pos += snprintf(v + write_pos, maxlen - write_pos, "%u ",
51 r.numerator);
52 } else {
53 write_pos += snprintf(v + write_pos, maxlen - write_pos, "%u%u ",
54 r.numerator, r.denominator);
55 }
56 }
57 *(v + write_pos - 1) = 0;
58 return v;
59 }
60
61 for (int i = 0; i < e->components && write_pos < maxlen; i++) {
62 if (e->format == EXIF_FORMAT_UNDEFINED) {
63 data = (e->data + i)[0];
64 } else if (e->format == EXIF_FORMAT_SLONG) {
65 data = exif_get_slong(e->data + i * 4, e->order);
66 } else if (e->format == EXIF_FORMAT_LONG) {
67 data = exif_get_long(e->data + i * 4, e->order);
68 } else {
69 snprintf(v, maxlen, _("unsupported data types: %d"), e->format);
70 return NULL;
71 }
72
73 write_pos += snprintf(v + write_pos, maxlen - write_pos, "%d ", data);
74 }
75
76 *(v + write_pos - 1) = 0;
77 return v;
78 }
79
80 int
mnote_huawei_entry_rational_timestamp_process(char * buff,const int buff_size,const char * v,int strlen,int * components,ExifMem * mem,ExifByteOrder order)81 mnote_huawei_entry_rational_timestamp_process(char *buff, const int buff_size, const char *v, int strlen,
82 int *components, ExifMem *mem, ExifByteOrder order)
83 {
84 char *token = NULL, *pv = NULL;
85 int components_local = 0, components_size = 0, ret = 0;
86 const int increment = 8;
87
88 pv = exif_mem_alloc(mem, strlen + 1);
89 if (!pv) {
90 ret = -1;
91 goto FINISH;
92 }
93 *(pv + strlen) = 0;
94 memcpy(pv, v, strlen);
95
96 token = strtok(pv, " ");
97 for (; token && components_size < buff_size;) {
98 int offset = increment * components_local;
99 char timestamp_buff[11] = {0};
100 snprintf(timestamp_buff, sizeof(timestamp_buff), "%s", token);
101 unsigned long numerator = strtoul(timestamp_buff, NULL, 10);
102
103 snprintf(timestamp_buff, 8, "%s", token+10);
104 unsigned long denominator = strtoul(timestamp_buff, NULL, 10);
105
106 ExifRational r = {
107 .numerator = numerator,
108 .denominator = denominator,
109 };
110
111 exif_set_rational((unsigned char*)buff + offset, order, r);
112 components_local++;
113 components_size = components_local * increment;
114 token = strtok(NULL, " ");
115 }
116
117 FINISH:
118 *components = components_local;
119 if (!components_local)
120 ret = -1;
121 if (pv)
122 exif_mem_free(mem, pv);
123 return ret;
124 }
125
126 int
mnote_huawei_entry_string_process(char * buff,const int buff_size,const char * v,int strlen,int * components)127 mnote_huawei_entry_string_process(char *buff, const int buff_size, const char *v, int strlen,
128 int *components)
129 {
130 int ret = 0;
131 *components = snprintf(buff, buff_size, _("%s"), v);
132 if (!(*components))
133 ret = -1;
134 else {
135 *components = *components + 1;
136 }
137 return ret;
138 }
139
140 int
mnote_huawei_entry_value_process(char * buff,const int buff_size,const char * v,int strlen,const int increment,int * components,ExifMem * mem,ExifByteOrder order)141 mnote_huawei_entry_value_process(char *buff, const int buff_size, const char *v, int strlen,
142 const int increment, int *components, ExifMem *mem, ExifByteOrder order)
143 {
144 char *token = NULL, *pv = NULL;
145 int components_local = 0, components_size = 0, ret = 0;
146
147 pv = exif_mem_alloc(mem, strlen + 1);
148 if (!pv) {
149 ret = -1;
150 goto FINISH;
151 }
152 *(pv + strlen) = 0;
153 memcpy(pv, v, strlen);
154
155 token = strtok(pv, " ");
156 for (; token && components_size < buff_size;) {
157 int value = atoi(token);
158 int offset = increment * components_local;
159 if (increment == 1) {
160 if (value > 0xff || value < 0) {
161 ret = -1;
162 goto FINISH;
163 }
164 *(buff + offset) = value;
165 } else {
166 exif_set_slong((unsigned char*)(buff + offset), order, value);
167 }
168 components_local++;
169 components_size = components_local * increment;
170 token = strtok(NULL, " ");
171 }
172
173 FINISH:
174 *components = components_local;
175 if (!components_local)
176 ret = -1;
177 if (pv)
178 exif_mem_free(mem, pv);
179 return ret;
180 }
181
182 int
mnote_huawei_entry_set_value(MnoteHuaweiEntry * e,const char * v,int strlen)183 mnote_huawei_entry_set_value(MnoteHuaweiEntry *e, const char *v, int strlen)
184 {
185 char data[1024] = {0};
186 int increment = 0, components = 0, components_size = 0, ret = 0;
187
188 if (!e || !v || e->md) {
189 ret = -1;
190 goto FINISH;
191 }
192
193 if (e->format == EXIF_FORMAT_UNDEFINED || e->format == EXIF_FORMAT_ASCII) {
194 increment = 1;
195 } else if (e->format == EXIF_FORMAT_SLONG || e->format == EXIF_FORMAT_LONG) {
196 increment = 4;
197 } else if (e->format == EXIF_FORMAT_RATIONAL || e->format == EXIF_FORMAT_SRATIONAL) {
198 increment = 8;
199 } else {
200 ret = -1;
201 goto FINISH;
202 }
203
204 if (e->tag == MNOTE_MICRO_VIDEO_PRESENTATION_TIMESTAMP_US) {
205 ret = mnote_huawei_entry_rational_timestamp_process(data, sizeof(data), v, strlen,
206 &components, e->mem, e->order);
207 } else if (e->format == EXIF_FORMAT_ASCII) {
208 ret = mnote_huawei_entry_string_process(data, sizeof(data), v, strlen, &components);
209 } else {
210 ret = mnote_huawei_entry_value_process(data, sizeof(data), v, strlen, increment,
211 &components, e->mem, e->order);
212 }
213
214 if (ret) {
215 goto FINISH;
216 }
217
218 components_size = increment * components;
219 if (e->size < components_size) {
220 unsigned char *realloc = exif_mem_realloc(e->mem, e->data, components_size);
221 if (!realloc) {
222 ret = -1;
223 goto FINISH;
224 }
225 e->data = realloc;
226 e->size = components_size;
227 }
228
229 e->components = components;
230 memcpy(e->data, data, components_size);
231
232 FINISH:
233 return ret;
234 }
235
236 MnoteHuaweiEntry *
mnote_huawei_entry_new(ExifMnoteData * n)237 mnote_huawei_entry_new(ExifMnoteData *n)
238 {
239 if (!is_huawei_md(n))
240 return NULL;
241 ExifMem *mem = n->mem;
242 MnoteHuaweiEntry *e = exif_mem_alloc(mem, sizeof(MnoteHuaweiEntry));
243 if (!e)
244 return e;
245 e->mem = mem;
246 return e;
247 }
248
249 void
mnote_huawei_entry_replace_mem(MnoteHuaweiEntry * e,ExifMem * mem)250 mnote_huawei_entry_replace_mem(MnoteHuaweiEntry *e, ExifMem *mem)
251 {
252 if (!e || !mem)
253 return;
254 if (e->mem == mem)
255 return;
256 exif_mem_unref(e->mem);
257 e->mem = mem;
258 return;
259 }
260
261 void
mnote_huawei_entry_free_content(MnoteHuaweiEntry * e)262 mnote_huawei_entry_free_content(MnoteHuaweiEntry *e)
263 {
264 if (!e)
265 return;
266 if (e->data)
267 exif_mem_free(e->mem, e->data);
268 if (e->md)
269 exif_mnote_data_huawei_clear((ExifMnoteDataHuawei*) e->md);
270 }
271
272 void
mnote_huawei_entry_free_contour(MnoteHuaweiEntry * e)273 mnote_huawei_entry_free_contour(MnoteHuaweiEntry *e)
274 {
275 if (!e)
276 return;
277 exif_mem_free(e->mem, e);
278 }
279
280 void
mnote_huawei_entry_free(MnoteHuaweiEntry * e)281 mnote_huawei_entry_free(MnoteHuaweiEntry *e)
282 {
283 if (!e)
284 return;
285 mnote_huawei_entry_free_content(e);
286 exif_mem_free(e->mem, e);
287 }
288
289 static void *
mnote_huawei_entry_alloc(MnoteHuaweiEntry * e,unsigned int i)290 mnote_huawei_entry_alloc (MnoteHuaweiEntry *e, unsigned int i)
291 {
292 if (!e || !i) return NULL;
293 void *p = exif_mem_alloc (e->mem, i);
294 if (p) memset(p, 0, i);
295 return p;
296 }
297
298 static void
clear_mnote_huawei_entry(MnoteHuaweiEntry * e)299 clear_mnote_huawei_entry (MnoteHuaweiEntry *e)
300 {
301 e->components = 0;
302 e->size = 0;
303 }
304
305 void
mnote_huawei_entry_initialize(MnoteHuaweiEntry * e,MnoteHuaweiTag tag,ExifByteOrder order)306 mnote_huawei_entry_initialize(MnoteHuaweiEntry *e, MnoteHuaweiTag tag, ExifByteOrder order)
307 {
308 if (!e || e->data)
309 return;
310 e->tag = tag;
311 e->order = order;
312 switch (tag) {
313 case MNOTE_HUAWEI_SCENE_INFO:
314 case MNOTE_HUAWEI_FACE_INFO:
315 case MNOTE_HUAWEI_CAPTURE_MODE:
316 case MNOTE_HUAWEI_BURST_NUMBER:
317 case MNOTE_HUAWEI_FRONT_CAMERA:
318 case MNOTE_HUAWEI_PHYSICAL_APERTURE:
319 case MNOTE_MOVING_PHOTO_VERSION:
320 case MNOTE_HUAWEI_FACE_VERSION:
321 case MNOTE_HUAWEI_FACE_COUNT:
322 case MNOTE_HUAWEI_FACE_CONF:
323 case MNOTE_HUAWEI_SCENE_VERSION:
324 case MNOTE_HUAWEI_SCENE_FOOD_CONF:
325 case MNOTE_HUAWEI_SCENE_STAGE_CONF:
326 case MNOTE_HUAWEI_SCENE_BLUESKY_CONF:
327 case MNOTE_HUAWEI_SCENE_GREENPLANT_CONF:
328 case MNOTE_HUAWEI_SCENE_BEACH_CONF:
329 case MNOTE_HUAWEI_SCENE_SNOW_CONF:
330 case MNOTE_HUAWEI_SCENE_SUNSET_CONF:
331 case MNOTE_HUAWEI_SCENE_FLOWERS_CONF:
332 case MNOTE_HUAWEI_SCENE_NIGHT_CONF:
333 case MNOTE_HUAWEI_SCENE_TEXT_CONF:
334 e->components = 1;
335 e->format = EXIF_FORMAT_LONG;
336 e->size = e->components * exif_format_get_size(e->format);
337 e->data = mnote_huawei_entry_alloc(e, e->size);
338 if (!e->data) { clear_mnote_huawei_entry(e); break; }
339 break;
340 case MNOTE_HUAWEI_ROLL_ANGLE:
341 case MNOTE_HUAWEI_PITCH_ANGLE:
342 case MNOTE_HUAWEI_FOCUS_MODE:
343 e->components = 1;
344 e->format = EXIF_FORMAT_SLONG;
345 e->size = e->components * exif_format_get_size(e->format);
346 e->data = mnote_huawei_entry_alloc(e, e->size);
347 if (!e->data) { clear_mnote_huawei_entry(e); break; }
348 break;
349
350 case MNOTE_MOVING_PHOTO_ID:
351 e->components = sizeof("[None]");
352 e->format = EXIF_FORMAT_ASCII;
353 e->size = e->components * exif_format_get_size(e->format);
354 e->data = mnote_huawei_entry_alloc(e, e->size);
355 if (!e->data) { clear_mnote_huawei_entry(e); break; }
356 snprintf((char*)e->data, e->size, "%s", "[None]");
357 break;
358
359 case MNOTE_MICRO_VIDEO_PRESENTATION_TIMESTAMP_US:
360 e->components = 8;
361 e->format = EXIF_FORMAT_RATIONAL;
362 e->size = e->components * exif_format_get_size(e->format);
363 e->data = mnote_huawei_entry_alloc(e, e->size);
364 if (!e->data) { clear_mnote_huawei_entry(e); break; }
365 memset(e->data, 0, e->size);
366 break;
367
368 case MNOTE_HUAWEI_FACE_SMILE_SCORE:
369 case MNOTE_HUAWEI_FACE_RECT:
370 case MNOTE_HUAWEI_FACE_LEYE_CENTER:
371 case MNOTE_HUAWEI_FACE_REYE_CENTER:
372 case MNOTE_HUAWEI_FACE_MOUTH_CENTER:
373 e->components = 1;
374 e->format = EXIF_FORMAT_UNDEFINED;
375 e->size = e->components * exif_format_get_size(e->format);
376 e->data = mnote_huawei_entry_alloc(e, e->size);
377 if (!e->data) { clear_mnote_huawei_entry(e); break; }
378 break;
379
380 default:
381 e->components = 0;
382 e->format = EXIF_FORMAT_UNDEFINED;
383 e->size = 0;
384 e->data = NULL;
385 break;
386 }
387 }