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 "box/item_property_box.h"
17
18 #include <algorithm>
19
20 namespace {
21 const uint8_t LARGE_PROPERTY_INDEX_FLAG = 1;
22 }
23
24 namespace OHOS {
25 namespace ImagePlugin {
ParseContentChildren(HeifStreamReader & reader,uint32_t & recursionCount)26 heif_error HeifIprpBox::ParseContentChildren(HeifStreamReader &reader, uint32_t &recursionCount)
27 {
28 recursionCount++;
29 if (recursionCount > MAX_RECURSION_COUNT) {
30 return heif_error_too_many_recursion;
31 }
32 return ReadChildren(reader, recursionCount);
33 }
34
ParseContentChildren(HeifStreamReader & reader,uint32_t & recursionCount)35 heif_error HeifIpcoBox::ParseContentChildren(HeifStreamReader &reader, uint32_t &recursionCount)
36 {
37 recursionCount++;
38 if (recursionCount > MAX_RECURSION_COUNT) {
39 return heif_error_too_many_recursion;
40 }
41 return ReadChildren(reader, recursionCount);
42 }
43
GetProperties(uint32_t itemId,const std::shared_ptr<class HeifIpmaBox> & ipma,std::vector<std::shared_ptr<HeifBox>> & outProperties) const44 heif_error HeifIpcoBox::GetProperties(uint32_t itemId, const std::shared_ptr<class HeifIpmaBox> &ipma,
45 std::vector<std::shared_ptr<HeifBox>> &outProperties) const
46 {
47 const std::vector<PropertyAssociation> *propertyAssocs = ipma->GetProperties(itemId);
48 if (propertyAssocs == nullptr) {
49 return heif_error_property_not_found;
50 }
51
52 const auto &allProperties = GetChildren();
53 for (const PropertyAssociation &assoc: *propertyAssocs) {
54 if (assoc.propertyIndex > allProperties.size()) {
55 return heif_error_invalid_property_index;
56 }
57
58 if (assoc.propertyIndex > 0) {
59 outProperties.push_back(allProperties[assoc.propertyIndex - 1]);
60 }
61 }
62
63 return heif_error_ok;
64 }
65
GetProperty(heif_item_id itemId,const std::shared_ptr<class HeifIpmaBox> & ipma,uint32_t boxType) const66 std::shared_ptr<HeifBox> HeifIpcoBox::GetProperty(heif_item_id itemId,
67 const std::shared_ptr<class HeifIpmaBox> &ipma, uint32_t boxType) const
68 {
69 const std::vector<PropertyAssociation> *propertyAssocs = ipma->GetProperties(itemId);
70 if (propertyAssocs == nullptr) {
71 return nullptr;
72 }
73
74 const auto &allProperties = GetChildren();
75 for (const PropertyAssociation &assoc: *propertyAssocs) {
76 if (assoc.propertyIndex > allProperties.size() ||
77 assoc.propertyIndex == 0) {
78 return nullptr;
79 }
80
81 const auto &property = allProperties[assoc.propertyIndex - 1];
82 if (property->GetBoxType() == boxType) {
83 return property;
84 }
85 }
86
87 return nullptr;
88 }
89
ParseContent(HeifStreamReader & reader)90 heif_error HeifIpmaBox::ParseContent(HeifStreamReader &reader)
91 {
92 ParseFullHeader(reader);
93
94 uint32_t entryNum = reader.Read32();
95 for (uint32_t i = 0; i < entryNum && !reader.HasError() && !reader.IsAtEnd(); i++) {
96 PropertyEntry entry;
97 if (GetVersion() < HEIF_BOX_VERSION_ONE) {
98 entry.itemId = reader.Read16();
99 } else {
100 entry.itemId = reader.Read32();
101 }
102
103 int assocNum = reader.Read8();
104 for (int k = 0; k < assocNum; k++) {
105 PropertyAssociation association;
106 uint16_t index;
107 if (GetFlags() & LARGE_PROPERTY_INDEX_FLAG) {
108 index = reader.Read16();
109 association.essential = !!(index & 0x8000);
110 association.propertyIndex = (index & 0x7fff);
111 } else {
112 index = reader.Read8();
113 association.essential = !!(index & 0x80);
114 association.propertyIndex = (index & 0x7f);
115 }
116 entry.associations.push_back(association);
117 }
118 entries_.push_back(entry);
119 }
120 return reader.GetError();
121 }
122
GetProperties(uint32_t itemId) const123 const std::vector<PropertyAssociation> *HeifIpmaBox::GetProperties(uint32_t itemId) const
124 {
125 auto iter = std::find_if(entries_.begin(), entries_.end(), [&itemId](const auto& entry) {
126 return entry.itemId == itemId;
127 });
128 return iter == entries_.end() ? nullptr : &(iter->associations);
129 }
130
AddProperty(heif_item_id itemId,PropertyAssociation assoc)131 void HeifIpmaBox::AddProperty(heif_item_id itemId, PropertyAssociation assoc)
132 {
133 size_t idx;
134 for (idx = 0; idx < entries_.size(); idx++) {
135 if (entries_[idx].itemId == itemId) {
136 break;
137 }
138 }
139
140 if (idx == entries_.size()) {
141 PropertyEntry entry;
142 entry.itemId = itemId;
143 entries_.push_back(entry);
144 }
145
146 entries_[idx].associations.push_back(assoc);
147 }
148
InferFullBoxVersion()149 void HeifIpmaBox::InferFullBoxVersion()
150 {
151 int version = HEIF_BOX_VERSION_ZERO;
152 bool largeIndices = false;
153
154 for (const PropertyEntry &entry: entries_) {
155 if (entry.itemId > 0xFFFF) {
156 version = HEIF_BOX_VERSION_ONE;
157 }
158
159 for (const auto &assoc: entry.associations) {
160 if (assoc.propertyIndex > 0x7F) {
161 largeIndices = true;
162 }
163 }
164 }
165
166 SetVersion((uint8_t) version);
167 SetFlags(largeIndices ? LARGE_PROPERTY_INDEX_FLAG : 0);
168 }
169
Write(HeifStreamWriter & writer) const170 heif_error HeifIpmaBox::Write(HeifStreamWriter &writer) const
171 {
172 size_t boxStart = ReserveHeader(writer);
173
174 size_t entryNum = entries_.size();
175 writer.Write32((uint32_t) entryNum);
176
177 for (const PropertyEntry &entry: entries_) {
178 if (GetVersion() < HEIF_BOX_VERSION_ONE) {
179 writer.Write16((uint16_t) entry.itemId);
180 } else {
181 writer.Write32(entry.itemId);
182 }
183 size_t assocNum = entry.associations.size();
184 writer.Write8((uint8_t) assocNum);
185 for (const PropertyAssociation &association: entry.associations) {
186 if (GetFlags() & LARGE_PROPERTY_INDEX_FLAG) {
187 writer.Write16((uint16_t) ((association.essential ? 0x8000 : 0) |
188 (association.propertyIndex & 0x7FFF)));
189 } else {
190 writer.Write8((uint8_t) ((association.essential ? 0x80 : 0) |
191 (association.propertyIndex & 0x7F)));
192 }
193 }
194 }
195
196 WriteCalculatedHeader(writer, boxStart);
197 return heif_error_ok;
198 }
199
MergeImpaBoxes(const HeifIpmaBox & b)200 void HeifIpmaBox::MergeImpaBoxes(const HeifIpmaBox &b)
201 {
202 entries_.insert(entries_.end(), b.entries_.begin(), b.entries_.end());
203 }
204 } // namespace ImagePlugin
205 } // namespace OHOS
206