Warning, file /sdk/dferry/serialization/arguments.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
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 #ifndef ARGUMENTS_H 0025 #define ARGUMENTS_H 0026 0027 #include "export.h" 0028 #include "types.h" 0029 0030 #include <cassert> 0031 #include <string> 0032 #include <vector> 0033 0034 class Error; 0035 class Message; 0036 class MessagePrivate; 0037 0038 //#define WITH_DICT_ENTRY 0039 0040 class DFERRY_EXPORT Arguments 0041 { 0042 public: 0043 class Reader; 0044 class Writer; 0045 0046 enum SignatureType 0047 { 0048 MethodSignature = 0, 0049 VariantSignature 0050 }; 0051 0052 enum 0053 { 0054 MaxSignatureLength = 255, 0055 MaxArrayLength = 1 << 26, // 64 MiB 0056 MaxMessageLength = 1 << 27 // 128 MiB 0057 // MaxMessageLength applies to a full Message (and it IS checked in Message when the message is 0058 // complete), which also implies a max size for Arguments. Instead of working out the exact minimum 0059 // size of the header part of a Message (which depends on too many variables), just allow the max 0060 // Message length as max Arguments length. 0061 // The way the limit is defined in the spec seems tied a bit too closely to the design of libdbus-1... 0062 }; 0063 0064 enum IoState 0065 { 0066 // "exceptional" states 0067 NotStarted = 0, 0068 Finished, 0069 NeedMoreData, // recoverable by adding data; should only happen when parsing the not length-prefixed variable message header 0070 InvalidData, // non-recoverable 0071 // Writer states when the next type is still open (not iterating in an array or dict) 0072 // ### it is inconsistent to have DictKey, but nothing for other constraints. The name AnyData is 0073 // also weird. Remove DictKey and call AnyData InputData? 0074 AnyData, // occurs in Writer when you are free to add any type 0075 DictKey, // occurs in Writer when the next type must be suitable for a dict key - 0076 // a simple string or numeric type. 0077 0078 // the following occur in Reader, and in Writer when in the second or higher iteration 0079 // of an array or dict where the types must match the first iteration (except inside variants). 0080 0081 // states pertaining to aggregates 0082 BeginArray, 0083 EndArray, 0084 BeginDict, 0085 EndDict, 0086 BeginStruct, // 10 0087 EndStruct, 0088 BeginVariant, 0089 EndVariant, 0090 // the next element is plain data 0091 Boolean, 0092 Byte, 0093 Int16, 0094 Uint16, 0095 Int32, 0096 Uint32, 0097 Int64, // 20 0098 Uint64, 0099 Double, 0100 String, 0101 ObjectPath, 0102 Signature, 0103 UnixFd, 0104 #ifdef WITH_DICT_ENTRY 0105 BeginDictEntry, 0106 EndDictEntry, 0107 #endif 0108 LastState 0109 }; 0110 0111 // Constructs an empty argument list 0112 Arguments(); 0113 0114 // Constructs an argument list to deserialize data in @p data with signature @p signature; 0115 // if memOwnership is non-null, this means that signature and data's memory is contained in 0116 // a malloc()ed block starting at memOwnership, and ~Arguments will free it. 0117 // Otherwise, the instance assumes that @p signature and @p data live in "borrowed" memory and 0118 // you need to make sure that the memory lives as long as the Arguments. 0119 // (A notable user of this is Message - you can only get a const ref to its internal Arguments 0120 // so you need to copy to take the Arguments away from the Message, which copies out of the 0121 // borrowed memory into heap memory so the copy is safe) 0122 // The copy contructor and assignment operator will always copy the data, so copying is safe 0123 // regarding memory correctness but has a significant performance impact. 0124 Arguments(byte *memOwnership, cstring signature, chunk data, bool isByteSwapped = false); 0125 0126 // Same thing as above, with file descriptors added 0127 Arguments(byte *memOwnership, cstring signature, chunk data, 0128 std::vector<int> fileDescriptors, bool isByteSwapped = false); 0129 0130 // use these wherever possible if you care at all about efficiency!! 0131 Arguments(Arguments &&other); 0132 Arguments &operator=(Arguments &&other); 0133 0134 // copying needs special treatment due to the d-pointer 0135 Arguments(const Arguments &other); 0136 Arguments &operator=(const Arguments &other); 0137 0138 ~Arguments(); 0139 0140 // error (if any) propagates to Message, so it is still available later 0141 Error error() const; 0142 0143 std::string prettyPrint() const; 0144 0145 cstring signature() const; 0146 chunk data() const; 0147 const std::vector<int> &fileDescriptors() const; 0148 bool isByteSwapped() const; 0149 0150 static bool isStringValid(cstring string); 0151 static bool isObjectPathValid(cstring objectPath); 0152 static bool isObjectPathElementValid(cstring pathElement); 0153 static bool isSignatureValid(cstring signature, SignatureType type = MethodSignature); 0154 0155 static void copyOneElement(Reader *reader, Writer *writer); 0156 0157 private: 0158 struct podCstring // Same as cstring but without ctor. 0159 // Can't put the cstring type into a union because it has a constructor :/ 0160 { 0161 char *ptr; 0162 uint32 length; 0163 }; 0164 0165 typedef union 0166 { 0167 byte Byte; 0168 bool Boolean; 0169 int16 Int16; 0170 uint16 Uint16; 0171 int32 Int32; 0172 uint32 Uint32; 0173 int64 Int64; 0174 uint64 Uint64; 0175 double Double; 0176 podCstring String; // also for ObjectPath and Signature 0177 } DataUnion; 0178 0179 public: 0180 // error handling is done by asking state() or isError(), not by method return values. 0181 // occasionally looking at isError() is less work than checking every call. 0182 class DFERRY_EXPORT Reader 0183 { 0184 public: 0185 explicit Reader(const Arguments &al); 0186 explicit Reader(const Message &msg); 0187 Reader(Reader &&other); 0188 void operator=(Reader &&other); 0189 // TODO unit-test copy and assignment 0190 Reader(const Reader &other); 0191 void operator=(const Reader &other); 0192 0193 ~Reader(); 0194 0195 bool isValid() const; 0196 Error error() const; // see also: aggregateStack() 0197 0198 IoState state() const { return m_state; } 0199 cstring stateString() const; 0200 bool isInsideEmptyArray() const; 0201 cstring currentSignature() const; // current signature, either main signature or current variant 0202 uint32 currentSignaturePosition() const; 0203 cstring currentSingleCompleteTypeSignature() const; 0204 // HACK call this in NeedMoreData state when more data has been added; this replaces m_data 0205 // WARNING: calling replaceData() invalidates copies (if any) of this Reader 0206 void replaceData(chunk data); 0207 0208 bool isFinished() const { return m_state == Finished; } 0209 bool isError() const { return m_state == InvalidData || m_state == NeedMoreData; } // TODO remove 0210 0211 enum EmptyArrayOption 0212 { 0213 SkipIfEmpty = 0, 0214 ReadTypesOnlyIfEmpty 0215 }; 0216 0217 // Start reading an array. @p option changes behavior in case the array is empty, i.e. it has 0218 // zero elements. Empty arrays still contain types, which may be of interest. 0219 // If @p option == SkipIfEmpty, empty arrays will work according to the usual rules: 0220 // you call nextArrayEntry() and it returns false, you call endArray() and proceed to the next 0221 // value or aggregate. 0222 // If @p option == ReadTypesOnlyIfEmpty, you will be taken on a single iteration through the array 0223 // if it is empty, which makes it possible to extract the type(s) of data inside the array. In 0224 // that mode, all data returned from read...() is undefined and should be discarded. Only use state() 0225 // to get the types and call read...() purely to move from one type to the next. 0226 // Empty arrays are handled that way for symmetry with regular data extraction code so that very 0227 // similar code can handle empty and nonempty arrays. 0228 // 0229 // The return value is false if the array is empty (has 0 elements), true if it has >= 1 elements. 0230 // The return value is not affected by @p option. 0231 bool beginArray(EmptyArrayOption option = SkipIfEmpty); 0232 void skipArray(); // skips the current array; only call this in state BeginArray! 0233 void endArray(); // leaves the current array; only call this in state EndArray! 0234 0235 bool beginDict(EmptyArrayOption option = SkipIfEmpty); 0236 void skipDict(); // like skipArray() 0237 bool isDictKey() const; // this can be used to track whether the current value is a dict key or value, e.g. 0238 // for pretty-printing purposes (it is usually clear in marshalling code). 0239 void endDict(); // like endArray() 0240 0241 void beginStruct(); 0242 void skipStruct(); // like skipArray() 0243 void endStruct(); // like endArray() 0244 0245 void beginVariant(); 0246 void skipVariant(); // like skipArray(); 0247 void endVariant(); // like endArray() 0248 0249 std::vector<IoState> aggregateStack() const; // the aggregates the reader is currently in 0250 uint32 aggregateDepth() const; // like calling aggregateStack().size() but much faster 0251 IoState currentAggregate() const; // the innermost aggregate, NotStarted if not in an aggregate 0252 0253 // reading a type that is not indicated by state() will cause undefined behavior and at 0254 // least return garbage. 0255 byte readByte() { byte ret = m_u.Byte; advanceState(); return ret; } 0256 bool readBoolean() { bool ret = m_u.Boolean; advanceState(); return ret; } 0257 int16 readInt16() { int ret = m_u.Int16; advanceState(); return ret; } 0258 uint16 readUint16() { uint16 ret = m_u.Uint16; advanceState(); return ret; } 0259 int32 readInt32() { int32 ret = m_u.Int32; advanceState(); return ret; } 0260 uint32 readUint32() { uint32 ret = m_u.Uint32; advanceState(); return ret; } 0261 int64 readInt64() { int64 ret = m_u.Int64; advanceState(); return ret; } 0262 uint64 readUint64() { uint64 ret = m_u.Uint64; advanceState(); return ret; } 0263 double readDouble() { double ret = m_u.Double; advanceState(); return ret; } 0264 cstring readString() { cstring ret(m_u.String.ptr, m_u.String.length); advanceState(); return ret; } 0265 cstring readObjectPath() { cstring ret(m_u.String.ptr, m_u.String.length); advanceState(); return ret; } 0266 cstring readSignature() { cstring ret(m_u.String.ptr, m_u.String.length); advanceState(); return ret; } 0267 int32 readUnixFd() { int32 ret = m_u.Int32; advanceState(); return ret; } 0268 0269 void skipCurrentElement(); // works on single values and Begin... states. In the Begin... states, 0270 // skips the whole aggregate. 0271 0272 // Returns primitive type and the raw array data if in BeginArray state of an array containing only a 0273 // primitive type. You must copy the data before destroying the Reader or changing its backing store 0274 // with replaceData(). 0275 // If the array is empty, that does not constitute a special case with this function: It will return 0276 // the type in the first return value as usual and an empty chunk in the second return value. 0277 // (### it might be possible to extend this feature to all fixed-length types including structs) 0278 std::pair<Arguments::IoState, chunk> readPrimitiveArray(); 0279 // In state BeginArray, check if the array is a primitive array, in order to check whether to use 0280 // readPrimitiveArray(). Returns a primitive type if readPrimitiveArray() will succeed, BeginArray 0281 // if the array is not primitive, InvalidData if state is not BeginArray. The latter will not put 0282 // the reader in InvalidData state. 0283 // If option is SkipIfEmpty, an empty array of primitives will result in a return value of BeginArray 0284 // instead of the type of primitive. 0285 Arguments::IoState peekPrimitiveArray(EmptyArrayOption option = SkipIfEmpty) const; 0286 0287 #ifdef WITH_DICT_ENTRY 0288 void beginDictEntry(); 0289 void endDictEntry(); 0290 #endif 0291 0292 class Private; 0293 friend class Private; 0294 0295 private: 0296 void beginRead(); 0297 void doReadPrimitiveType(); 0298 void doReadString(uint32 lengthPrefixSize); 0299 void advanceState(); 0300 void beginArrayOrDict(bool isDict, EmptyArrayOption option); 0301 void skipArrayOrDictSignature(bool isDict); 0302 void skipArrayOrDict(bool isDict); 0303 0304 Private *d; 0305 0306 // two data members not behind d-pointer for performance reasons, especially inlining 0307 IoState m_state; 0308 0309 // it is more efficient, in code size and performance, to read the data in advanceState() 0310 // and store the result for later retrieval in readFoo() 0311 DataUnion m_u; 0312 }; 0313 0314 class DFERRY_EXPORT Writer 0315 { 0316 public: 0317 explicit Writer(); 0318 Writer(Writer &&other); 0319 void operator=(Writer &&other); 0320 // TODO unit-test copy and assignment 0321 Writer(const Writer &other); 0322 void operator=(const Writer &other); 0323 0324 ~Writer(); 0325 0326 bool isValid() const; 0327 // error propagates to Arguments (if the error wasn't that the Arguments is not writable), 0328 // so it is still available later 0329 Error error() const; // see also: aggregateStack() 0330 0331 IoState state() const { return m_state; } 0332 cstring stateString() const; 0333 bool isInsideEmptyArray() const; 0334 cstring currentSignature() const; // current signature, either main signature or current variant 0335 uint32 currentSignaturePosition() const; 0336 0337 enum ArrayOption 0338 { 0339 NonEmptyArray = 0, 0340 WriteTypesOfEmptyArray, 0341 RestartEmptyArrayToWriteTypes 0342 }; 0343 0344 void beginArray(ArrayOption option = NonEmptyArray); 0345 void endArray(); 0346 0347 void beginDict(ArrayOption option = NonEmptyArray); 0348 void endDict(); 0349 0350 void beginStruct(); 0351 void endStruct(); 0352 0353 void beginVariant(); 0354 void endVariant(); 0355 0356 Arguments finish(); 0357 0358 std::vector<IoState> aggregateStack() const; // the aggregates the writer is currently in 0359 uint32 aggregateDepth() const; // like calling aggregateStack().size() but much faster 0360 IoState currentAggregate() const; // the innermost aggregate, NotStarted if not in an aggregate 0361 0362 void writeByte(byte b); 0363 void writeBoolean(bool b); 0364 void writeInt16(int16 i); 0365 void writeUint16(uint16 i); 0366 void writeInt32(int32 i); 0367 void writeUint32(uint32 i); 0368 void writeInt64(int64 i); 0369 void writeUint64(uint64 i); 0370 void writeDouble(double d); 0371 void writeString(cstring string); 0372 void writeObjectPath(cstring objectPath); 0373 void writeSignature(cstring signature); 0374 void writeUnixFd(int32 fd); 0375 0376 void writePrimitiveArray(IoState type, chunk data); 0377 0378 // Return the current serialized data; if the current state of writing has any aggregates open 0379 // OR is in an error state, return an empty chunk (instead of invalid serialized data). 0380 // After (or before - this method is const!) an empty chunk is returned, you can find out why 0381 // using state(), isValid(), and currentAggregate(). 0382 // The returned memory is only valid as long as the Writer is not mutated in any way! 0383 // If successful, the returned data can be used together with currentSignature() and 0384 // fileDescriptors() to construct a temporary Arguments as a strucrured view into the data. 0385 chunk peekSerializedData() const; 0386 const std::vector<int> &fileDescriptors() const; 0387 0388 #ifdef WITH_DICT_ENTRY 0389 void beginDictEntry(); 0390 void endDictEntry(); 0391 #endif 0392 0393 class Private; 0394 friend class Private; 0395 0396 private: 0397 friend class MessagePrivate; 0398 void writeVariantForMessageHeader(char sig); // faster variant for typical message headers; 0399 // does not work for nested variants which aren't needed for message headers. Also does not 0400 // change the aggregate stack, but Message knows how to handle it. 0401 void fixupAfterWriteVariantForMessageHeader(); 0402 0403 void doWritePrimitiveType(IoState type, uint32 alignAndSize); 0404 void doWriteString(IoState type, uint32 lengthPrefixSize); 0405 void advanceState(cstring signatureFragment, IoState newState); 0406 void beginArrayOrDict(IoState beginWhat, ArrayOption option); 0407 void flushQueuedData(); 0408 0409 Private *d; 0410 0411 // two data members not behind d-pointer for performance reasons 0412 IoState m_state; 0413 0414 // ### check if it makes any performance difference to have this here (writeFoo() should benefit) 0415 DataUnion m_u; 0416 }; 0417 0418 class Private; 0419 0420 private: 0421 Private *d; 0422 }; 0423 0424 #endif // ARGUMENTS_H