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_ref_box.h"
17 
18 #include <algorithm>
19 
20 namespace OHOS {
21 namespace ImagePlugin {
ParseItemRef(HeifStreamReader & reader,Reference & ref)22 void HeifIrefBox::ParseItemRef(HeifStreamReader &reader, Reference& ref)
23 {
24     if (GetVersion() == HEIF_BOX_VERSION_ZERO) {
25         ref.fromItemId = reader.Read16();
26         int nRefs = reader.Read16();
27         for (int i = 0; i < nRefs; i++) {
28             ref.toItemIds.push_back(reader.Read16());
29             if (reader.IsAtEnd()) {
30                 break;
31             }
32         }
33     } else {
34         ref.fromItemId = reader.Read32();
35         int nRefs = reader.Read16();
36         for (int i = 0; i < nRefs; i++) {
37             ref.toItemIds.push_back(reader.Read32());
38             if (reader.IsAtEnd()) {
39                 break;
40             }
41         }
42     }
43 }
44 
ParseContent(HeifStreamReader & reader)45 heif_error HeifIrefBox::ParseContent(HeifStreamReader &reader)
46 {
47     ParseFullHeader(reader);
48     while (!reader.IsAtEnd()) {
49         Reference ref;
50         heif_error err = ref.box.ParseHeader(reader);
51         if (err != heif_error_ok) {
52             return err;
53         }
54         ParseItemRef(reader, ref);
55         references_.push_back(ref);
56     }
57 
58     return reader.GetError();
59 }
60 
InferFullBoxVersion()61 void HeifIrefBox::InferFullBoxVersion()
62 {
63     uint8_t version = 0;
64     for (auto &ref: references_) {
65         if ((ref.fromItemId >> TWO_BYTES_SHIFT) > 0) {
66             version = HEIF_BOX_VERSION_ONE;
67             SetVersion(version);
68             return;
69         }
70 
71         for (auto id: ref.toItemIds) {
72             if ((id >> TWO_BYTES_SHIFT) > 0) {
73                 version = HEIF_BOX_VERSION_ONE;
74                 SetVersion(version);
75                 return;
76             }
77         }
78     }
79     SetVersion(version);
80 }
81 
82 
Write(HeifStreamWriter & writer) const83 heif_error HeifIrefBox::Write(HeifStreamWriter &writer) const
84 {
85     size_t boxStart = ReserveHeader(writer);
86 
87     int idSize = ((GetVersion() == HEIF_BOX_VERSION_ZERO) ? UINT16_BYTES_NUM : UINT32_BYTES_NUM);
88 
89     for (const auto &ref: references_) {
90         auto box_size = uint32_t(UINT32_BYTES_NUM + UINT32_BYTES_NUM + UINT16_BYTES_NUM +
91                                  static_cast<size_t>(idSize) * (UINT8_BYTES_NUM + ref.toItemIds.size()));
92 
93         writer.Write32(box_size);
94         writer.Write32(ref.box.GetBoxType());
95 
96         writer.Write(idSize, ref.fromItemId);
97         writer.Write16((uint16_t) ref.toItemIds.size());
98 
99         for (uint32_t r: ref.toItemIds) {
100             writer.Write(idSize, r);
101         }
102     }
103     WriteCalculatedHeader(writer, boxStart);
104 
105     return heif_error_ok;
106 }
107 
HasReferences(heif_item_id itemId) const108 bool HeifIrefBox::HasReferences(heif_item_id itemId) const
109 {
110     return std::any_of(references_.begin(), references_.end(), [&itemId](const auto& ref) {
111         return ref.fromItemId == itemId;
112     });
113 }
114 
115 
GetReferencesFrom(heif_item_id itemId) const116 std::vector<HeifIrefBox::Reference> HeifIrefBox::GetReferencesFrom(heif_item_id itemId) const
117 {
118     std::vector<Reference> references;
119     for (const Reference &ref: references_) {
120         if (ref.fromItemId == itemId) {
121             references.push_back(ref);
122         }
123     }
124     return references;
125 }
126 
127 
GetReferences(heif_item_id itemId,uint32_t ref_type) const128 std::vector<uint32_t> HeifIrefBox::GetReferences(heif_item_id itemId, uint32_t ref_type) const
129 {
130     std::vector<uint32_t> res{};
131     auto iter = std::find_if(references_.begin(), references_.end(), [&itemId, &ref_type](const auto& ref) {
132         return ref.fromItemId == itemId && ref.box.GetBoxType() == ref_type;
133     });
134     return iter == references_.end() ? res : iter->toItemIds;
135 }
136 
137 
AddReferences(heif_item_id from_id,uint32_t type,const std::vector<heif_item_id> & to_ids)138 void HeifIrefBox::AddReferences(heif_item_id from_id, uint32_t type, const std::vector<heif_item_id> &to_ids)
139 {
140     Reference ref;
141     ref.box.SetBoxType(type);
142     ref.fromItemId = from_id;
143     ref.toItemIds = to_ids;
144     references_.push_back(ref);
145 }
146 } // namespace ImagePlugin
147 } // namespace OHOS