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