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