Showing the changes to Source/Libraries/TimeSeriesPlatformLibrary/Transport/TSSCDecoder.cpp (1 of 10 files). Show all
Unified · Split
| @@ -0,0 +1,553 @@ | ||
| 1 | +//****************************************************************************************************** | |
| 2 | +// TSSCDecoder.cpp - Gbtc | |
| 3 | +// | |
| 4 | +// Copyright © 2018, Grid Protection Alliance. All Rights Reserved. | |
| 5 | +// | |
| 6 | +// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See | |
| 7 | +// the NOTICE file distributed with this work for additional information regarding copyright ownership. | |
| 8 | +// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this | |
| 9 | +// file except in compliance with the License. You may obtain a copy of the License at: | |
| 10 | +// | |
| 11 | +// http://opensource.org/licenses/MIT | |
| 12 | +// | |
| 13 | +// Unless agreed to in writing, the subject software distributed under the License is distributed on an | |
| 14 | +// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the | |
| 15 | +// License for the specific language governing permissions and limitations. | |
| 16 | +// | |
| 17 | +// Code Modification History: | |
| 18 | +// ---------------------------------------------------------------------------------------------------- | |
| 19 | +// 04/11/2018 - J. Ritchie Carroll | |
| 20 | +// Generated original version of source code. | |
| 21 | +// | |
| 22 | +//****************************************************************************************************** | |
| 23 | + | |
| 24 | +#include "TSSCDecoder.h" | |
| 25 | +#include "Constants.h" | |
| 26 | + | |
| 27 | +using namespace std; | |
| 28 | +using namespace GSF; | |
| 29 | +using namespace GSF::TimeSeries; | |
| 30 | +using namespace GSF::TimeSeries::Transport; | |
| 31 | + | |
| 32 | +uint32_t Decode7BitUInt32(const uint8_t* stream, uint32_t& position); | |
| 33 | +uint64_t Decode7BitUInt64(const uint8_t* stream, uint32_t& position); | |
| 34 | + | |
| 35 | +TSSCDecoder::TSSCDecoder() : | |
| 36 | + m_data(nullptr), | |
| 37 | + m_position(0), | |
| 38 | + m_lastPosition(0), | |
| 39 | + m_prevTimestamp1(0L), | |
| 40 | + m_prevTimestamp2(0L), | |
| 41 | + m_prevTimeDelta1(Int64::MaxValue), | |
| 42 | + m_prevTimeDelta2(Int64::MaxValue), | |
| 43 | + m_prevTimeDelta3(Int64::MaxValue), | |
| 44 | + m_prevTimeDelta4(Int64::MaxValue), | |
| 45 | + m_bitStreamCount(0), | |
| 46 | + m_bitStreamCache(0) | |
| 47 | +{ | |
| 48 | + m_lastPoint = NewTSSCPointMetadata(); | |
| 49 | +} | |
| 50 | + | |
| 51 | +void TSSCDecoder::Reset() | |
| 52 | +{ | |
| 53 | + m_data = nullptr; | |
| 54 | + m_points.clear(); | |
| 55 | + m_lastPoint = NewTSSCPointMetadata(); | |
| 56 | + m_position = 0; | |
| 57 | + m_lastPosition = 0; | |
| 58 | + ClearBitStream(); | |
| 59 | + m_prevTimeDelta1 = Int64::MaxValue; | |
| 60 | + m_prevTimeDelta2 = Int64::MaxValue; | |
| 61 | + m_prevTimeDelta3 = Int64::MaxValue; | |
| 62 | + m_prevTimeDelta4 = Int64::MaxValue; | |
| 63 | + m_prevTimestamp1 = 0L; | |
| 64 | + m_prevTimestamp2 = 0L; | |
| 65 | +} | |
| 66 | + | |
| 67 | +TSSCPointMetadataPtr TSSCDecoder::NewTSSCPointMetadata() | |
| 68 | +{ | |
| 69 | + return NewSharedPtr<TSSCPointMetadata>([this]() { return ReadBit(); }, [this]() { return ReadBits5(); }); | |
| 70 | +} | |
| 71 | + | |
| 72 | +void TSSCDecoder::SetBuffer(uint8_t* data, uint32_t offset, uint32_t length) | |
| 73 | +{ | |
| 74 | + ClearBitStream(); | |
| 75 | + m_data = data; | |
| 76 | + m_position = offset; | |
| 77 | + m_lastPosition = length; | |
| 78 | +} | |
| 79 | + | |
| 80 | +bool TSSCDecoder::TryGetMeasurement(uint16_t& id, int64_t& timestamp, uint32_t& quality, float32_t& value) | |
| 81 | +{ | |
| 82 | + if (m_position == m_lastPosition && BitStreamIsEmpty()) | |
| 83 | + { | |
| 84 | + ClearBitStream(); | |
| 85 | + id = 0; | |
| 86 | + timestamp = 0; | |
| 87 | + quality = 0; | |
| 88 | + value = 0.0F; | |
| 89 | + return false; | |
| 90 | + } | |
| 91 | + | |
| 92 | + //Note: since I will not know the incoming pointID. The most recent | |
| 93 | + // measurement received will be the one that contains the | |
| 94 | + // coding algorithm for this measurement. Since for the more part | |
| 95 | + // measurements generally have some sort of sequence to them, | |
| 96 | + // this still ends up being a good enough assumption. | |
| 97 | + | |
| 98 | + int32_t code = m_lastPoint->ReadCode(); | |
| 99 | + | |
| 100 | + if (code == TSSCCodeWords::EndOfStream) | |
| 101 | + { | |
| 102 | + ClearBitStream(); | |
| 103 | + id = 0; | |
| 104 | + timestamp = 0; | |
| 105 | + quality = 0; | |
| 106 | + value = 0.0F; | |
| 107 | + return false; | |
| 108 | + } | |
| 109 | + | |
| 110 | + if (code <= TSSCCodeWords::PointIDXOR16) | |
| 111 | + { | |
| 112 | + DecodePointID(code, m_lastPoint); | |
| 113 | + code = m_lastPoint->ReadCode(); | |
| 114 | + | |
| 115 | + if (code < TSSCCodeWords::TimeDelta1Forward) | |
| 116 | + { | |
| 117 | + stringstream errorMessageStream; | |
| 118 | + | |
| 119 | + errorMessageStream << "Expecting code >= "; | |
| 120 | + errorMessageStream << static_cast<int>(TSSCCodeWords::TimeDelta1Forward); | |
| 121 | + errorMessageStream << " Received "; | |
| 122 | + errorMessageStream << static_cast<int>(code); | |
| 123 | + errorMessageStream << " at position "; | |
| 124 | + errorMessageStream << static_cast<int>(m_position); | |
| 125 | + errorMessageStream << " with last position "; | |
| 126 | + errorMessageStream << static_cast<int>(m_lastPosition); | |
| 127 | + | |
| 128 | + throw SubscriberException(errorMessageStream.str()); | |
| 129 | + } | |
| 130 | + } | |
| 131 | + | |
| 132 | + id = m_lastPoint->PrevNextPointId1; | |
| 133 | + TSSCPointMetadataPtr nextPoint = id >= m_points.size() ? nullptr : m_points[id]; | |
| 134 | + | |
| 135 | + if (nextPoint == nullptr) | |
| 136 | + { | |
| 137 | + nextPoint = NewTSSCPointMetadata(); | |
| 138 | + | |
| 139 | + if (id >= m_points.size()) | |
| 140 | + m_points.resize(id + 1, nullptr); | |
| 141 | + | |
| 142 | + m_points[id] = nextPoint; | |
| 143 | + | |
| 144 | + nextPoint->PrevNextPointId1 = static_cast<uint16_t>(id + 1); | |
| 145 | + } | |
| 146 | + | |
| 147 | + if (code <= TSSCCodeWords::TimeXOR7Bit) | |
| 148 | + { | |
| 149 | + timestamp = DecodeTimestamp(code); | |
| 150 | + code = m_lastPoint->ReadCode(); | |
| 151 | + | |
| 152 | + if (code < TSSCCodeWords::Quality2) | |
| 153 | + { | |
| 154 | + stringstream errorMessageStream; | |
| 155 | + | |
| 156 | + errorMessageStream << "Expecting code >= "; | |
| 157 | + errorMessageStream << static_cast<int>(TSSCCodeWords::Quality2); | |
| 158 | + errorMessageStream << " Received "; | |
| 159 | + errorMessageStream << static_cast<int>(code); | |
| 160 | + errorMessageStream << " at position "; | |
| 161 | + errorMessageStream << static_cast<int>(m_position); | |
| 162 | + errorMessageStream << " with last position "; | |
| 163 | + errorMessageStream << static_cast<int>(m_lastPosition); | |
| 164 | + | |
| 165 | + throw SubscriberException(errorMessageStream.str()); | |
| 166 | + } | |
| 167 | + } | |
| 168 | + else | |
| 169 | + { | |
| 170 | + timestamp = m_prevTimestamp1; | |
| 171 | + } | |
| 172 | + | |
| 173 | + if (code <= TSSCCodeWords::Quality7Bit32) | |
| 174 | + { | |
| 175 | + quality = DecodeQuality(code, nextPoint); | |
| 176 | + code = m_lastPoint->ReadCode(); | |
| 177 | + | |
| 178 | + if (code < TSSCCodeWords::Value1) | |
| 179 | + { | |
| 180 | + stringstream errorMessageStream; | |
| 181 | + | |
| 182 | + errorMessageStream << "Expecting code >= "; | |
| 183 | + errorMessageStream << static_cast<int>(TSSCCodeWords::Value1); | |
| 184 | + errorMessageStream << " Received "; | |
| 185 | + errorMessageStream << static_cast<int>(code); | |
| 186 | + errorMessageStream << " at position "; | |
| 187 | + errorMessageStream << static_cast<int>(m_position); | |
| 188 | + errorMessageStream << " with last position "; | |
| 189 | + errorMessageStream << static_cast<int>(m_lastPosition); | |
| 190 | + | |
| 191 | + throw SubscriberException(errorMessageStream.str()); | |
| 192 | + } | |
| 193 | + } | |
| 194 | + else | |
| 195 | + { | |
| 196 | + quality = nextPoint->PrevQuality1; | |
| 197 | + } | |
| 198 | + | |
| 199 | + //Since value will almost always change, | |
| 200 | + //This is not put inside a function call. | |
| 201 | + uint32_t valueRaw; | |
| 202 | + | |
| 203 | + if (code == TSSCCodeWords::Value1) | |
| 204 | + { | |
| 205 | + valueRaw = nextPoint->PrevValue1; | |
| 206 | + } | |
| 207 | + else if (code == TSSCCodeWords::Value2) | |
| 208 | + { | |
| 209 | + valueRaw = nextPoint->PrevValue2; | |
| 210 | + nextPoint->PrevValue2 = nextPoint->PrevValue1; | |
| 211 | + nextPoint->PrevValue1 = valueRaw; | |
| 212 | + } | |
| 213 | + else if (code == TSSCCodeWords::Value3) | |
| 214 | + { | |
| 215 | + valueRaw = nextPoint->PrevValue3; | |
| 216 | + nextPoint->PrevValue3 = nextPoint->PrevValue2; | |
| 217 | + nextPoint->PrevValue2 = nextPoint->PrevValue1; | |
| 218 | + nextPoint->PrevValue1 = valueRaw; | |
| 219 | + } | |
| 220 | + else if (code == TSSCCodeWords::ValueZero) | |
| 221 | + { | |
| 222 | + valueRaw = 0; | |
| 223 | + nextPoint->PrevValue3 = nextPoint->PrevValue2; | |
| 224 | + nextPoint->PrevValue2 = nextPoint->PrevValue1; | |
| 225 | + nextPoint->PrevValue1 = valueRaw; | |
| 226 | + } | |
| 227 | + else | |
| 228 | + { | |
| 229 | + switch (code) | |
| 230 | + { | |
| 231 | + case TSSCCodeWords::ValueXOR4: | |
| 232 | + valueRaw = static_cast<uint32_t>(ReadBits4()) ^ nextPoint->PrevValue1; | |
| 233 | + break; | |
| 234 | + case TSSCCodeWords::ValueXOR8: | |
| 235 | + valueRaw = static_cast<uint32_t>(m_data[m_position]) ^ nextPoint->PrevValue1; | |
| 236 | + m_position++; | |
| 237 | + break; | |
| 238 | + case TSSCCodeWords::ValueXOR12: | |
| 239 | + valueRaw = static_cast<uint32_t>(ReadBits4()) ^ static_cast<uint32_t>(m_data[m_position] << 4) ^ nextPoint->PrevValue1; | |
| 240 | + m_position++; | |
| 241 | + break; | |
| 242 | + case TSSCCodeWords::ValueXOR16: | |
| 243 | + valueRaw = static_cast<uint32_t>(m_data[m_position]) ^ static_cast<uint32_t>(m_data[m_position + 1] << 8) ^ nextPoint->PrevValue1; | |
| 244 | + m_position += 2; | |
| 245 | + break; | |
| 246 | + case TSSCCodeWords::ValueXOR20: | |
| 247 | + valueRaw = static_cast<uint32_t>(ReadBits4()) ^ static_cast<uint32_t>(m_data[m_position] << 4) ^ static_cast<uint32_t>(m_data[m_position + 1] << 12) ^ nextPoint->PrevValue1; | |
| 248 | + m_position += 2; | |
| 249 | + break; | |
| 250 | + case TSSCCodeWords::ValueXOR24: | |
| 251 | + valueRaw = static_cast<uint32_t>(m_data[m_position]) ^ static_cast<uint32_t>(m_data[m_position + 1] << 8) ^ static_cast<uint32_t>(m_data[m_position + 2] << 16) ^ nextPoint->PrevValue1; | |
| 252 | + m_position += 3; | |
| 253 | + break; | |
| 254 | + case TSSCCodeWords::ValueXOR28: | |
| 255 | + valueRaw = static_cast<uint32_t>(ReadBits4()) ^ static_cast<uint32_t>(m_data[m_position] << 4) ^ static_cast<uint32_t>(m_data[m_position + 1] << 12) ^ static_cast<uint32_t>(m_data[m_position + 2] << 20) ^ nextPoint->PrevValue1; | |
| 256 | + m_position += 3; | |
| 257 | + break; | |
| 258 | + case TSSCCodeWords::ValueXOR32: | |
| 259 | + valueRaw = static_cast<uint32_t>(m_data[m_position]) ^ static_cast<uint32_t>(m_data[m_position + 1] << 8) ^ static_cast<uint32_t>(m_data[m_position + 2] << 16) ^ static_cast<uint32_t>(m_data[m_position + 3] << 24) ^ nextPoint->PrevValue1; | |
| 260 | + m_position += 4; | |
| 261 | + break; | |
| 262 | + default: | |
| 263 | + stringstream errorMessageStream; | |
| 264 | + | |
| 265 | + errorMessageStream << "Invalid code received "; | |
| 266 | + errorMessageStream << static_cast<int>(code); | |
| 267 | + errorMessageStream << " at position "; | |
| 268 | + errorMessageStream << static_cast<int>(m_position); | |
| 269 | + errorMessageStream << " with last position "; | |
| 270 | + errorMessageStream << static_cast<int>(m_lastPosition); | |
| 271 | + | |
| 272 | + throw SubscriberException(errorMessageStream.str()); | |
| 273 | + } | |
| 274 | + | |
| 275 | + nextPoint->PrevValue3 = nextPoint->PrevValue2; | |
| 276 | + nextPoint->PrevValue2 = nextPoint->PrevValue1; | |
| 277 | + nextPoint->PrevValue1 = valueRaw; | |
| 278 | + } | |
| 279 | + | |
| 280 | + value = *reinterpret_cast<float32_t*>(&valueRaw); | |
| 281 | + m_lastPoint = nextPoint; | |
| 282 | + | |
| 283 | + return true; | |
| 284 | +} | |
| 285 | + | |
| 286 | +void TSSCDecoder::DecodePointID(uint8_t code, const TSSCPointMetadataPtr& lastPoint) | |
| 287 | +{ | |
| 288 | + if (code == TSSCCodeWords::PointIDXOR4) | |
| 289 | + { | |
| 290 | + lastPoint->PrevNextPointId1 ^= static_cast<uint16_t>(ReadBits4()); | |
| 291 | + } | |
| 292 | + else if (code == TSSCCodeWords::PointIDXOR8) | |
| 293 | + { | |
| 294 | + lastPoint->PrevNextPointId1 ^= static_cast<uint16_t>(m_data[m_position++]); | |
| 295 | + } | |
| 296 | + else if (code == TSSCCodeWords::PointIDXOR12) | |
| 297 | + { | |
| 298 | + lastPoint->PrevNextPointId1 ^= static_cast<uint16_t>(ReadBits4()); | |
| 299 | + lastPoint->PrevNextPointId1 ^= static_cast<uint16_t>(m_data[m_position++] << 4); | |
| 300 | + } | |
| 301 | + else | |
| 302 | + { | |
| 303 | + lastPoint->PrevNextPointId1 ^= static_cast<uint16_t>(m_data[m_position++]); | |
| 304 | + lastPoint->PrevNextPointId1 ^= static_cast<uint16_t>(m_data[m_position++] << 8); | |
| 305 | + } | |
| 306 | +} | |
| 307 | + | |
| 308 | +int64_t TSSCDecoder::DecodeTimestamp(uint8_t code) | |
| 309 | +{ | |
| 310 | + int64_t timestamp; | |
| 311 | + | |
| 312 | + if (code == TSSCCodeWords::TimeDelta1Forward) | |
| 313 | + { | |
| 314 | + timestamp = m_prevTimestamp1 + m_prevTimeDelta1; | |
| 315 | + } | |
| 316 | + else if (code == TSSCCodeWords::TimeDelta2Forward) | |
| 317 | + { | |
| 318 | + timestamp = m_prevTimestamp1 + m_prevTimeDelta2; | |
| 319 | + } | |
| 320 | + else if (code == TSSCCodeWords::TimeDelta3Forward) | |
| 321 | + { | |
| 322 | + timestamp = m_prevTimestamp1 + m_prevTimeDelta3; | |
| 323 | + } | |
| 324 | + else if (code == TSSCCodeWords::TimeDelta4Forward) | |
| 325 | + { | |
| 326 | + timestamp = m_prevTimestamp1 + m_prevTimeDelta4; | |
| 327 | + } | |
| 328 | + else if (code == TSSCCodeWords::TimeDelta1Reverse) | |
| 329 | + { | |
| 330 | + timestamp = m_prevTimestamp1 - m_prevTimeDelta1; | |
| 331 | + } | |
| 332 | + else if (code == TSSCCodeWords::TimeDelta2Reverse) | |
| 333 | + { | |
| 334 | + timestamp = m_prevTimestamp1 - m_prevTimeDelta2; | |
| 335 | + } | |
| 336 | + else if (code == TSSCCodeWords::TimeDelta3Reverse) | |
| 337 | + { | |
| 338 | + timestamp = m_prevTimestamp1 - m_prevTimeDelta3; | |
| 339 | + } | |
| 340 | + else if (code == TSSCCodeWords::TimeDelta4Reverse) | |
| 341 | + { | |
| 342 | + timestamp = m_prevTimestamp1 - m_prevTimeDelta4; | |
| 343 | + } | |
| 344 | + else if (code == TSSCCodeWords::Timestamp2) | |
| 345 | + { | |
| 346 | + timestamp = m_prevTimestamp2; | |
| 347 | + } | |
| 348 | + else | |
| 349 | + { | |
| 350 | + timestamp = m_prevTimestamp1 ^ static_cast<int64_t>(Decode7BitUInt64(&m_data[0], m_position)); | |
| 351 | + } | |
| 352 | + | |
| 353 | + // Save the smallest delta time | |
| 354 | + const int64_t minDelta = abs(m_prevTimestamp1 - timestamp); | |
| 355 | + | |
| 356 | + if (minDelta < m_prevTimeDelta4 && minDelta != m_prevTimeDelta1 && minDelta != m_prevTimeDelta2 && minDelta != m_prevTimeDelta3) | |
| 357 | + { | |
| 358 | + if (minDelta < m_prevTimeDelta1) | |
| 359 | + { | |
| 360 | + m_prevTimeDelta4 = m_prevTimeDelta3; | |
| 361 | + m_prevTimeDelta3 = m_prevTimeDelta2; | |
| 362 | + m_prevTimeDelta2 = m_prevTimeDelta1; | |
| 363 | + m_prevTimeDelta1 = minDelta; | |
| 364 | + } | |
| 365 | + else if (minDelta < m_prevTimeDelta2) | |
| 366 | + { | |
| 367 | + m_prevTimeDelta4 = m_prevTimeDelta3; | |
| 368 | + m_prevTimeDelta3 = m_prevTimeDelta2; | |
| 369 | + m_prevTimeDelta2 = minDelta; | |
| 370 | + } | |
| 371 | + else if (minDelta < m_prevTimeDelta3) | |
| 372 | + { | |
| 373 | + m_prevTimeDelta4 = m_prevTimeDelta3; | |
| 374 | + m_prevTimeDelta3 = minDelta; | |
| 375 | + } | |
| 376 | + else | |
| 377 | + { | |
| 378 | + m_prevTimeDelta4 = minDelta; | |
| 379 | + } | |
| 380 | + } | |
| 381 | + | |
| 382 | + m_prevTimestamp2 = m_prevTimestamp1; | |
| 383 | + m_prevTimestamp1 = timestamp; | |
| 384 | + | |
| 385 | + return timestamp; | |
| 386 | +} | |
| 387 | + | |
| 388 | +uint32_t TSSCDecoder::DecodeQuality(uint8_t code, const TSSCPointMetadataPtr& nextPoint) | |
| 389 | +{ | |
| 390 | + uint32_t quality; | |
| 391 | + | |
| 392 | + if (code == TSSCCodeWords::Quality2) | |
| 393 | + { | |
| 394 | + quality = nextPoint->PrevQuality2; | |
| 395 | + } | |
| 396 | + else | |
| 397 | + { | |
| 398 | + quality = Decode7BitUInt32(&m_data[0], m_position); | |
| 399 | + } | |
| 400 | + | |
| 401 | + nextPoint->PrevQuality2 = nextPoint->PrevQuality1; | |
| 402 | + nextPoint->PrevQuality1 = quality; | |
| 403 | + | |
| 404 | + return quality; | |
| 405 | +} | |
| 406 | + | |
| 407 | +bool TSSCDecoder::BitStreamIsEmpty() const | |
| 408 | +{ | |
| 409 | + return m_bitStreamCount == 0; | |
| 410 | +} | |
| 411 | + | |
| 412 | +void TSSCDecoder::ClearBitStream() | |
| 413 | +{ | |
| 414 | + m_bitStreamCount = 0; | |
| 415 | + m_bitStreamCache = 0; | |
| 416 | +} | |
| 417 | + | |
| 418 | +int32_t TSSCDecoder::ReadBit() | |
| 419 | +{ | |
| 420 | + if (m_bitStreamCount == 0) | |
| 421 | + { | |
| 422 | + m_bitStreamCount = 8; | |
| 423 | + m_bitStreamCache = static_cast<int32_t>(m_data[m_position++]); | |
| 424 | + } | |
| 425 | + | |
| 426 | + m_bitStreamCount--; | |
| 427 | + | |
| 428 | + return (m_bitStreamCache >> m_bitStreamCount) & 1; | |
| 429 | +} | |
| 430 | + | |
| 431 | +int32_t TSSCDecoder::ReadBits4() | |
| 432 | +{ | |
| 433 | + return ReadBit() << 3 | ReadBit() << 2 | ReadBit() << 1 | ReadBit();; | |
| 434 | +} | |
| 435 | + | |
| 436 | +int32_t TSSCDecoder::ReadBits5() | |
| 437 | +{ | |
| 438 | + return ReadBit() << 4 | ReadBit() << 3 | ReadBit() << 2 | ReadBit() << 1 | ReadBit();; | |
| 439 | +} | |
| 440 | + | |
| 441 | +uint32_t Decode7BitUInt32(const uint8_t* stream, uint32_t& position) | |
| 442 | +{ | |
| 443 | + stream += position; | |
| 444 | + uint32_t value = *stream; | |
| 445 | + | |
| 446 | + if (value < 128) | |
| 447 | + { | |
| 448 | + position++; | |
| 449 | + return value; | |
| 450 | + } | |
| 451 | + | |
| 452 | + value ^= (static_cast<uint32_t>(stream[1]) << 7); | |
| 453 | + | |
| 454 | + if (value < 16384) | |
| 455 | + { | |
| 456 | + position += 2; | |
| 457 | + return value ^ 0x80; | |
| 458 | + } | |
| 459 | + | |
| 460 | + value ^= (static_cast<uint32_t>(stream[2]) << 14); | |
| 461 | + | |
| 462 | + if (value < 2097152) | |
| 463 | + { | |
| 464 | + position += 3; | |
| 465 | + return value ^ 0x4080; | |
| 466 | + } | |
| 467 | + | |
| 468 | + value ^= (static_cast<uint32_t>(stream[3]) << 21); | |
| 469 | + | |
| 470 | + if (value < 268435456) | |
| 471 | + { | |
| 472 | + position += 4; | |
| 473 | + return value ^ 0x204080; | |
| 474 | + } | |
| 475 | + | |
| 476 | + value ^= (static_cast<uint32_t>(stream[4]) << 28); | |
| 477 | + position += 5; | |
| 478 | + | |
| 479 | + return value ^ 0x10204080; | |
| 480 | +} | |
| 481 | + | |
| 482 | +uint64_t Decode7BitUInt64(const uint8_t* stream, uint32_t& position) | |
| 483 | +{ | |
| 484 | + stream += position; | |
| 485 | + uint64_t value = *stream; | |
| 486 | + | |
| 487 | + if (value < 128UL) | |
| 488 | + { | |
| 489 | + position++; | |
| 490 | + return value; | |
| 491 | + } | |
| 492 | + | |
| 493 | + value ^= (static_cast<uint64_t>(stream[1]) << 7); | |
| 494 | + | |
| 495 | + if (value < 16384UL) | |
| 496 | + { | |
| 497 | + position += 2; | |
| 498 | + return value ^ 0x80UL; | |
| 499 | + } | |
| 500 | + | |
| 501 | + value ^= (static_cast<uint64_t>(stream[2]) << 14); | |
| 502 | + | |
| 503 | + if (value < 2097152UL) | |
| 504 | + { | |
| 505 | + position += 3; | |
| 506 | + return value ^ 0x4080UL; | |
| 507 | + } | |
| 508 | + | |
| 509 | + value ^= (static_cast<uint64_t>(stream[3]) << 21); | |
| 510 | + | |
| 511 | + if (value < 268435456UL) | |
| 512 | + { | |
| 513 | + position += 4; | |
| 514 | + return value ^ 0x204080UL; | |
| 515 | + } | |
| 516 | + | |
| 517 | + value ^= (static_cast<uint64_t>(stream[4]) << 28); | |
| 518 | + | |
| 519 | + if (value < 34359738368UL) | |
| 520 | + { | |
| 521 | + position += 5; | |
| 522 | + return value ^ 0x10204080UL; | |
| 523 | + } | |
| 524 | + | |
| 525 | + value ^= (static_cast<uint64_t>(stream[5]) << 35); | |
| 526 | + | |
| 527 | + if (value < 4398046511104UL) | |
| 528 | + { | |
| 529 | + position += 6; | |
| 530 | + return value ^ 0x810204080UL; | |
| 531 | + } | |
| 532 | + | |
| 533 | + value ^= (static_cast<uint64_t>(stream[6]) << 42); | |
| 534 | + | |
| 535 | + if (value < 562949953421312UL) | |
| 536 | + { | |
| 537 | + position += 7; | |
| 538 | + return value ^ 0x40810204080UL; | |
| 539 | + } | |
| 540 | + | |
| 541 | + value ^= (static_cast<uint64_t>(stream[7]) << 49); | |
| 542 | + | |
| 543 | + if (value < 72057594037927936UL) | |
| 544 | + { | |
| 545 | + position += 8; | |
| 546 | + return value ^ 0x2040810204080UL; | |
| 547 | + } | |
| 548 | + | |
| 549 | + value ^= (static_cast<uint64_t>(stream[8]) << 56); | |
| 550 | + position += 9; | |
| 551 | + | |
| 552 | + return value ^ 0x102040810204080UL; | |
| 553 | +} | |