Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2020 Project CHIP Authors 4 : * 5 : * Licensed under the Apache License, Version 2.0 (the "License"); 6 : * you may not use this file except in compliance with the License. 7 : * You may obtain a copy of the License at 8 : * 9 : * http://www.apache.org/licenses/LICENSE-2.0 10 : * 11 : * Unless required by applicable law or agreed to in writing, software 12 : * distributed under the License is distributed on an "AS IS" BASIS, 13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 : * See the License for the specific language governing permissions and 15 : * limitations under the License. 16 : */ 17 : 18 : #include "BufferReader.h" 19 : 20 : #include <lib/core/CHIPEncoding.h> 21 : 22 : #include <string.h> 23 : #include <type_traits> 24 : 25 : namespace chip { 26 : namespace Encoding { 27 : namespace LittleEndian { 28 : 29 : namespace { 30 : 31 : // This helper methods return void and put the value being read into an 32 : // outparam because that allows us to easily overload on the type of the 33 : // thing being read. 34 6 : void ReadHelper(const uint8_t * p, bool * dest) 35 : { 36 6 : *dest = (*p != 0); 37 6 : } 38 : 39 : template <typename T> 40 152848 : void ReadHelper(const uint8_t * p, T * dest) 41 : { 42 : std::make_unsigned_t<T> result; 43 152848 : memcpy(&result, p, sizeof(result)); 44 152848 : result = chip::Encoding::LittleEndian::HostSwap(result); 45 : 46 152848 : *dest = static_cast<T>(result); 47 152848 : } 48 : 49 : } // anonymous namespace 50 : 51 : template <typename T> 52 153165 : void Reader::RawReadLowLevelBeCareful(T * retval) 53 : { 54 : static_assert(CHAR_BIT == 8, "Our various sizeof checks rely on bytes and octets being the same thing"); 55 : static_assert((-1 & 3) == 3, "LittleEndian::BufferReader only works with 2's complement architectures."); 56 : 57 153165 : VerifyOrReturn(IsSuccess()); 58 : 59 153159 : constexpr size_t data_size = sizeof(T); 60 : 61 153159 : if (mAvailable < data_size) 62 : { 63 305 : mStatus = CHIP_ERROR_BUFFER_TOO_SMALL; 64 : // Ensure that future reads all fail. 65 305 : mAvailable = 0; 66 305 : return; 67 : } 68 : 69 152854 : ReadHelper(mReadPtr, retval); 70 152854 : mReadPtr += data_size; 71 : 72 152854 : mAvailable = static_cast<uint16_t>(mAvailable - data_size); 73 : } 74 : 75 4364 : Reader & Reader::ReadBytes(uint8_t * dest, size_t size) 76 : { 77 : static_assert(CHAR_BIT == 8, "Our various sizeof checks rely on bytes and octets being the same thing"); 78 : 79 4364 : if ((size > UINT16_MAX) || (mAvailable < size)) 80 : { 81 0 : mStatus = CHIP_ERROR_BUFFER_TOO_SMALL; 82 : // Ensure that future reads all fail. 83 0 : mAvailable = 0; 84 0 : return *this; 85 : } 86 : 87 4364 : memcpy(dest, mReadPtr, size); 88 : 89 4364 : mReadPtr += size; 90 4364 : mAvailable = static_cast<uint16_t>(mAvailable - size); 91 4364 : return *this; 92 : } 93 : 94 : // Explicit Read instantiations for the data types we want to support. 95 : template void Reader::RawReadLowLevelBeCareful(char *); 96 : template void Reader::RawReadLowLevelBeCareful(bool *); 97 : template void Reader::RawReadLowLevelBeCareful(int8_t *); 98 : template void Reader::RawReadLowLevelBeCareful(int16_t *); 99 : template void Reader::RawReadLowLevelBeCareful(int32_t *); 100 : template void Reader::RawReadLowLevelBeCareful(int64_t *); 101 : template void Reader::RawReadLowLevelBeCareful(uint8_t *); 102 : template void Reader::RawReadLowLevelBeCareful(uint16_t *); 103 : template void Reader::RawReadLowLevelBeCareful(uint32_t *); 104 : template void Reader::RawReadLowLevelBeCareful(uint64_t *); 105 : 106 : } // namespace LittleEndian 107 : } // namespace Encoding 108 : } // namespace chip