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