1 // Copyright 2016 The Draco Authors.
2 //
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 #include "draco/compression/attributes/attributes_decoder.h"
16 
17 #include "draco/core/varint_decoding.h"
18 
19 namespace draco {
20 
AttributesDecoder()21 AttributesDecoder::AttributesDecoder()
22     : point_cloud_decoder_(nullptr), point_cloud_(nullptr) {}
23 
Init(PointCloudDecoder * decoder,PointCloud * pc)24 bool AttributesDecoder::Init(PointCloudDecoder *decoder, PointCloud *pc) {
25   point_cloud_decoder_ = decoder;
26   point_cloud_ = pc;
27   return true;
28 }
29 
DecodeAttributesDecoderData(DecoderBuffer * in_buffer)30 bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) {
31   // Decode and create attributes.
32   uint32_t num_attributes;
33 #ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
34   if (point_cloud_decoder_->bitstream_version() <
35       DRACO_BITSTREAM_VERSION(2, 0)) {
36     if (!in_buffer->Decode(&num_attributes)) {
37       return false;
38     }
39   } else
40 #endif
41   {
42     if (!DecodeVarint(&num_attributes, in_buffer)) {
43       return false;
44     }
45   }
46 
47   // Check that decoded number of attributes is valid.
48   if (num_attributes == 0) {
49     return false;
50   }
51   if (num_attributes > 5 * in_buffer->remaining_size()) {
52     // The decoded number of attributes is unreasonably high, because at least
53     // five bytes of attribute descriptor data per attribute are expected.
54     return false;
55   }
56 
57   // Decode attribute descriptor data.
58   point_attribute_ids_.resize(num_attributes);
59   PointCloud *pc = point_cloud_;
60   for (uint32_t i = 0; i < num_attributes; ++i) {
61     // Decode attribute descriptor data.
62     uint8_t att_type, data_type, num_components, normalized;
63     if (!in_buffer->Decode(&att_type)) {
64       return false;
65     }
66     if (!in_buffer->Decode(&data_type)) {
67       return false;
68     }
69     if (!in_buffer->Decode(&num_components)) {
70       return false;
71     }
72     if (!in_buffer->Decode(&normalized)) {
73       return false;
74     }
75     if (att_type >= GeometryAttribute::NAMED_ATTRIBUTES_COUNT) {
76       return false;
77     }
78     if (data_type == DT_INVALID || data_type >= DT_TYPES_COUNT) {
79       return false;
80     }
81 
82     // Check decoded attribute descriptor data.
83     if (num_components == 0) {
84       return false;
85     }
86 
87     // Add the attribute to the point cloud.
88     const DataType draco_dt = static_cast<DataType>(data_type);
89     GeometryAttribute ga;
90     ga.Init(static_cast<GeometryAttribute::Type>(att_type), nullptr,
91             num_components, draco_dt, normalized > 0,
92             DataTypeLength(draco_dt) * num_components, 0);
93     uint32_t unique_id;
94 #ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
95     if (point_cloud_decoder_->bitstream_version() <
96         DRACO_BITSTREAM_VERSION(1, 3)) {
97       uint16_t custom_id;
98       if (!in_buffer->Decode(&custom_id)) {
99         return false;
100       }
101       // TODO(draco-eng): Add "custom_id" to attribute metadata.
102       unique_id = static_cast<uint32_t>(custom_id);
103       ga.set_unique_id(unique_id);
104     } else
105 #endif
106     {
107       if (!DecodeVarint(&unique_id, in_buffer)) {
108         return false;
109       }
110       ga.set_unique_id(unique_id);
111     }
112     const int att_id = pc->AddAttribute(
113         std::unique_ptr<PointAttribute>(new PointAttribute(ga)));
114     pc->attribute(att_id)->set_unique_id(unique_id);
115     point_attribute_ids_[i] = att_id;
116 
117     // Update the inverse map.
118     if (att_id >=
119         static_cast<int32_t>(point_attribute_to_local_id_map_.size())) {
120       point_attribute_to_local_id_map_.resize(att_id + 1, -1);
121     }
122     point_attribute_to_local_id_map_[att_id] = i;
123   }
124   return true;
125 }
126 
127 }  // namespace draco
128