File indexing completed on 2024-04-28 16:59:45
0001 /* 0002 Copyright (C) 2013 Andreas Hartmetz <ahartmetz@gmail.com> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LGPL. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 Boston, MA 02110-1301, USA. 0018 0019 Alternatively, this file is available under the Mozilla Public License 0020 Version 1.1. You may obtain a copy of the License at 0021 http://www.mozilla.org/MPL/ 0022 */ 0023 0024 #include "arguments.h" 0025 #include "arguments_p.h" 0026 0027 #include "basictypeio.h" 0028 #include "error.h" 0029 #include "malloccache.h" 0030 #include "message.h" 0031 #include "platform.h" 0032 0033 #include <cstddef> 0034 0035 #ifdef HAVE_BOOST 0036 #include <boost/container/small_vector.hpp> 0037 #endif 0038 0039 0040 class Arguments::Reader::Private 0041 { 0042 public: 0043 Private() 0044 : m_args(nullptr), 0045 m_signaturePosition(uint32(-1)), 0046 m_dataPosition(0), 0047 m_nilArrayNesting(0) 0048 {} 0049 0050 const Arguments *m_args; 0051 cstring m_signature; 0052 uint32 m_signaturePosition; 0053 chunk m_data; 0054 uint32 m_dataPosition; 0055 uint32 m_nilArrayNesting; // this keeps track of how many nil arrays we are in 0056 Error m_error; 0057 Nesting m_nesting; 0058 0059 struct ArrayInfo 0060 { 0061 uint32 dataEnd; // one past the last data byte of the array 0062 uint32 containedTypeBegin; // to rewind when reading the next element 0063 }; 0064 0065 struct VariantInfo 0066 { 0067 podCstring prevSignature; // a variant switches the currently parsed signature, so we 0068 uint32 prevSignaturePosition; // need to store the old signature and parse position. 0069 }; 0070 0071 // for structs, we don't need to know more than that we are in a struct 0072 0073 struct AggregateInfo 0074 { 0075 IoState aggregateType; // can be BeginArray, BeginDict, BeginStruct, BeginVariant 0076 union { 0077 ArrayInfo arr; 0078 VariantInfo var; 0079 }; 0080 }; 0081 0082 // this keeps track of which aggregates we are currently in 0083 #ifdef HAVE_BOOST 0084 boost::container::small_vector<AggregateInfo, 8> m_aggregateStack; 0085 #else 0086 std::vector<AggregateInfo> m_aggregateStack; 0087 #endif 0088 }; 0089 0090 thread_local static MallocCache<sizeof(Arguments::Reader::Private), 4> allocCache; 0091 0092 Arguments::Reader::Reader(const Arguments &al) 0093 : d(new(allocCache.allocate()) Private), 0094 m_state(NotStarted) 0095 { 0096 d->m_args = &al; 0097 beginRead(); 0098 } 0099 0100 Arguments::Reader::Reader(const Message &msg) 0101 : d(new(allocCache.allocate()) Private), 0102 m_state(NotStarted) 0103 { 0104 d->m_args = &msg.arguments(); 0105 beginRead(); 0106 } 0107 0108 Arguments::Reader::Reader(Reader &&other) 0109 : d(other.d), 0110 m_state(other.m_state), 0111 m_u(other.m_u) 0112 { 0113 other.d = nullptr; 0114 } 0115 0116 void Arguments::Reader::operator=(Reader &&other) 0117 { 0118 if (&other == this) { 0119 return; 0120 } 0121 if (d) { 0122 d->~Private(); 0123 allocCache.free(d); 0124 } 0125 d = other.d; 0126 m_state = other.m_state; 0127 m_u = other.m_u; 0128 0129 other.d = nullptr; 0130 } 0131 0132 Arguments::Reader::Reader(const Reader &other) 0133 : d(nullptr), 0134 m_state(other.m_state), 0135 m_u(other.m_u) 0136 { 0137 if (other.d) { 0138 d = new(allocCache.allocate()) Private(*other.d); 0139 } 0140 } 0141 0142 void Arguments::Reader::operator=(const Reader &other) 0143 { 0144 if (&other == this) { 0145 return; 0146 } 0147 m_state = other.m_state; 0148 m_u = other.m_u; 0149 if (d && other.d) { 0150 *d = *other.d; 0151 } else { 0152 Reader temp(other); 0153 std::swap(d, temp.d); 0154 } 0155 } 0156 0157 Arguments::Reader::~Reader() 0158 { 0159 if (d) { 0160 d->~Private(); 0161 allocCache.free(d); 0162 d = nullptr; 0163 } 0164 } 0165 0166 void Arguments::Reader::beginRead() 0167 { 0168 VALID_IF(d->m_args, Error::NotAttachedToArguments); 0169 d->m_signature = d->m_args->d->m_signature; 0170 d->m_data = d->m_args->d->m_data; 0171 // as a slightly hacky optimizaton, we allow empty Argumentss to allocate no space for d->m_buffer. 0172 if (d->m_signature.length) { 0173 VALID_IF(Arguments::isSignatureValid(d->m_signature), Error::InvalidSignature); 0174 } 0175 advanceState(); 0176 } 0177 0178 bool Arguments::Reader::isValid() const 0179 { 0180 return d->m_args; 0181 } 0182 0183 Error Arguments::Reader::error() const 0184 { 0185 return d->m_error; 0186 } 0187 0188 cstring Arguments::Reader::stateString() const 0189 { 0190 return printableState(m_state); 0191 } 0192 0193 bool Arguments::Reader::isInsideEmptyArray() const 0194 { 0195 return d->m_nilArrayNesting > 0; 0196 } 0197 0198 cstring Arguments::Reader::currentSignature() const 0199 { 0200 return d->m_signature; 0201 } 0202 0203 uint32 Arguments::Reader::currentSignaturePosition() const 0204 { 0205 return d->m_signaturePosition; 0206 } 0207 0208 cstring Arguments::Reader::currentSingleCompleteTypeSignature() const 0209 { 0210 const uint32 startingLength = d->m_signature.length - d->m_signaturePosition; 0211 cstring sigCopy = { d->m_signature.ptr + d->m_signaturePosition, startingLength }; 0212 Nesting nest; 0213 if (!parseSingleCompleteType(&sigCopy, &nest)) { 0214 // the signature should have been validated before, but e.g. in Finished state this may happen 0215 return cstring(); 0216 } 0217 sigCopy.ptr = d->m_signature.ptr + d->m_signaturePosition; 0218 sigCopy.length = startingLength - sigCopy.length; 0219 return sigCopy; 0220 } 0221 0222 void Arguments::Reader::replaceData(chunk data) 0223 { 0224 VALID_IF(data.length >= d->m_dataPosition, Error::ReplacementDataIsShorter); 0225 0226 ptrdiff_t offset = data.ptr - d->m_data.ptr; 0227 0228 // fix up variant signature addresses occurring on the aggregate stack pointing into m_data; 0229 // don't touch the original (= call parameter, not variant) signature, which does not point into m_data. 0230 bool isMainSignature = true; 0231 for (Private::AggregateInfo &aggregate : d->m_aggregateStack) { 0232 if (aggregate.aggregateType == BeginVariant) { 0233 if (isMainSignature) { 0234 isMainSignature = false; 0235 } else { 0236 aggregate.var.prevSignature.ptr += offset; 0237 } 0238 } 0239 } 0240 if (!isMainSignature) { 0241 d->m_signature.ptr += offset; 0242 } 0243 0244 d->m_data = data; 0245 if (m_state == NeedMoreData) { 0246 advanceState(); 0247 } 0248 } 0249 0250 void Arguments::Reader::doReadPrimitiveType() 0251 { 0252 switch(m_state) { 0253 case Boolean: { 0254 uint32 num = basic::readUint32(d->m_data.ptr + d->m_dataPosition, d->m_args->d->m_isByteSwapped); 0255 m_u.Boolean = num == 1; 0256 VALID_IF(num <= 1, Error::MalformedMessageData); 0257 break; } 0258 case Byte: 0259 m_u.Byte = d->m_data.ptr[d->m_dataPosition]; 0260 break; 0261 case Int16: 0262 m_u.Int16 = basic::readInt16(d->m_data.ptr + d->m_dataPosition, d->m_args->d->m_isByteSwapped); 0263 break; 0264 case Uint16: 0265 m_u.Uint16 = basic::readUint16(d->m_data.ptr + d->m_dataPosition, d->m_args->d->m_isByteSwapped); 0266 break; 0267 case Int32: 0268 m_u.Int32 = basic::readInt32(d->m_data.ptr + d->m_dataPosition, d->m_args->d->m_isByteSwapped); 0269 break; 0270 case Uint32: 0271 m_u.Uint32 = basic::readUint32(d->m_data.ptr + d->m_dataPosition, d->m_args->d->m_isByteSwapped); 0272 break; 0273 case Int64: 0274 m_u.Int64 = basic::readInt64(d->m_data.ptr + d->m_dataPosition, d->m_args->d->m_isByteSwapped); 0275 break; 0276 case Uint64: 0277 m_u.Uint64 = basic::readUint64(d->m_data.ptr + d->m_dataPosition, d->m_args->d->m_isByteSwapped); 0278 break; 0279 case Double: 0280 m_u.Double = basic::readDouble(d->m_data.ptr + d->m_dataPosition, d->m_args->d->m_isByteSwapped); 0281 break; 0282 case UnixFd: { 0283 uint32 index = basic::readUint32(d->m_data.ptr + d->m_dataPosition, d->m_args->d->m_isByteSwapped); 0284 if (!d->m_nilArrayNesting) { 0285 VALID_IF(index < d->m_args->d->m_fileDescriptors.size(), Error::MalformedMessageData); 0286 m_u.Int32 = d->m_args->d->m_fileDescriptors[index]; 0287 } else { 0288 m_u.Int32 = int32(InvalidFileDescriptor); 0289 } 0290 break; } 0291 default: 0292 assert(false); 0293 VALID_IF(false, Error::MalformedMessageData); 0294 } 0295 } 0296 0297 void Arguments::Reader::doReadString(uint32 lengthPrefixSize) 0298 { 0299 uint32 stringLength = 1; 0300 if (lengthPrefixSize == 1) { 0301 stringLength += d->m_data.ptr[d->m_dataPosition]; 0302 } else { 0303 stringLength += basic::readUint32(d->m_data.ptr + d->m_dataPosition, 0304 d->m_args->d->m_isByteSwapped); 0305 VALID_IF(stringLength + 1 < Arguments::MaxArrayLength, Error::MalformedMessageData); 0306 } 0307 d->m_dataPosition += lengthPrefixSize; 0308 if (unlikely(d->m_dataPosition + stringLength > d->m_data.length)) { 0309 m_state = NeedMoreData; 0310 return; 0311 } 0312 m_u.String.ptr = reinterpret_cast<char *>(d->m_data.ptr) + d->m_dataPosition; 0313 m_u.String.length = stringLength - 1; // terminating null is not counted 0314 d->m_dataPosition += stringLength; 0315 bool isValidString = false; 0316 if (m_state == String) { 0317 isValidString = Arguments::isStringValid(cstring(m_u.String.ptr, m_u.String.length)); 0318 } else if (m_state == ObjectPath) { 0319 isValidString = Arguments::isObjectPathValid(cstring(m_u.String.ptr, m_u.String.length)); 0320 } else if (m_state == Signature) { 0321 isValidString = Arguments::isSignatureValid(cstring(m_u.String.ptr, m_u.String.length)); 0322 } 0323 VALID_IF(isValidString, Error::MalformedMessageData); 0324 } 0325 0326 void Arguments::Reader::advanceState() 0327 { 0328 // if we don't have enough data, the strategy is to keep everything unchanged 0329 // except for the state which will be NeedMoreData 0330 // we don't have to deal with invalid signatures here because they are checked beforehand EXCEPT 0331 // for aggregate nesting which cannot be checked using only one signature, due to variants. 0332 // variant signatures are only parsed while reading the data. individual variant signatures 0333 // ARE checked beforehand whenever we find one in this method. 0334 0335 if (unlikely(m_state == InvalidData)) { // nonrecoverable... 0336 return; 0337 } 0338 // can't do the following because a dict is one aggregate in our counting, but two according to 0339 // the spec: an array (one) containing dict entries (two) 0340 // assert(d->m_nesting.total() == d->m_aggregateStack.size()); 0341 assert((d->m_nesting.total() == 0) == d->m_aggregateStack.empty()); 0342 0343 const uint32 savedSignaturePosition = d->m_signaturePosition; 0344 const uint32 savedDataPosition = d->m_dataPosition; 0345 0346 d->m_signaturePosition++; 0347 assert(d->m_signaturePosition <= d->m_signature.length); 0348 0349 // check if we are about to close any aggregate or even the whole argument list 0350 if (d->m_aggregateStack.empty()) { 0351 // TODO check if there is still data left, if so it's probably an error 0352 if (d->m_signaturePosition >= d->m_signature.length) { 0353 m_state = Finished; 0354 return; 0355 } 0356 } else { 0357 const Private::AggregateInfo &aggregateInfo = d->m_aggregateStack.back(); 0358 switch (aggregateInfo.aggregateType) { 0359 case BeginStruct: 0360 break; // handled later by TypeInfo knowing ')' -> EndStruct 0361 case BeginVariant: 0362 if (d->m_signaturePosition >= d->m_signature.length) { 0363 m_state = EndVariant; 0364 return; 0365 } 0366 break; 0367 case BeginArray: 0368 if (d->m_signaturePosition > aggregateInfo.arr.containedTypeBegin) { 0369 // End of current iteration; either there are more or the array ends 0370 const Private::ArrayInfo &arrayInfo = aggregateInfo.arr; 0371 if (likely(!d->m_nilArrayNesting) && d->m_dataPosition < arrayInfo.dataEnd) { 0372 // rewind to start of contained type and read the type info there 0373 d->m_signaturePosition = arrayInfo.containedTypeBegin; 0374 break; // proceed immediately to reading the next element in the array 0375 } 0376 // TODO check that final data position is where it should be according to the 0377 // serialized array length (same in BeginDict!) 0378 VALID_IF(d->m_dataPosition == arrayInfo.dataEnd, Error::MalformedMessageData); 0379 m_state = EndArray; 0380 return; 0381 } 0382 break; 0383 case BeginDict: 0384 if (d->m_signaturePosition > aggregateInfo.arr.containedTypeBegin + 1) { 0385 // Almost like BeginArray, only differences are commented 0386 const Private::ArrayInfo &arrayInfo = aggregateInfo.arr; 0387 if (likely(!d->m_nilArrayNesting) && d->m_dataPosition < arrayInfo.dataEnd) { 0388 d->m_dataPosition = align(d->m_dataPosition, 8); // align to dict entry 0389 d->m_signaturePosition = arrayInfo.containedTypeBegin; 0390 #ifdef WITH_DICT_ENTRY 0391 d->m_signaturePosition--; 0392 m_state = EndDictEntry; 0393 m_u.Uint32 = 0; // meaning: more dict entries follow (state after next is BeginDictEntry) 0394 return; 0395 #endif 0396 break; 0397 } 0398 #ifdef WITH_DICT_ENTRY 0399 m_state = EndDictEntry; 0400 m_u.Uint32 = 1; // meaning: array end reached (state after next is EndDict) 0401 return; 0402 #endif 0403 m_state = EndDict; 0404 return; 0405 } 0406 break; 0407 default: 0408 break; 0409 } 0410 } 0411 0412 // for aggregate types, ty.alignment is just the alignment. 0413 // for primitive types, it's also the actual size. 0414 const TypeInfo ty = typeInfo(d->m_signature.ptr[d->m_signaturePosition]); 0415 m_state = ty.state(); 0416 0417 VALID_IF(m_state != InvalidData, Error::MalformedMessageData); 0418 0419 // check if we have enough data for the next type, and read it 0420 // if we're in a nil array, we are iterating only over the types without reading any data 0421 0422 if (likely(!d->m_nilArrayNesting)) { 0423 uint32 padStart = d->m_dataPosition; 0424 d->m_dataPosition = align(d->m_dataPosition, ty.alignment); 0425 if (unlikely(d->m_dataPosition > d->m_data.length)) { 0426 goto out_needMoreData; 0427 } 0428 VALID_IF(isPaddingZero(d->m_data, padStart, d->m_dataPosition), Error::MalformedMessageData); 0429 0430 if (ty.isPrimitive || ty.isString) { 0431 if (unlikely(d->m_dataPosition + ty.alignment > d->m_data.length)) { 0432 goto out_needMoreData; 0433 } 0434 0435 if (ty.isPrimitive) { 0436 doReadPrimitiveType(); 0437 d->m_dataPosition += ty.alignment; 0438 } else { 0439 doReadString(ty.alignment); 0440 if (unlikely(m_state == NeedMoreData)) { 0441 goto out_needMoreData; 0442 } 0443 } 0444 return; 0445 } 0446 } else { 0447 if (ty.isPrimitive || ty.isString) { 0448 return; // nothing to do! (readFoo() will return "random" data, so don't use that data!) 0449 } 0450 } 0451 0452 // now the interesting part: aggregates 0453 0454 switch (m_state) { 0455 case BeginStruct: 0456 VALID_IF(d->m_nesting.beginParen(), Error::MalformedMessageData); 0457 break; 0458 case EndStruct: 0459 if (!d->m_aggregateStack.size() || d->m_aggregateStack.back().aggregateType != BeginStruct) { 0460 assert(false); // should never happen due to the pre-validated signature 0461 } 0462 break; 0463 0464 case BeginVariant: { 0465 cstring signature; 0466 if (unlikely(d->m_nilArrayNesting)) { 0467 static const char *emptyString = ""; 0468 signature = cstring(emptyString, 0); 0469 } else { 0470 if (unlikely(d->m_dataPosition >= d->m_data.length)) { 0471 goto out_needMoreData; 0472 } 0473 signature.length = d->m_data.ptr[d->m_dataPosition++]; 0474 signature.ptr = reinterpret_cast<char *>(d->m_data.ptr) + d->m_dataPosition; 0475 d->m_dataPosition += signature.length + 1; 0476 if (unlikely(d->m_dataPosition > d->m_data.length)) { 0477 goto out_needMoreData; 0478 } 0479 VALID_IF(Arguments::isSignatureValid(signature, Arguments::VariantSignature), 0480 Error::MalformedMessageData); 0481 } 0482 // do not clobber nesting before potentially going to out_needMoreData! 0483 VALID_IF(d->m_nesting.beginVariant(), Error::MalformedMessageData); 0484 0485 // use m_u as temporary storage - its contents are undefined anyway in state BeginVariant 0486 m_u.String.ptr = signature.ptr; 0487 m_u.String.length = signature.length; 0488 break; } 0489 0490 case BeginArray: { 0491 // NB: Do not make non-idempotent changes to member variables before potentially going to 0492 // out_needMoreData! We'll make the same change again after getting more data. 0493 uint32 arrayLength = 0; 0494 if (likely(!d->m_nilArrayNesting)) { 0495 if (unlikely(d->m_dataPosition + sizeof(uint32) > d->m_data.length)) { 0496 goto out_needMoreData; 0497 } 0498 arrayLength = basic::readUint32(d->m_data.ptr + d->m_dataPosition, d->m_args->d->m_isByteSwapped); 0499 VALID_IF(arrayLength <= Arguments::MaxArrayLength, Error::MalformedMessageData); 0500 d->m_dataPosition += sizeof(uint32); 0501 } 0502 0503 if (d->m_signature.ptr[d->m_signaturePosition + 1] == '{') { 0504 m_state = BeginDict; 0505 } 0506 0507 uint32 dataEnd = d->m_dataPosition; 0508 // In case (and we don't check this) the internal type has greater alignment requirements than the 0509 // array index type (which aligns to 4 bytes), align to the nonexistent first element. 0510 // d->m_nilArrayNesting is only increased when the API client calls beginArray(), so 0511 // d->m_nilArrayNesting is the old state. As a side effect of that, it is possible to implement the 0512 // requirement that, in nested containers inside empty arrays, only the outermost array's first type 0513 // is used for alignment purposes. 0514 // TODO: unit-test this 0515 if (likely(!d->m_nilArrayNesting)) { 0516 const uint32 padStart = d->m_dataPosition; 0517 const uint32 alignment = m_state == BeginDict ? uint32(StructAlignment) : 0518 typeInfo(d->m_signature.ptr[d->m_signaturePosition + 1]).alignment; 0519 d->m_dataPosition = align(d->m_dataPosition, alignment); 0520 VALID_IF(isPaddingZero(d->m_data, padStart, d->m_dataPosition), Error::MalformedMessageData); 0521 dataEnd = d->m_dataPosition + arrayLength; 0522 if (unlikely(dataEnd > d->m_data.length)) { 0523 goto out_needMoreData; 0524 } 0525 } 0526 0527 VALID_IF(d->m_nesting.beginArray(), Error::MalformedMessageData); 0528 if (m_state == BeginDict) { 0529 // TODO check whether the first type is a primitive or string type! // ### isn't that already 0530 // checked for the main signature and / or variants, though? 0531 // only closed at end of dict - there is no observable difference for clients 0532 VALID_IF(d->m_nesting.beginParen(), Error::MalformedMessageData); 0533 } 0534 // temporarily store the future ArrayInfo::dataEnd in m_u.Uint32. used by {begin,skip}{Array,Dict}() 0535 m_u.Uint32 = dataEnd; 0536 break; } 0537 0538 default: 0539 assert(false); 0540 break; 0541 } 0542 0543 return; 0544 0545 out_needMoreData: 0546 // we only start an array when the data for it has fully arrived (possible due to the length 0547 // prefix), so if we still run out of data in an array the input is invalid. 0548 VALID_IF(!d->m_nesting.array, Error::MalformedMessageData); 0549 m_state = NeedMoreData; 0550 d->m_signaturePosition = savedSignaturePosition; 0551 d->m_dataPosition = savedDataPosition; 0552 } 0553 0554 void Arguments::Reader::skipArrayOrDictSignature(bool isDict) 0555 { 0556 // Note that we cannot just pass a dummy Nesting instance to parseSingleCompleteType, it must 0557 // actually check the nesting because an array may contain other nested aggregates. So we must 0558 // compensate for the already raised nesting levels from BeginArray handling in advanceState(). 0559 d->m_nesting.endArray(); 0560 if (isDict) { 0561 d->m_nesting.endParen(); 0562 // the Reader ad-hoc parsing code moved at ahead by one to skip the '{', but parseSingleCompleteType() 0563 // needs to see the full dict signature, so fix it up 0564 d->m_signaturePosition--; 0565 } 0566 0567 // parse the full (i.e. starting with the 'a') array (or dict) signature in order to skip it - 0568 // barring bugs, must have been too deep nesting inside variants if parsing fails 0569 cstring remainingSig(d->m_signature.ptr + d->m_signaturePosition, 0570 d->m_signature.length - d->m_signaturePosition); 0571 VALID_IF(parseSingleCompleteType(&remainingSig, &d->m_nesting), Error::MalformedMessageData); 0572 d->m_signaturePosition = d->m_signature.length - remainingSig.length; 0573 0574 // Compensate for pre-increment in advanceState() 0575 d->m_signaturePosition--; 0576 0577 d->m_nesting.beginArray(); 0578 if (isDict) { 0579 d->m_nesting.beginParen(); 0580 // Compensate for code in advanceState() that kind of ignores the '}' at the end of a dict. 0581 // Unlike advanceState(), parseSingleCompleteType() does properly parse that one. 0582 d->m_signaturePosition--; 0583 } 0584 } 0585 0586 bool Arguments::Reader::beginArray(EmptyArrayOption option) 0587 { 0588 if (unlikely(m_state != BeginArray)) { 0589 m_state = InvalidData; 0590 d->m_error.setCode(Error::ReadWrongType); 0591 return false; 0592 } 0593 0594 Private::AggregateInfo aggregateInfo; 0595 aggregateInfo.aggregateType = BeginArray; 0596 Private::ArrayInfo &arrayInfo = aggregateInfo.arr; // also used for dict 0597 arrayInfo.dataEnd = m_u.Uint32; 0598 arrayInfo.containedTypeBegin = d->m_signaturePosition + 1; 0599 d->m_aggregateStack.push_back(aggregateInfo); 0600 0601 const uint32 arrayLength = m_u.Uint32 - d->m_dataPosition; 0602 if (!arrayLength) { 0603 d->m_nilArrayNesting++; 0604 } 0605 0606 if (unlikely(d->m_nilArrayNesting && option == SkipIfEmpty)) { 0607 skipArrayOrDictSignature(false); 0608 } 0609 0610 advanceState(); 0611 return !d->m_nilArrayNesting; 0612 } 0613 0614 void Arguments::Reader::skipArrayOrDict(bool isDict) 0615 { 0616 // fast-forward the signature and data positions 0617 skipArrayOrDictSignature(isDict); 0618 d->m_dataPosition = m_u.Uint32; 0619 0620 // m_state = isDict ? EndDict : EndArray; // nobody looks at it 0621 if (isDict) { 0622 d->m_nesting.endParen(); 0623 d->m_signaturePosition++; // skip '}' 0624 } 0625 d->m_nesting.endArray(); 0626 0627 // proceed to next element 0628 advanceState(); 0629 } 0630 0631 void Arguments::Reader::skipArray() 0632 { 0633 if (unlikely(m_state != BeginArray)) { 0634 // TODO test this 0635 m_state = InvalidData; 0636 d->m_error.setCode(Error::ReadWrongType); 0637 } else { 0638 skipArrayOrDict(false); 0639 } 0640 } 0641 0642 void Arguments::Reader::endArray() 0643 { 0644 VALID_IF(m_state == EndArray, Error::ReadWrongType); 0645 d->m_signaturePosition--; // fix up for the pre-increment of d->m_signaturePosition in advanceState() 0646 d->m_nesting.endArray(); 0647 d->m_aggregateStack.pop_back(); 0648 if (unlikely(d->m_nilArrayNesting)) { 0649 d->m_nilArrayNesting--; 0650 } 0651 advanceState(); 0652 } 0653 0654 std::pair<Arguments::IoState, chunk> Arguments::Reader::readPrimitiveArray() 0655 { 0656 auto ret = std::make_pair(InvalidData, chunk()); 0657 0658 if (m_state != BeginArray) { 0659 return ret; 0660 } 0661 0662 // the point of "primitive array" accessors is that the data can be just memcpy()ed, so we 0663 // reject anything that needs validation, including booleans 0664 0665 const TypeInfo elementType = typeInfo(d->m_signature.ptr[d->m_signaturePosition + 1]); 0666 if (!elementType.isPrimitive || elementType.state() == Boolean || elementType.state() == UnixFd) { 0667 return ret; 0668 } 0669 if (d->m_args->d->m_isByteSwapped && elementType.state() != Byte) { 0670 return ret; 0671 } 0672 0673 const uint32 size = m_u.Uint32 - d->m_dataPosition; 0674 // does the end of data line up with the end of the last data element? 0675 if (!isAligned(size, elementType.alignment)) { 0676 return ret; 0677 } 0678 if (size) { 0679 ret.second.ptr = d->m_data.ptr + d->m_dataPosition; 0680 ret.second.length = size; 0681 } 0682 // No need to change d->m_nilArrayNesting - it can't be observed while "in" the current array 0683 0684 ret.first = elementType.state(); 0685 d->m_signaturePosition += 1; 0686 d->m_dataPosition = m_u.Uint32; 0687 m_state = EndArray; 0688 d->m_nesting.endArray(); 0689 0690 // ... leave the array, there is nothing more to do in it 0691 advanceState(); 0692 0693 return ret; 0694 } 0695 0696 Arguments::IoState Arguments::Reader::peekPrimitiveArray(EmptyArrayOption option) const 0697 { 0698 // almost duplicated from readPrimitiveArray(), so keep it in sync 0699 if (m_state != BeginArray) { 0700 return InvalidData; 0701 } 0702 const uint32 arrayLength = m_u.Uint32 - d->m_dataPosition; 0703 if (option == SkipIfEmpty && !arrayLength) { 0704 return BeginArray; 0705 } 0706 const TypeInfo elementType = typeInfo(d->m_signature.ptr[d->m_signaturePosition + 1]); 0707 if (!elementType.isPrimitive || elementType.state() == Boolean || elementType.state() == UnixFd) { 0708 return BeginArray; 0709 } 0710 if (d->m_args->d->m_isByteSwapped && elementType.state() != Byte) { 0711 return BeginArray; 0712 } 0713 return elementType.state(); 0714 } 0715 0716 bool Arguments::Reader::beginDict(EmptyArrayOption option) 0717 { 0718 if (unlikely(m_state != BeginDict)) { 0719 m_state = InvalidData; 0720 d->m_error.setCode(Error::ReadWrongType); 0721 return false; 0722 } 0723 0724 d->m_signaturePosition++; // skip '{` 0725 0726 Private::AggregateInfo aggregateInfo; 0727 aggregateInfo.aggregateType = BeginDict; 0728 Private::ArrayInfo &arrayInfo = aggregateInfo.arr; // also used for dict 0729 arrayInfo.dataEnd = m_u.Uint32; 0730 arrayInfo.containedTypeBegin = d->m_signaturePosition + 1; 0731 d->m_aggregateStack.push_back(aggregateInfo); 0732 0733 const uint32 arrayLength = m_u.Uint32 - d->m_dataPosition; 0734 if (!arrayLength) { 0735 d->m_nilArrayNesting++; 0736 } 0737 0738 if (unlikely(d->m_nilArrayNesting && option == SkipIfEmpty)) { 0739 skipArrayOrDictSignature(true); 0740 #ifdef WITH_DICT_ENTRY 0741 const bool ret = !d->m_nilArrayNesting; 0742 advanceState(); 0743 endDictEntry(); 0744 return ret; 0745 } 0746 m_state = BeginDictEntry; 0747 #else 0748 } 0749 0750 advanceState(); 0751 #endif 0752 return !d->m_nilArrayNesting; 0753 } 0754 0755 void Arguments::Reader::skipDict() 0756 { 0757 if (unlikely(m_state != BeginDict)) { 0758 // TODO test this 0759 m_state = InvalidData; 0760 d->m_error.setCode(Error::ReadWrongType); 0761 } else { 0762 d->m_signaturePosition++; // skip '{' like beginDict() does - skipArrayOrDict() expects it 0763 skipArrayOrDict(true); 0764 } 0765 } 0766 0767 bool Arguments::Reader::isDictKey() const 0768 { 0769 if (!d->m_aggregateStack.empty()) { 0770 const Private::AggregateInfo &aggregateInfo = d->m_aggregateStack.back(); 0771 return aggregateInfo.aggregateType == BeginDict && 0772 d->m_signaturePosition == aggregateInfo.arr.containedTypeBegin; 0773 } 0774 return false; 0775 } 0776 0777 void Arguments::Reader::endDict() 0778 { 0779 VALID_IF(m_state == EndDict, Error::ReadWrongType); 0780 d->m_nesting.endParen(); 0781 //d->m_signaturePosition++; // skip '}' 0782 //d->m_signaturePosition--; // fix up for the pre-increment of d->m_signaturePosition in advanceState() 0783 d->m_nesting.endArray(); 0784 d->m_aggregateStack.pop_back(); 0785 if (unlikely(d->m_nilArrayNesting)) { 0786 d->m_nilArrayNesting--; 0787 } 0788 advanceState(); 0789 } 0790 0791 #ifdef WITH_DICT_ENTRY 0792 void Arguments::Reader::beginDictEntry() 0793 { 0794 VALID_IF(m_state == BeginDictEntry, Error::ReadWrongType); 0795 advanceState(); 0796 } 0797 0798 void Arguments::Reader::endDictEntry() 0799 { 0800 VALID_IF(m_state == EndDictEntry, Error::ReadWrongType); 0801 if (m_u.Uint32 == 0) { 0802 m_state = BeginDictEntry; 0803 } else { 0804 m_state = EndDict; 0805 } 0806 } 0807 #endif 0808 0809 void Arguments::Reader::beginStruct() 0810 { 0811 VALID_IF(m_state == BeginStruct, Error::ReadWrongType); 0812 Private::AggregateInfo aggregateInfo; 0813 aggregateInfo.aggregateType = BeginStruct; 0814 d->m_aggregateStack.push_back(aggregateInfo); 0815 advanceState(); 0816 } 0817 0818 void Arguments::Reader::skipStruct() 0819 { 0820 if (unlikely(m_state != BeginStruct)) { 0821 m_state = InvalidData; 0822 d->m_error.setCode(Error::ReadWrongType); 0823 } else { 0824 skipCurrentElement(); 0825 } 0826 } 0827 0828 void Arguments::Reader::endStruct() 0829 { 0830 VALID_IF(m_state == EndStruct, Error::ReadWrongType); 0831 d->m_nesting.endParen(); 0832 d->m_aggregateStack.pop_back(); 0833 advanceState(); 0834 } 0835 0836 void Arguments::Reader::beginVariant() 0837 { 0838 VALID_IF(m_state == BeginVariant, Error::ReadWrongType); 0839 0840 Private::AggregateInfo aggregateInfo; 0841 aggregateInfo.aggregateType = BeginVariant; 0842 Private::VariantInfo &variantInfo = aggregateInfo.var; 0843 variantInfo.prevSignature.ptr = d->m_signature.ptr; 0844 variantInfo.prevSignature.length = d->m_signature.length; 0845 variantInfo.prevSignaturePosition = d->m_signaturePosition; 0846 d->m_aggregateStack.push_back(aggregateInfo); 0847 d->m_signature.ptr = m_u.String.ptr; 0848 d->m_signature.length = m_u.String.length; 0849 d->m_signaturePosition = uint32(-1); // we increment d->m_signaturePosition before reading a char 0850 0851 advanceState(); 0852 } 0853 0854 void Arguments::Reader::skipVariant() 0855 { 0856 if (unlikely(m_state != BeginVariant)) { 0857 m_state = InvalidData; 0858 d->m_error.setCode(Error::ReadWrongType); 0859 } else { 0860 skipCurrentElement(); 0861 } 0862 } 0863 0864 void Arguments::Reader::endVariant() 0865 { 0866 VALID_IF(m_state == EndVariant, Error::ReadWrongType); 0867 d->m_nesting.endVariant(); 0868 0869 const Private::AggregateInfo &aggregateInfo = d->m_aggregateStack.back(); 0870 const Private::VariantInfo &variantInfo = aggregateInfo.var; 0871 d->m_signature.ptr = variantInfo.prevSignature.ptr; 0872 d->m_signature.length = variantInfo.prevSignature.length; 0873 d->m_signaturePosition = variantInfo.prevSignaturePosition; 0874 d->m_aggregateStack.pop_back(); 0875 0876 advanceState(); 0877 } 0878 0879 void Arguments::Reader::skipCurrentElement() 0880 { 0881 // ### We could implement a skipping fast path for more aggregates, but it would be a lot of work, so 0882 // until it's proven to be a problem, just reuse what we have. 0883 0884 #ifndef NDEBUG 0885 Arguments::IoState stateOnEntry = m_state; 0886 #endif 0887 int nestingLevel = 0; 0888 bool isDone = false; 0889 0890 while (!isDone) { 0891 switch(state()) { 0892 case Arguments::Finished: 0893 // Okay, that's a bit weird. I guess the graceful way to handle it is do nothing in release 0894 // mode, and explode in debug mode in order to warn the API client. 0895 // (We could use a warning message facility here, make one?) 0896 assert(false); 0897 isDone = true; 0898 break; 0899 case Arguments::BeginStruct: 0900 beginStruct(); 0901 nestingLevel++; 0902 break; 0903 case Arguments::EndStruct: 0904 endStruct(); 0905 nestingLevel--; 0906 if (!nestingLevel) { 0907 assert(stateOnEntry == BeginStruct); 0908 } 0909 break; 0910 case Arguments::BeginVariant: 0911 beginVariant(); 0912 nestingLevel++; 0913 break; 0914 case Arguments::EndVariant: 0915 endVariant(); 0916 nestingLevel--; 0917 if (!nestingLevel) { 0918 assert(stateOnEntry == BeginVariant); 0919 } 0920 break; 0921 case Arguments::BeginArray: 0922 skipArray(); 0923 break; 0924 case Arguments::EndArray: 0925 assert(stateOnEntry == EndArray); // only way this can happen - we gracefully skip EndArray 0926 // and DON'T decrease nestingLevel b/c it would go negative. 0927 endArray(); 0928 break; 0929 case Arguments::BeginDict: 0930 skipDict(); 0931 break; 0932 #ifdef WITH_DICT_ENTRY 0933 case Arguments::BeginDictEntry: 0934 beginDictEntry(); 0935 break; 0936 case Arguments::EndDictEntry: 0937 endDictEntry(); 0938 break; 0939 #endif 0940 case Arguments::EndDict: 0941 assert(stateOnEntry == EndDict); // only way this can happen - we gracefully "skip" EndDict 0942 // and DON'T decrease nestingLevel b/c it would go negative. 0943 endDict(); 0944 break; 0945 case Arguments::Boolean: 0946 readBoolean(); 0947 break; 0948 case Arguments::Byte: 0949 readByte(); 0950 break; 0951 case Arguments::Int16: 0952 readInt16(); 0953 break; 0954 case Arguments::Uint16: 0955 readUint16(); 0956 break; 0957 case Arguments::Int32: 0958 readInt32(); 0959 break; 0960 case Arguments::Uint32: 0961 readUint32(); 0962 break; 0963 case Arguments::Int64: 0964 readInt64(); 0965 break; 0966 case Arguments::Uint64: 0967 readUint64(); 0968 break; 0969 case Arguments::Double: 0970 readDouble(); 0971 break; 0972 case Arguments::String: 0973 readString(); 0974 break; 0975 case Arguments::ObjectPath: 0976 readObjectPath(); 0977 break; 0978 case Arguments::Signature: 0979 readSignature(); 0980 break; 0981 case Arguments::UnixFd: 0982 readUnixFd(); 0983 break; 0984 case Arguments::NeedMoreData: 0985 // TODO handle this properly: rewind the state to before the aggregate - or get fancy and support 0986 // resuming, but that is going to get really ugly 0987 // fall through 0988 default: 0989 m_state = InvalidData; 0990 d->m_error.setCode(Error::StateNotSkippable); 0991 // fall through 0992 case Arguments::InvalidData: 0993 isDone = true; 0994 break; 0995 } 0996 if (!nestingLevel) { 0997 isDone = true; 0998 } 0999 } 1000 } 1001 1002 std::vector<Arguments::IoState> Arguments::Reader::aggregateStack() const 1003 { 1004 std::vector<IoState> ret; 1005 ret.reserve(d->m_aggregateStack.size()); 1006 for (Private::AggregateInfo &aggregate : d->m_aggregateStack) { 1007 ret.push_back(aggregate.aggregateType); 1008 } 1009 return ret; 1010 } 1011 1012 uint32 Arguments::Reader::aggregateDepth() const 1013 { 1014 return d->m_aggregateStack.size(); 1015 } 1016 1017 Arguments::IoState Arguments::Reader::currentAggregate() const 1018 { 1019 if (d->m_aggregateStack.empty()) { 1020 return NotStarted; 1021 } 1022 return d->m_aggregateStack.back().aggregateType; 1023 }