├── .gitignore ├── Debug ├── lpclib.dll ├── netmonlog.exe ├── netmonset.exe ├── uframe.dll ├── ulpc_32.dll ├── ulpc_64.dll └── ulpc_64_32.dll ├── README.md ├── include └── netmon_i.h ├── json ├── autolink.h ├── config.h ├── features.h ├── forwards.h ├── json.h ├── jsoncpp.hpp ├── reader.h ├── src │ ├── json_batchallocator.h │ ├── json_internalarray.inl │ ├── json_internalmap.inl │ ├── json_reader.cpp │ ├── json_value.cpp │ ├── json_valueiterator.inl │ └── json_writer.cpp ├── value.h └── writer.h ├── netmon.sln ├── netmonlog ├── netmonlog.cpp ├── netmonlog.rc ├── netmonlog.vcxproj ├── netmonlog.vcxproj.filters ├── pch.cpp ├── pch.h └── resource.h ├── netmonset ├── cconv.h ├── netmonset.cpp ├── netmonset.rc ├── netmonset.vcxproj ├── netmonset.vcxproj.filters ├── netmonset.vcxproj.user ├── pch.cpp ├── pch.h └── resource.h ├── netmonsys ├── AutoVersion.exe ├── CDnsDomainParse.cpp ├── CDnsDomainParse.h ├── CDnsTask.cpp ├── CDnsTask.h ├── CFlowContext.cpp ├── CFlowContext.h ├── CIPTask.cpp ├── CIPTask.h ├── CMetaValue.cpp ├── CMetaValue.h ├── CTaskBase.cpp ├── CTaskBase.h ├── CTaskCenter.h ├── CalloutImpl.cpp ├── CalloutImpl.h ├── Callouts.cpp ├── Callouts.h ├── ClassDefine.cpp ├── ClassDefine.h ├── NetMonDevice.cpp ├── NetMonDevice.h ├── WfpHelp.cpp ├── WfpHelp.h ├── deelx.h ├── main.cpp ├── netmonsys.inf ├── netmonsys.rc ├── netmonsys.vcxproj ├── netmonsys.vcxproj.filters ├── resource.h ├── slre.cpp ├── slre.h ├── stdafx.h └── windns.h └── 工程说明.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /Debug/lpclib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/Debug/lpclib.dll -------------------------------------------------------------------------------- /Debug/netmonlog.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/Debug/netmonlog.exe -------------------------------------------------------------------------------- /Debug/netmonset.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/Debug/netmonset.exe -------------------------------------------------------------------------------- /Debug/uframe.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/Debug/uframe.dll -------------------------------------------------------------------------------- /Debug/ulpc_32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/Debug/ulpc_32.dll -------------------------------------------------------------------------------- /Debug/ulpc_64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/Debug/ulpc_64.dll -------------------------------------------------------------------------------- /Debug/ulpc_64_32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/Debug/ulpc_64_32.dll -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # netmonsys 2 | a net filter driver developed by wfp and **[msddk](https://github.com/ZhanLang/msddk)** 3 | 4 | this is an example for how to use msddk develop drives. 5 | 6 | 7 | -------------------------------------------------------------------------------- /include/netmon_i.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/include/netmon_i.h -------------------------------------------------------------------------------- /json/autolink.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_AUTOLINK_H_INCLUDED 2 | # define JSON_AUTOLINK_H_INCLUDED 3 | 4 | # include "config.h" 5 | 6 | # ifdef JSON_IN_CPPTL 7 | # include 8 | # endif 9 | 10 | # if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) 11 | # define CPPTL_AUTOLINK_NAME "json" 12 | # undef CPPTL_AUTOLINK_DLL 13 | # ifdef JSON_DLL 14 | # define CPPTL_AUTOLINK_DLL 15 | # endif 16 | # include "autolink.h" 17 | # endif 18 | 19 | #endif // JSON_AUTOLINK_H_INCLUDED 20 | -------------------------------------------------------------------------------- /json/config.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_CONFIG_H_INCLUDED 2 | # define JSON_CONFIG_H_INCLUDED 3 | 4 | /// If defined, indicates that json library is embedded in CppTL library. 5 | //# define JSON_IN_CPPTL 1 6 | 7 | /// If defined, indicates that json may leverage CppTL library 8 | //# define JSON_USE_CPPTL 1 9 | /// If defined, indicates that cpptl vector based map should be used instead of std::map 10 | /// as Value container. 11 | //# define JSON_USE_CPPTL_SMALLMAP 1 12 | /// If defined, indicates that Json specific container should be used 13 | /// (hash table & simple deque container with customizable allocator). 14 | /// THIS FEATURE IS STILL EXPERIMENTAL! 15 | //# define JSON_VALUE_USE_INTERNAL_MAP 1 16 | /// Force usage of standard new/malloc based allocator instead of memory pool based allocator. 17 | /// The memory pools allocator used optimization (initializing Value and ValueInternalLink 18 | /// as if it was a POD) that may cause some validation tool to report errors. 19 | /// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. 20 | //# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 21 | 22 | /// If defined, indicates that Json use exception to report invalid type manipulation 23 | /// instead of C assert macro. 24 | # define JSON_USE_EXCEPTION 1 25 | 26 | # ifdef JSON_IN_CPPTL 27 | # include 28 | # ifndef JSON_USE_CPPTL 29 | # define JSON_USE_CPPTL 1 30 | # endif 31 | # endif 32 | 33 | # ifdef JSON_IN_CPPTL 34 | # define JSON_API CPPTL_API 35 | # elif defined(JSON_DLL_BUILD) 36 | # define JSON_API __declspec(dllexport) 37 | # elif defined(JSON_DLL) 38 | # define JSON_API __declspec(dllimport) 39 | # else 40 | # define JSON_API 41 | # endif 42 | 43 | #endif // JSON_CONFIG_H_INCLUDED 44 | -------------------------------------------------------------------------------- /json/features.h: -------------------------------------------------------------------------------- 1 | #ifndef CPPTL_JSON_FEATURES_H_INCLUDED 2 | # define CPPTL_JSON_FEATURES_H_INCLUDED 3 | 4 | # include "forwards.h" 5 | 6 | namespace Json { 7 | 8 | /** \brief Configuration passed to reader and writer. 9 | * This configuration object can be used to force the Reader or Writer 10 | * to behave in a standard conforming way. 11 | */ 12 | class JSON_API Features 13 | { 14 | public: 15 | /** \brief A configuration that allows all features and assumes all strings are UTF-8. 16 | * - C & C++ comments are allowed 17 | * - Root object can be any JSON value 18 | * - Assumes Value strings are encoded in UTF-8 19 | */ 20 | static Features all(); 21 | 22 | /** \brief A configuration that is strictly compatible with the JSON specification. 23 | * - Comments are forbidden. 24 | * - Root object must be either an array or an object value. 25 | * - Assumes Value strings are encoded in UTF-8 26 | */ 27 | static Features strictMode(); 28 | 29 | /** \brief Initialize the configuration like JsonConfig::allFeatures; 30 | */ 31 | Features(); 32 | 33 | /// \c true if comments are allowed. Default: \c true. 34 | bool allowComments_; 35 | 36 | /// \c true if root must be either an array or an object value. Default: \c false. 37 | bool strictRoot_; 38 | }; 39 | 40 | } // namespace Json 41 | 42 | #endif // CPPTL_JSON_FEATURES_H_INCLUDED 43 | -------------------------------------------------------------------------------- /json/forwards.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_FORWARDS_H_INCLUDED 2 | # define JSON_FORWARDS_H_INCLUDED 3 | 4 | # include "config.h" 5 | 6 | namespace Json { 7 | 8 | // writer.h 9 | class FastWriter; 10 | class StyledWriter; 11 | 12 | // reader.h 13 | class Reader; 14 | 15 | // features.h 16 | class Features; 17 | 18 | // value.h 19 | typedef int Int; 20 | typedef unsigned int UInt; 21 | class StaticString; 22 | class Path; 23 | class PathArgument; 24 | class Value; 25 | class ValueIteratorBase; 26 | class ValueIterator; 27 | class ValueConstIterator; 28 | #ifdef JSON_VALUE_USE_INTERNAL_MAP 29 | class ValueAllocator; 30 | class ValueMapAllocator; 31 | class ValueInternalLink; 32 | class ValueInternalArray; 33 | class ValueInternalMap; 34 | #endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP 35 | 36 | } // namespace Json 37 | 38 | 39 | #endif // JSON_FORWARDS_H_INCLUDED 40 | -------------------------------------------------------------------------------- /json/json.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_JSON_H_INCLUDED 2 | # define JSON_JSON_H_INCLUDED 3 | 4 | # include "autolink.h" 5 | # include "value.h" 6 | # include "reader.h" 7 | # include "writer.h" 8 | # include "features.h" 9 | 10 | /* 11 | 12 | #ifdef _MT 13 | # ifdef _DEBUG 14 | # ifdef _X64 15 | # pragma comment(lib, "jsoncpp_64_d_mt.lib") 16 | # else 17 | # pragma comment(lib, "jsoncpp_d_mt.lib") 18 | # endif // _X64 19 | # else 20 | # ifdef _X64 21 | # pragma comment(lib, "jsoncpp_64_r_mt.lib") 22 | # else 23 | # pragma comment(lib, "jsoncpp_r_mt.lib") 24 | # endif // _X64 25 | # endif 26 | #else 27 | # ifdef _DEBUG 28 | # ifdef _X64 29 | # pragma comment(lib, "jsoncpp_64_d.lib") 30 | # else 31 | # pragma comment(lib, "jsoncpp_d.lib") 32 | # endif // _X64 33 | # else 34 | # ifdef _X64 35 | # pragma comment(lib, "jsoncpp_64_r.lib") 36 | # else 37 | # pragma comment(lib, "jsoncpp_r_.lib") 38 | # endif // _X64 39 | # endif 40 | #endif 41 | 42 | */ 43 | #endif // JSON_JSON_H_INCLUDED 44 | -------------------------------------------------------------------------------- /json/jsoncpp.hpp: -------------------------------------------------------------------------------- 1 | #include "src/json_reader.cpp" 2 | #include "src/json_value.cpp" 3 | #include "src/json_writer.cpp" -------------------------------------------------------------------------------- /json/reader.h: -------------------------------------------------------------------------------- 1 | #ifndef CPPTL_JSON_READER_H_INCLUDED 2 | # define CPPTL_JSON_READER_H_INCLUDED 3 | 4 | # include "features.h" 5 | # include "value.h" 6 | # include 7 | # include 8 | # include 9 | # include 10 | 11 | namespace Json { 12 | 13 | /** \brief Unserialize a JSON document into a Value. 14 | * 15 | */ 16 | class JSON_API Reader 17 | { 18 | public: 19 | typedef char Char; 20 | typedef const Char *Location; 21 | 22 | /** \brief Constructs a Reader allowing all features 23 | * for parsing. 24 | */ 25 | Reader(); 26 | 27 | /** \brief Constructs a Reader allowing the specified feature set 28 | * for parsing. 29 | */ 30 | Reader( const Features &features ); 31 | 32 | /** \brief Read a Value from a JSON document. 33 | * \param document UTF-8 encoded string containing the document to read. 34 | * \param root [out] Contains the root value of the document if it was 35 | * successfully parsed. 36 | * \param collectComments \c true to collect comment and allow writing them back during 37 | * serialization, \c false to discard comments. 38 | * This parameter is ignored if Features::allowComments_ 39 | * is \c false. 40 | * \return \c true if the document was successfully parsed, \c false if an error occurred. 41 | */ 42 | bool parse( const std::string &document, 43 | Value &root, 44 | bool collectComments = true ); 45 | 46 | bool parse( const std::wstring &document, 47 | Value &root, 48 | bool collectComments = true ); 49 | 50 | /** \brief Read a Value from a JSON document. 51 | * \param document UTF-8 encoded string containing the document to read. 52 | * \param root [out] Contains the root value of the document if it was 53 | * successfully parsed. 54 | * \param collectComments \c true to collect comment and allow writing them back during 55 | * serialization, \c false to discard comments. 56 | * This parameter is ignored if Features::allowComments_ 57 | * is \c false. 58 | * \return \c true if the document was successfully parsed, \c false if an error occurred. 59 | */ 60 | bool parse( const char *beginDoc, const char *endDoc, 61 | Value &root, 62 | bool collectComments = true ); 63 | 64 | /// \brief Parse from input stream. 65 | /// \see Json::operator>>(std::istream&, Json::Value&). 66 | bool parse( std::istream &is, 67 | Value &root, 68 | bool collectComments = true ); 69 | 70 | /** \brief Returns a user friendly string that list errors in the parsed document. 71 | * \return Formatted error message with the list of errors with their location in 72 | * the parsed document. An empty string is returned if no error occurred 73 | * during parsing. 74 | */ 75 | std::string getFormatedErrorMessages() const; 76 | 77 | private: 78 | enum TokenType 79 | { 80 | tokenEndOfStream = 0, 81 | tokenObjectBegin, 82 | tokenObjectEnd, 83 | tokenArrayBegin, 84 | tokenArrayEnd, 85 | tokenString, 86 | tokenNumber, 87 | tokenTrue, 88 | tokenFalse, 89 | tokenNull, 90 | tokenArraySeparator, 91 | tokenMemberSeparator, 92 | tokenComment, 93 | tokenError 94 | }; 95 | 96 | class Token 97 | { 98 | public: 99 | TokenType type_; 100 | Location start_; 101 | Location end_; 102 | }; 103 | 104 | class ErrorInfo 105 | { 106 | public: 107 | Token token_; 108 | std::string message_; 109 | Location extra_; 110 | }; 111 | 112 | typedef std::deque Errors; 113 | 114 | bool expectToken( TokenType type, Token &token, const char *message ); 115 | bool readToken( Token &token ); 116 | void skipSpaces(); 117 | bool match( Location pattern, 118 | int patternLength ); 119 | bool readComment(); 120 | bool readCStyleComment(); 121 | bool readCppStyleComment(); 122 | bool readString(); 123 | void readNumber(); 124 | bool readValue(); 125 | bool readObject( Token &token ); 126 | bool readArray( Token &token ); 127 | bool decodeNumber( Token &token ); 128 | bool decodeString( Token &token ); 129 | bool decodeString( Token &token, std::string &decoded ); 130 | bool decodeDouble( Token &token ); 131 | bool decodeUnicodeCodePoint( Token &token, 132 | Location ¤t, 133 | Location end, 134 | unsigned int &unicode ); 135 | bool decodeUnicodeEscapeSequence( Token &token, 136 | Location ¤t, 137 | Location end, 138 | unsigned int &unicode ); 139 | bool addError( const std::string &message, 140 | Token &token, 141 | Location extra = 0 ); 142 | bool recoverFromError( TokenType skipUntilToken ); 143 | bool addErrorAndRecover( const std::string &message, 144 | Token &token, 145 | TokenType skipUntilToken ); 146 | void skipUntilSpace(); 147 | Value ¤tValue(); 148 | Char getNextChar(); 149 | void getLocationLineAndColumn( Location location, 150 | int &line, 151 | int &column ) const; 152 | std::string getLocationLineAndColumn( Location location ) const; 153 | void addComment( Location begin, 154 | Location end, 155 | CommentPlacement placement ); 156 | void skipCommentTokens( Token &token ); 157 | 158 | typedef std::stack Nodes; 159 | Nodes nodes_; 160 | Errors errors_; 161 | std::string document_; 162 | Location begin_; 163 | Location end_; 164 | Location current_; 165 | Location lastValueEnd_; 166 | Value *lastValue_; 167 | std::string commentsBefore_; 168 | Features features_; 169 | bool collectComments_; 170 | }; 171 | 172 | 173 | 174 | /** \brief Read from 'sin' into 'root'. 175 | 176 | Always keep comments from the input JSON. 177 | 178 | This can be used to read a file into a particular sub-object. 179 | For example: 180 | \code 181 | Json::Value root; 182 | cin >> root["dir"]["file"]; 183 | cout << root; 184 | \endcode 185 | Result: 186 | \verbatim 187 | { 188 | "dir": { 189 | "file": { 190 | // The input stream JSON would be nested here. 191 | } 192 | } 193 | } 194 | \endverbatim 195 | \throw std::exception on parse error. 196 | \see Json::operator<<() 197 | */ 198 | std::istream& operator>>( std::istream&, Value& ); 199 | 200 | } // namespace Json 201 | 202 | #endif // CPPTL_JSON_READER_H_INCLUDED 203 | -------------------------------------------------------------------------------- /json/src/json_batchallocator.h: -------------------------------------------------------------------------------- 1 | #ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED 2 | # define JSONCPP_BATCHALLOCATOR_H_INCLUDED 3 | 4 | # include 5 | # include 6 | 7 | # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION 8 | 9 | namespace Json { 10 | 11 | /* Fast memory allocator. 12 | * 13 | * This memory allocator allocates memory for a batch of object (specified by 14 | * the page size, the number of object in each page). 15 | * 16 | * It does not allow the destruction of a single object. All the allocated objects 17 | * can be destroyed at once. The memory can be either released or reused for future 18 | * allocation. 19 | * 20 | * The in-place new operator must be used to construct the object using the pointer 21 | * returned by allocate. 22 | */ 23 | template 25 | class BatchAllocator 26 | { 27 | public: 28 | typedef AllocatedType Type; 29 | 30 | BatchAllocator( unsigned int objectsPerPage = 255 ) 31 | : freeHead_( 0 ) 32 | , objectsPerPage_( objectsPerPage ) 33 | { 34 | // printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); 35 | assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. 36 | assert( objectsPerPage >= 16 ); 37 | batches_ = allocateBatch( 0 ); // allocated a dummy page 38 | currentBatch_ = batches_; 39 | } 40 | 41 | ~BatchAllocator() 42 | { 43 | for ( BatchInfo *batch = batches_; batch; ) 44 | { 45 | BatchInfo *nextBatch = batch->next_; 46 | free( batch ); 47 | batch = nextBatch; 48 | } 49 | } 50 | 51 | /// allocate space for an array of objectPerAllocation object. 52 | /// @warning it is the responsability of the caller to call objects constructors. 53 | AllocatedType *allocate() 54 | { 55 | if ( freeHead_ ) // returns node from free list. 56 | { 57 | AllocatedType *object = freeHead_; 58 | freeHead_ = *(AllocatedType **)object; 59 | return object; 60 | } 61 | if ( currentBatch_->used_ == currentBatch_->end_ ) 62 | { 63 | currentBatch_ = currentBatch_->next_; 64 | while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) 65 | currentBatch_ = currentBatch_->next_; 66 | 67 | if ( !currentBatch_ ) // no free batch found, allocate a new one 68 | { 69 | currentBatch_ = allocateBatch( objectsPerPage_ ); 70 | currentBatch_->next_ = batches_; // insert at the head of the list 71 | batches_ = currentBatch_; 72 | } 73 | } 74 | AllocatedType *allocated = currentBatch_->used_; 75 | currentBatch_->used_ += objectPerAllocation; 76 | return allocated; 77 | } 78 | 79 | /// Release the object. 80 | /// @warning it is the responsability of the caller to actually destruct the object. 81 | void release( AllocatedType *object ) 82 | { 83 | assert( object != 0 ); 84 | *(AllocatedType **)object = freeHead_; 85 | freeHead_ = object; 86 | } 87 | 88 | private: 89 | struct BatchInfo 90 | { 91 | BatchInfo *next_; 92 | AllocatedType *used_; 93 | AllocatedType *end_; 94 | AllocatedType buffer_[objectPerAllocation]; 95 | }; 96 | 97 | // disabled copy constructor and assignement operator. 98 | BatchAllocator( const BatchAllocator & ); 99 | void operator =( const BatchAllocator &); 100 | 101 | static BatchInfo *allocateBatch( unsigned int objectsPerPage ) 102 | { 103 | const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation 104 | + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; 105 | BatchInfo *batch = static_cast( malloc( mallocSize ) ); 106 | batch->next_ = 0; 107 | batch->used_ = batch->buffer_; 108 | batch->end_ = batch->buffer_ + objectsPerPage; 109 | return batch; 110 | } 111 | 112 | BatchInfo *batches_; 113 | BatchInfo *currentBatch_; 114 | /// Head of a single linked list within the allocated space of freeed object 115 | AllocatedType *freeHead_; 116 | unsigned int objectsPerPage_; 117 | }; 118 | 119 | 120 | } // namespace Json 121 | 122 | # endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION 123 | 124 | #endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED 125 | 126 | -------------------------------------------------------------------------------- /json/src/json_internalarray.inl: -------------------------------------------------------------------------------- 1 | // included by json_value.cpp 2 | // everything is within Json namespace 3 | 4 | // ////////////////////////////////////////////////////////////////// 5 | // ////////////////////////////////////////////////////////////////// 6 | // ////////////////////////////////////////////////////////////////// 7 | // class ValueInternalArray 8 | // ////////////////////////////////////////////////////////////////// 9 | // ////////////////////////////////////////////////////////////////// 10 | // ////////////////////////////////////////////////////////////////// 11 | 12 | ValueArrayAllocator::~ValueArrayAllocator() 13 | { 14 | } 15 | 16 | // ////////////////////////////////////////////////////////////////// 17 | // class DefaultValueArrayAllocator 18 | // ////////////////////////////////////////////////////////////////// 19 | #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 20 | class DefaultValueArrayAllocator : public ValueArrayAllocator 21 | { 22 | public: // overridden from ValueArrayAllocator 23 | virtual ~DefaultValueArrayAllocator() 24 | { 25 | } 26 | 27 | virtual ValueInternalArray *newArray() 28 | { 29 | return new ValueInternalArray(); 30 | } 31 | 32 | virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) 33 | { 34 | return new ValueInternalArray( other ); 35 | } 36 | 37 | virtual void destructArray( ValueInternalArray *array ) 38 | { 39 | delete array; 40 | } 41 | 42 | virtual void reallocateArrayPageIndex( Value **&indexes, 43 | ValueInternalArray::PageIndex &indexCount, 44 | ValueInternalArray::PageIndex minNewIndexCount ) 45 | { 46 | ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; 47 | if ( minNewIndexCount > newIndexCount ) 48 | newIndexCount = minNewIndexCount; 49 | void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); 50 | if ( !newIndexes ) 51 | throw std::bad_alloc(); 52 | indexCount = newIndexCount; 53 | indexes = static_cast( newIndexes ); 54 | } 55 | virtual void releaseArrayPageIndex( Value **indexes, 56 | ValueInternalArray::PageIndex indexCount ) 57 | { 58 | if ( indexes ) 59 | free( indexes ); 60 | } 61 | 62 | virtual Value *allocateArrayPage() 63 | { 64 | return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); 65 | } 66 | 67 | virtual void releaseArrayPage( Value *value ) 68 | { 69 | if ( value ) 70 | free( value ); 71 | } 72 | }; 73 | 74 | #else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 75 | /// @todo make this thread-safe (lock when accessign batch allocator) 76 | class DefaultValueArrayAllocator : public ValueArrayAllocator 77 | { 78 | public: // overridden from ValueArrayAllocator 79 | virtual ~DefaultValueArrayAllocator() 80 | { 81 | } 82 | 83 | virtual ValueInternalArray *newArray() 84 | { 85 | ValueInternalArray *array = arraysAllocator_.allocate(); 86 | new (array) ValueInternalArray(); // placement new 87 | return array; 88 | } 89 | 90 | virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) 91 | { 92 | ValueInternalArray *array = arraysAllocator_.allocate(); 93 | new (array) ValueInternalArray( other ); // placement new 94 | return array; 95 | } 96 | 97 | virtual void destructArray( ValueInternalArray *array ) 98 | { 99 | if ( array ) 100 | { 101 | array->~ValueInternalArray(); 102 | arraysAllocator_.release( array ); 103 | } 104 | } 105 | 106 | virtual void reallocateArrayPageIndex( Value **&indexes, 107 | ValueInternalArray::PageIndex &indexCount, 108 | ValueInternalArray::PageIndex minNewIndexCount ) 109 | { 110 | ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; 111 | if ( minNewIndexCount > newIndexCount ) 112 | newIndexCount = minNewIndexCount; 113 | void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); 114 | if ( !newIndexes ) 115 | throw std::bad_alloc(); 116 | indexCount = newIndexCount; 117 | indexes = static_cast( newIndexes ); 118 | } 119 | virtual void releaseArrayPageIndex( Value **indexes, 120 | ValueInternalArray::PageIndex indexCount ) 121 | { 122 | if ( indexes ) 123 | free( indexes ); 124 | } 125 | 126 | virtual Value *allocateArrayPage() 127 | { 128 | return static_cast( pagesAllocator_.allocate() ); 129 | } 130 | 131 | virtual void releaseArrayPage( Value *value ) 132 | { 133 | if ( value ) 134 | pagesAllocator_.release( value ); 135 | } 136 | private: 137 | BatchAllocator arraysAllocator_; 138 | BatchAllocator pagesAllocator_; 139 | }; 140 | #endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 141 | 142 | static ValueArrayAllocator *&arrayAllocator() 143 | { 144 | static DefaultValueArrayAllocator defaultAllocator; 145 | static ValueArrayAllocator *arrayAllocator = &defaultAllocator; 146 | return arrayAllocator; 147 | } 148 | 149 | static struct DummyArrayAllocatorInitializer { 150 | DummyArrayAllocatorInitializer() 151 | { 152 | arrayAllocator(); // ensure arrayAllocator() statics are initialized before main(). 153 | } 154 | } dummyArrayAllocatorInitializer; 155 | 156 | // ////////////////////////////////////////////////////////////////// 157 | // class ValueInternalArray 158 | // ////////////////////////////////////////////////////////////////// 159 | bool 160 | ValueInternalArray::equals( const IteratorState &x, 161 | const IteratorState &other ) 162 | { 163 | return x.array_ == other.array_ 164 | && x.currentItemIndex_ == other.currentItemIndex_ 165 | && x.currentPageIndex_ == other.currentPageIndex_; 166 | } 167 | 168 | 169 | void 170 | ValueInternalArray::increment( IteratorState &it ) 171 | { 172 | JSON_ASSERT_MESSAGE( it.array_ && 173 | (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ 174 | != it.array_->size_, 175 | "ValueInternalArray::increment(): moving iterator beyond end" ); 176 | ++(it.currentItemIndex_); 177 | if ( it.currentItemIndex_ == itemsPerPage ) 178 | { 179 | it.currentItemIndex_ = 0; 180 | ++(it.currentPageIndex_); 181 | } 182 | } 183 | 184 | 185 | void 186 | ValueInternalArray::decrement( IteratorState &it ) 187 | { 188 | JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_ 189 | && it.currentItemIndex_ == 0, 190 | "ValueInternalArray::decrement(): moving iterator beyond end" ); 191 | if ( it.currentItemIndex_ == 0 ) 192 | { 193 | it.currentItemIndex_ = itemsPerPage-1; 194 | --(it.currentPageIndex_); 195 | } 196 | else 197 | { 198 | --(it.currentItemIndex_); 199 | } 200 | } 201 | 202 | 203 | Value & 204 | ValueInternalArray::unsafeDereference( const IteratorState &it ) 205 | { 206 | return (*(it.currentPageIndex_))[it.currentItemIndex_]; 207 | } 208 | 209 | 210 | Value & 211 | ValueInternalArray::dereference( const IteratorState &it ) 212 | { 213 | JSON_ASSERT_MESSAGE( it.array_ && 214 | (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ 215 | < it.array_->size_, 216 | "ValueInternalArray::dereference(): dereferencing invalid iterator" ); 217 | return unsafeDereference( it ); 218 | } 219 | 220 | void 221 | ValueInternalArray::makeBeginIterator( IteratorState &it ) const 222 | { 223 | it.array_ = const_cast( this ); 224 | it.currentItemIndex_ = 0; 225 | it.currentPageIndex_ = pages_; 226 | } 227 | 228 | 229 | void 230 | ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const 231 | { 232 | it.array_ = const_cast( this ); 233 | it.currentItemIndex_ = index % itemsPerPage; 234 | it.currentPageIndex_ = pages_ + index / itemsPerPage; 235 | } 236 | 237 | 238 | void 239 | ValueInternalArray::makeEndIterator( IteratorState &it ) const 240 | { 241 | makeIterator( it, size_ ); 242 | } 243 | 244 | 245 | ValueInternalArray::ValueInternalArray() 246 | : pages_( 0 ) 247 | , size_( 0 ) 248 | , pageCount_( 0 ) 249 | { 250 | } 251 | 252 | 253 | ValueInternalArray::ValueInternalArray( const ValueInternalArray &other ) 254 | : pages_( 0 ) 255 | , pageCount_( 0 ) 256 | , size_( other.size_ ) 257 | { 258 | PageIndex minNewPages = other.size_ / itemsPerPage; 259 | arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); 260 | JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, 261 | "ValueInternalArray::reserve(): bad reallocation" ); 262 | IteratorState itOther; 263 | other.makeBeginIterator( itOther ); 264 | Value *value; 265 | for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) ) 266 | { 267 | if ( index % itemsPerPage == 0 ) 268 | { 269 | PageIndex pageIndex = index / itemsPerPage; 270 | value = arrayAllocator()->allocateArrayPage(); 271 | pages_[pageIndex] = value; 272 | } 273 | new (value) Value( dereference( itOther ) ); 274 | } 275 | } 276 | 277 | 278 | ValueInternalArray & 279 | ValueInternalArray::operator =( const ValueInternalArray &other ) 280 | { 281 | ValueInternalArray temp( other ); 282 | swap( temp ); 283 | return *this; 284 | } 285 | 286 | 287 | ValueInternalArray::~ValueInternalArray() 288 | { 289 | // destroy all constructed items 290 | IteratorState it; 291 | IteratorState itEnd; 292 | makeBeginIterator( it); 293 | makeEndIterator( itEnd ); 294 | for ( ; !equals(it,itEnd); increment(it) ) 295 | { 296 | Value *value = &dereference(it); 297 | value->~Value(); 298 | } 299 | // release all pages 300 | PageIndex lastPageIndex = size_ / itemsPerPage; 301 | for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex ) 302 | arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); 303 | // release pages index 304 | arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ ); 305 | } 306 | 307 | 308 | void 309 | ValueInternalArray::swap( ValueInternalArray &other ) 310 | { 311 | Value **tempPages = pages_; 312 | pages_ = other.pages_; 313 | other.pages_ = tempPages; 314 | ArrayIndex tempSize = size_; 315 | size_ = other.size_; 316 | other.size_ = tempSize; 317 | PageIndex tempPageCount = pageCount_; 318 | pageCount_ = other.pageCount_; 319 | other.pageCount_ = tempPageCount; 320 | } 321 | 322 | void 323 | ValueInternalArray::clear() 324 | { 325 | ValueInternalArray dummy; 326 | swap( dummy ); 327 | } 328 | 329 | 330 | void 331 | ValueInternalArray::resize( ArrayIndex newSize ) 332 | { 333 | if ( newSize == 0 ) 334 | clear(); 335 | else if ( newSize < size_ ) 336 | { 337 | IteratorState it; 338 | IteratorState itEnd; 339 | makeIterator( it, newSize ); 340 | makeIterator( itEnd, size_ ); 341 | for ( ; !equals(it,itEnd); increment(it) ) 342 | { 343 | Value *value = &dereference(it); 344 | value->~Value(); 345 | } 346 | PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage; 347 | PageIndex lastPageIndex = size_ / itemsPerPage; 348 | for ( ; pageIndex < lastPageIndex; ++pageIndex ) 349 | arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); 350 | size_ = newSize; 351 | } 352 | else if ( newSize > size_ ) 353 | resolveReference( newSize ); 354 | } 355 | 356 | 357 | void 358 | ValueInternalArray::makeIndexValid( ArrayIndex index ) 359 | { 360 | // Need to enlarge page index ? 361 | if ( index >= pageCount_ * itemsPerPage ) 362 | { 363 | PageIndex minNewPages = (index + 1) / itemsPerPage; 364 | arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); 365 | JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" ); 366 | } 367 | 368 | // Need to allocate new pages ? 369 | ArrayIndex nextPageIndex = 370 | (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage 371 | : size_; 372 | if ( nextPageIndex <= index ) 373 | { 374 | PageIndex pageIndex = nextPageIndex / itemsPerPage; 375 | PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1; 376 | for ( ; pageToAllocate-- > 0; ++pageIndex ) 377 | pages_[pageIndex] = arrayAllocator()->allocateArrayPage(); 378 | } 379 | 380 | // Initialize all new entries 381 | IteratorState it; 382 | IteratorState itEnd; 383 | makeIterator( it, size_ ); 384 | size_ = index + 1; 385 | makeIterator( itEnd, size_ ); 386 | for ( ; !equals(it,itEnd); increment(it) ) 387 | { 388 | Value *value = &dereference(it); 389 | new (value) Value(); // Construct a default value using placement new 390 | } 391 | } 392 | 393 | Value & 394 | ValueInternalArray::resolveReference( ArrayIndex index ) 395 | { 396 | if ( index >= size_ ) 397 | makeIndexValid( index ); 398 | return pages_[index/itemsPerPage][index%itemsPerPage]; 399 | } 400 | 401 | Value * 402 | ValueInternalArray::find( ArrayIndex index ) const 403 | { 404 | if ( index >= size_ ) 405 | return 0; 406 | return &(pages_[index/itemsPerPage][index%itemsPerPage]); 407 | } 408 | 409 | ValueInternalArray::ArrayIndex 410 | ValueInternalArray::size() const 411 | { 412 | return size_; 413 | } 414 | 415 | int 416 | ValueInternalArray::distance( const IteratorState &x, const IteratorState &y ) 417 | { 418 | return indexOf(y) - indexOf(x); 419 | } 420 | 421 | 422 | ValueInternalArray::ArrayIndex 423 | ValueInternalArray::indexOf( const IteratorState &iterator ) 424 | { 425 | if ( !iterator.array_ ) 426 | return ArrayIndex(-1); 427 | return ArrayIndex( 428 | (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage 429 | + iterator.currentItemIndex_ ); 430 | } 431 | 432 | 433 | int 434 | ValueInternalArray::compare( const ValueInternalArray &other ) const 435 | { 436 | int sizeDiff( size_ - other.size_ ); 437 | if ( sizeDiff != 0 ) 438 | return sizeDiff; 439 | 440 | for ( ArrayIndex index =0; index < size_; ++index ) 441 | { 442 | int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare( 443 | other.pages_[index/itemsPerPage][index%itemsPerPage] ); 444 | if ( diff != 0 ) 445 | return diff; 446 | } 447 | return 0; 448 | } 449 | -------------------------------------------------------------------------------- /json/src/json_internalmap.inl: -------------------------------------------------------------------------------- 1 | // included by json_value.cpp 2 | // everything is within Json namespace 3 | 4 | // ////////////////////////////////////////////////////////////////// 5 | // ////////////////////////////////////////////////////////////////// 6 | // ////////////////////////////////////////////////////////////////// 7 | // class ValueInternalMap 8 | // ////////////////////////////////////////////////////////////////// 9 | // ////////////////////////////////////////////////////////////////// 10 | // ////////////////////////////////////////////////////////////////// 11 | 12 | /** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) ); 13 | * This optimization is used by the fast allocator. 14 | */ 15 | ValueInternalLink::ValueInternalLink() 16 | : previous_( 0 ) 17 | , next_( 0 ) 18 | { 19 | } 20 | 21 | ValueInternalLink::~ValueInternalLink() 22 | { 23 | for ( int index =0; index < itemPerLink; ++index ) 24 | { 25 | if ( !items_[index].isItemAvailable() ) 26 | { 27 | if ( !items_[index].isMemberNameStatic() ) 28 | free( keys_[index] ); 29 | } 30 | else 31 | break; 32 | } 33 | } 34 | 35 | 36 | 37 | ValueMapAllocator::~ValueMapAllocator() 38 | { 39 | } 40 | 41 | #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 42 | class DefaultValueMapAllocator : public ValueMapAllocator 43 | { 44 | public: // overridden from ValueMapAllocator 45 | virtual ValueInternalMap *newMap() 46 | { 47 | return new ValueInternalMap(); 48 | } 49 | 50 | virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) 51 | { 52 | return new ValueInternalMap( other ); 53 | } 54 | 55 | virtual void destructMap( ValueInternalMap *map ) 56 | { 57 | delete map; 58 | } 59 | 60 | virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) 61 | { 62 | return new ValueInternalLink[size]; 63 | } 64 | 65 | virtual void releaseMapBuckets( ValueInternalLink *links ) 66 | { 67 | delete [] links; 68 | } 69 | 70 | virtual ValueInternalLink *allocateMapLink() 71 | { 72 | return new ValueInternalLink(); 73 | } 74 | 75 | virtual void releaseMapLink( ValueInternalLink *link ) 76 | { 77 | delete link; 78 | } 79 | }; 80 | #else 81 | /// @todo make this thread-safe (lock when accessign batch allocator) 82 | class DefaultValueMapAllocator : public ValueMapAllocator 83 | { 84 | public: // overridden from ValueMapAllocator 85 | virtual ValueInternalMap *newMap() 86 | { 87 | ValueInternalMap *map = mapsAllocator_.allocate(); 88 | new (map) ValueInternalMap(); // placement new 89 | return map; 90 | } 91 | 92 | virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) 93 | { 94 | ValueInternalMap *map = mapsAllocator_.allocate(); 95 | new (map) ValueInternalMap( other ); // placement new 96 | return map; 97 | } 98 | 99 | virtual void destructMap( ValueInternalMap *map ) 100 | { 101 | if ( map ) 102 | { 103 | map->~ValueInternalMap(); 104 | mapsAllocator_.release( map ); 105 | } 106 | } 107 | 108 | virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) 109 | { 110 | return new ValueInternalLink[size]; 111 | } 112 | 113 | virtual void releaseMapBuckets( ValueInternalLink *links ) 114 | { 115 | delete [] links; 116 | } 117 | 118 | virtual ValueInternalLink *allocateMapLink() 119 | { 120 | ValueInternalLink *link = linksAllocator_.allocate(); 121 | memset( link, 0, sizeof(ValueInternalLink) ); 122 | return link; 123 | } 124 | 125 | virtual void releaseMapLink( ValueInternalLink *link ) 126 | { 127 | link->~ValueInternalLink(); 128 | linksAllocator_.release( link ); 129 | } 130 | private: 131 | BatchAllocator mapsAllocator_; 132 | BatchAllocator linksAllocator_; 133 | }; 134 | #endif 135 | 136 | static ValueMapAllocator *&mapAllocator() 137 | { 138 | static DefaultValueMapAllocator defaultAllocator; 139 | static ValueMapAllocator *mapAllocator = &defaultAllocator; 140 | return mapAllocator; 141 | } 142 | 143 | static struct DummyMapAllocatorInitializer { 144 | DummyMapAllocatorInitializer() 145 | { 146 | mapAllocator(); // ensure mapAllocator() statics are initialized before main(). 147 | } 148 | } dummyMapAllocatorInitializer; 149 | 150 | 151 | 152 | // h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32. 153 | 154 | /* 155 | use linked list hash map. 156 | buckets array is a container. 157 | linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124) 158 | value have extra state: valid, available, deleted 159 | */ 160 | 161 | 162 | ValueInternalMap::ValueInternalMap() 163 | : buckets_( 0 ) 164 | , tailLink_( 0 ) 165 | , bucketsSize_( 0 ) 166 | , itemCount_( 0 ) 167 | { 168 | } 169 | 170 | 171 | ValueInternalMap::ValueInternalMap( const ValueInternalMap &other ) 172 | : buckets_( 0 ) 173 | , tailLink_( 0 ) 174 | , bucketsSize_( 0 ) 175 | , itemCount_( 0 ) 176 | { 177 | reserve( other.itemCount_ ); 178 | IteratorState it; 179 | IteratorState itEnd; 180 | other.makeBeginIterator( it ); 181 | other.makeEndIterator( itEnd ); 182 | for ( ; !equals(it,itEnd); increment(it) ) 183 | { 184 | bool isStatic; 185 | const char *memberName = key( it, isStatic ); 186 | const Value &aValue = value( it ); 187 | resolveReference(memberName, isStatic) = aValue; 188 | } 189 | } 190 | 191 | 192 | ValueInternalMap & 193 | ValueInternalMap::operator =( const ValueInternalMap &other ) 194 | { 195 | ValueInternalMap dummy( other ); 196 | swap( dummy ); 197 | return *this; 198 | } 199 | 200 | 201 | ValueInternalMap::~ValueInternalMap() 202 | { 203 | if ( buckets_ ) 204 | { 205 | for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex ) 206 | { 207 | ValueInternalLink *link = buckets_[bucketIndex].next_; 208 | while ( link ) 209 | { 210 | ValueInternalLink *linkToRelease = link; 211 | link = link->next_; 212 | mapAllocator()->releaseMapLink( linkToRelease ); 213 | } 214 | } 215 | mapAllocator()->releaseMapBuckets( buckets_ ); 216 | } 217 | } 218 | 219 | 220 | void 221 | ValueInternalMap::swap( ValueInternalMap &other ) 222 | { 223 | ValueInternalLink *tempBuckets = buckets_; 224 | buckets_ = other.buckets_; 225 | other.buckets_ = tempBuckets; 226 | ValueInternalLink *tempTailLink = tailLink_; 227 | tailLink_ = other.tailLink_; 228 | other.tailLink_ = tempTailLink; 229 | BucketIndex tempBucketsSize = bucketsSize_; 230 | bucketsSize_ = other.bucketsSize_; 231 | other.bucketsSize_ = tempBucketsSize; 232 | BucketIndex tempItemCount = itemCount_; 233 | itemCount_ = other.itemCount_; 234 | other.itemCount_ = tempItemCount; 235 | } 236 | 237 | 238 | void 239 | ValueInternalMap::clear() 240 | { 241 | ValueInternalMap dummy; 242 | swap( dummy ); 243 | } 244 | 245 | 246 | ValueInternalMap::BucketIndex 247 | ValueInternalMap::size() const 248 | { 249 | return itemCount_; 250 | } 251 | 252 | bool 253 | ValueInternalMap::reserveDelta( BucketIndex growth ) 254 | { 255 | return reserve( itemCount_ + growth ); 256 | } 257 | 258 | bool 259 | ValueInternalMap::reserve( BucketIndex newItemCount ) 260 | { 261 | if ( !buckets_ && newItemCount > 0 ) 262 | { 263 | buckets_ = mapAllocator()->allocateMapBuckets( 1 ); 264 | bucketsSize_ = 1; 265 | tailLink_ = &buckets_[0]; 266 | } 267 | // BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink; 268 | return true; 269 | } 270 | 271 | 272 | const Value * 273 | ValueInternalMap::find( const char *key ) const 274 | { 275 | if ( !bucketsSize_ ) 276 | return 0; 277 | HashKey hashedKey = hash( key ); 278 | BucketIndex bucketIndex = hashedKey % bucketsSize_; 279 | for ( const ValueInternalLink *current = &buckets_[bucketIndex]; 280 | current != 0; 281 | current = current->next_ ) 282 | { 283 | for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index ) 284 | { 285 | if ( current->items_[index].isItemAvailable() ) 286 | return 0; 287 | if ( strcmp( key, current->keys_[index] ) == 0 ) 288 | return ¤t->items_[index]; 289 | } 290 | } 291 | return 0; 292 | } 293 | 294 | 295 | Value * 296 | ValueInternalMap::find( const char *key ) 297 | { 298 | const ValueInternalMap *constThis = this; 299 | return const_cast( constThis->find( key ) ); 300 | } 301 | 302 | 303 | Value & 304 | ValueInternalMap::resolveReference( const char *key, 305 | bool isStatic ) 306 | { 307 | HashKey hashedKey = hash( key ); 308 | if ( bucketsSize_ ) 309 | { 310 | BucketIndex bucketIndex = hashedKey % bucketsSize_; 311 | ValueInternalLink **previous = 0; 312 | BucketIndex index; 313 | for ( ValueInternalLink *current = &buckets_[bucketIndex]; 314 | current != 0; 315 | previous = ¤t->next_, current = current->next_ ) 316 | { 317 | for ( index=0; index < ValueInternalLink::itemPerLink; ++index ) 318 | { 319 | if ( current->items_[index].isItemAvailable() ) 320 | return setNewItem( key, isStatic, current, index ); 321 | if ( strcmp( key, current->keys_[index] ) == 0 ) 322 | return current->items_[index]; 323 | } 324 | } 325 | } 326 | 327 | reserveDelta( 1 ); 328 | return unsafeAdd( key, isStatic, hashedKey ); 329 | } 330 | 331 | 332 | void 333 | ValueInternalMap::remove( const char *key ) 334 | { 335 | HashKey hashedKey = hash( key ); 336 | if ( !bucketsSize_ ) 337 | return; 338 | BucketIndex bucketIndex = hashedKey % bucketsSize_; 339 | for ( ValueInternalLink *link = &buckets_[bucketIndex]; 340 | link != 0; 341 | link = link->next_ ) 342 | { 343 | BucketIndex index; 344 | for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) 345 | { 346 | if ( link->items_[index].isItemAvailable() ) 347 | return; 348 | if ( strcmp( key, link->keys_[index] ) == 0 ) 349 | { 350 | doActualRemove( link, index, bucketIndex ); 351 | return; 352 | } 353 | } 354 | } 355 | } 356 | 357 | void 358 | ValueInternalMap::doActualRemove( ValueInternalLink *link, 359 | BucketIndex index, 360 | BucketIndex bucketIndex ) 361 | { 362 | // find last item of the bucket and swap it with the 'removed' one. 363 | // set removed items flags to 'available'. 364 | // if last page only contains 'available' items, then desallocate it (it's empty) 365 | ValueInternalLink *&lastLink = getLastLinkInBucket( index ); 366 | BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1 367 | for ( ; 368 | lastItemIndex < ValueInternalLink::itemPerLink; 369 | ++lastItemIndex ) // may be optimized with dicotomic search 370 | { 371 | if ( lastLink->items_[lastItemIndex].isItemAvailable() ) 372 | break; 373 | } 374 | 375 | BucketIndex lastUsedIndex = lastItemIndex - 1; 376 | Value *valueToDelete = &link->items_[index]; 377 | Value *valueToPreserve = &lastLink->items_[lastUsedIndex]; 378 | if ( valueToDelete != valueToPreserve ) 379 | valueToDelete->swap( *valueToPreserve ); 380 | if ( lastUsedIndex == 0 ) // page is now empty 381 | { // remove it from bucket linked list and delete it. 382 | ValueInternalLink *linkPreviousToLast = lastLink->previous_; 383 | if ( linkPreviousToLast != 0 ) // can not deleted bucket link. 384 | { 385 | mapAllocator()->releaseMapLink( lastLink ); 386 | linkPreviousToLast->next_ = 0; 387 | lastLink = linkPreviousToLast; 388 | } 389 | } 390 | else 391 | { 392 | Value dummy; 393 | valueToPreserve->swap( dummy ); // restore deleted to default Value. 394 | valueToPreserve->setItemUsed( false ); 395 | } 396 | --itemCount_; 397 | } 398 | 399 | 400 | ValueInternalLink *& 401 | ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex ) 402 | { 403 | if ( bucketIndex == bucketsSize_ - 1 ) 404 | return tailLink_; 405 | ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_; 406 | if ( !previous ) 407 | previous = &buckets_[bucketIndex]; 408 | return previous; 409 | } 410 | 411 | 412 | Value & 413 | ValueInternalMap::setNewItem( const char *key, 414 | bool isStatic, 415 | ValueInternalLink *link, 416 | BucketIndex index ) 417 | { 418 | char *duplicatedKey = valueAllocator()->makeMemberName( key ); 419 | ++itemCount_; 420 | link->keys_[index] = duplicatedKey; 421 | link->items_[index].setItemUsed(); 422 | link->items_[index].setMemberNameIsStatic( isStatic ); 423 | return link->items_[index]; // items already default constructed. 424 | } 425 | 426 | 427 | Value & 428 | ValueInternalMap::unsafeAdd( const char *key, 429 | bool isStatic, 430 | HashKey hashedKey ) 431 | { 432 | JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." ); 433 | BucketIndex bucketIndex = hashedKey % bucketsSize_; 434 | ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex ); 435 | ValueInternalLink *link = previousLink; 436 | BucketIndex index; 437 | for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) 438 | { 439 | if ( link->items_[index].isItemAvailable() ) 440 | break; 441 | } 442 | if ( index == ValueInternalLink::itemPerLink ) // need to add a new page 443 | { 444 | ValueInternalLink *newLink = mapAllocator()->allocateMapLink(); 445 | index = 0; 446 | link->next_ = newLink; 447 | previousLink = newLink; 448 | link = newLink; 449 | } 450 | return setNewItem( key, isStatic, link, index ); 451 | } 452 | 453 | 454 | ValueInternalMap::HashKey 455 | ValueInternalMap::hash( const char *key ) const 456 | { 457 | HashKey hash = 0; 458 | while ( *key ) 459 | hash += *key++ * 37; 460 | return hash; 461 | } 462 | 463 | 464 | int 465 | ValueInternalMap::compare( const ValueInternalMap &other ) const 466 | { 467 | int sizeDiff( itemCount_ - other.itemCount_ ); 468 | if ( sizeDiff != 0 ) 469 | return sizeDiff; 470 | // Strict order guaranty is required. Compare all keys FIRST, then compare values. 471 | IteratorState it; 472 | IteratorState itEnd; 473 | makeBeginIterator( it ); 474 | makeEndIterator( itEnd ); 475 | for ( ; !equals(it,itEnd); increment(it) ) 476 | { 477 | if ( !other.find( key( it ) ) ) 478 | return 1; 479 | } 480 | 481 | // All keys are equals, let's compare values 482 | makeBeginIterator( it ); 483 | for ( ; !equals(it,itEnd); increment(it) ) 484 | { 485 | const Value *otherValue = other.find( key( it ) ); 486 | int valueDiff = value(it).compare( *otherValue ); 487 | if ( valueDiff != 0 ) 488 | return valueDiff; 489 | } 490 | return 0; 491 | } 492 | 493 | 494 | void 495 | ValueInternalMap::makeBeginIterator( IteratorState &it ) const 496 | { 497 | it.map_ = const_cast( this ); 498 | it.bucketIndex_ = 0; 499 | it.itemIndex_ = 0; 500 | it.link_ = buckets_; 501 | } 502 | 503 | 504 | void 505 | ValueInternalMap::makeEndIterator( IteratorState &it ) const 506 | { 507 | it.map_ = const_cast( this ); 508 | it.bucketIndex_ = bucketsSize_; 509 | it.itemIndex_ = 0; 510 | it.link_ = 0; 511 | } 512 | 513 | 514 | bool 515 | ValueInternalMap::equals( const IteratorState &x, const IteratorState &other ) 516 | { 517 | return x.map_ == other.map_ 518 | && x.bucketIndex_ == other.bucketIndex_ 519 | && x.link_ == other.link_ 520 | && x.itemIndex_ == other.itemIndex_; 521 | } 522 | 523 | 524 | void 525 | ValueInternalMap::incrementBucket( IteratorState &iterator ) 526 | { 527 | ++iterator.bucketIndex_; 528 | JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_, 529 | "ValueInternalMap::increment(): attempting to iterate beyond end." ); 530 | if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ ) 531 | iterator.link_ = 0; 532 | else 533 | iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]); 534 | iterator.itemIndex_ = 0; 535 | } 536 | 537 | 538 | void 539 | ValueInternalMap::increment( IteratorState &iterator ) 540 | { 541 | JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." ); 542 | ++iterator.itemIndex_; 543 | if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink ) 544 | { 545 | JSON_ASSERT_MESSAGE( iterator.link_ != 0, 546 | "ValueInternalMap::increment(): attempting to iterate beyond end." ); 547 | iterator.link_ = iterator.link_->next_; 548 | if ( iterator.link_ == 0 ) 549 | incrementBucket( iterator ); 550 | } 551 | else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() ) 552 | { 553 | incrementBucket( iterator ); 554 | } 555 | } 556 | 557 | 558 | void 559 | ValueInternalMap::decrement( IteratorState &iterator ) 560 | { 561 | if ( iterator.itemIndex_ == 0 ) 562 | { 563 | JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." ); 564 | if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] ) 565 | { 566 | JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." ); 567 | --(iterator.bucketIndex_); 568 | } 569 | iterator.link_ = iterator.link_->previous_; 570 | iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1; 571 | } 572 | } 573 | 574 | 575 | const char * 576 | ValueInternalMap::key( const IteratorState &iterator ) 577 | { 578 | JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); 579 | return iterator.link_->keys_[iterator.itemIndex_]; 580 | } 581 | 582 | const char * 583 | ValueInternalMap::key( const IteratorState &iterator, bool &isStatic ) 584 | { 585 | JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); 586 | isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic(); 587 | return iterator.link_->keys_[iterator.itemIndex_]; 588 | } 589 | 590 | 591 | Value & 592 | ValueInternalMap::value( const IteratorState &iterator ) 593 | { 594 | JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); 595 | return iterator.link_->items_[iterator.itemIndex_]; 596 | } 597 | 598 | 599 | int 600 | ValueInternalMap::distance( const IteratorState &x, const IteratorState &y ) 601 | { 602 | int offset = 0; 603 | IteratorState it = x; 604 | while ( !equals( it, y ) ) 605 | increment( it ); 606 | return offset; 607 | } 608 | -------------------------------------------------------------------------------- /json/src/json_reader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #if _MSC_VER >= 1400 // VC++ 8.0 12 | #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. 13 | #endif 14 | 15 | namespace Json { 16 | 17 | // Implementation of class Features 18 | // //////////////////////////////// 19 | 20 | Features::Features() 21 | : allowComments_( true ) 22 | , strictRoot_( false ) 23 | { 24 | } 25 | 26 | 27 | Features 28 | Features::all() 29 | { 30 | return Features(); 31 | } 32 | 33 | 34 | Features 35 | Features::strictMode() 36 | { 37 | Features features; 38 | features.allowComments_ = false; 39 | features.strictRoot_ = true; 40 | return features; 41 | } 42 | 43 | // Implementation of class Reader 44 | // //////////////////////////////// 45 | 46 | 47 | static inline bool 48 | in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) 49 | { 50 | return c == c1 || c == c2 || c == c3 || c == c4; 51 | } 52 | 53 | static inline bool 54 | in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) 55 | { 56 | return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; 57 | } 58 | 59 | 60 | static bool 61 | containsNewLine( Reader::Location begin, 62 | Reader::Location end ) 63 | { 64 | for ( ;begin < end; ++begin ) 65 | if ( *begin == '\n' || *begin == '\r' ) 66 | return true; 67 | return false; 68 | } 69 | 70 | static std::string codePointToUTF8(unsigned int cp) 71 | { 72 | std::string result; 73 | 74 | // based on description from http://en.wikipedia.org/wiki/UTF-8 75 | 76 | if (cp <= 0x7f) 77 | { 78 | result.resize(1); 79 | result[0] = static_cast(cp); 80 | } 81 | else if (cp <= 0x7FF) 82 | { 83 | result.resize(2); 84 | result[1] = static_cast(0x80 | (0x3f & cp)); 85 | result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); 86 | } 87 | else if (cp <= 0xFFFF) 88 | { 89 | result.resize(3); 90 | result[2] = static_cast(0x80 | (0x3f & cp)); 91 | result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); 92 | result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); 93 | } 94 | else if (cp <= 0x10FFFF) 95 | { 96 | result.resize(4); 97 | result[3] = static_cast(0x80 | (0x3f & cp)); 98 | result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); 99 | result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); 100 | result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); 101 | } 102 | 103 | return result; 104 | } 105 | 106 | 107 | // Class Reader 108 | // ////////////////////////////////////////////////////////////////// 109 | 110 | Reader::Reader() 111 | : features_( Features::all() ) 112 | { 113 | } 114 | 115 | 116 | Reader::Reader( const Features &features ) 117 | : features_( features ) 118 | { 119 | 120 | } 121 | 122 | 123 | bool 124 | Reader::parse( const std::string &document, 125 | Value &root, 126 | bool collectComments ) 127 | { 128 | document_ = document; 129 | const char *begin = document_.c_str(); 130 | const char *end = begin + document_.length(); 131 | return parse( begin, end, root, collectComments ); 132 | } 133 | 134 | bool 135 | Reader::parse( const std::wstring &document, 136 | Value &root, 137 | bool collectComments /*= true*/ ) 138 | { 139 | USES_CONVERSION; 140 | return parse(W2A(document.c_str()) , root, collectComments); 141 | } 142 | 143 | bool 144 | Reader::parse( std::istream& sin, 145 | Value &root, 146 | bool collectComments ) 147 | { 148 | //std::istream_iterator begin(sin); 149 | //std::istream_iterator end; 150 | // Those would allow streamed input from a file, if parse() were a 151 | // template function. 152 | 153 | // Since std::string is reference-counted, this at least does not 154 | // create an extra copy. 155 | std::string doc; 156 | std::getline(sin, doc, (char)EOF); 157 | return parse( doc, root, collectComments ); 158 | } 159 | 160 | bool 161 | Reader::parse( const char *beginDoc, const char *endDoc, 162 | Value &root, 163 | bool collectComments ) 164 | { 165 | if ( !features_.allowComments_ ) 166 | { 167 | collectComments = false; 168 | } 169 | 170 | begin_ = beginDoc; 171 | end_ = endDoc; 172 | collectComments_ = collectComments; 173 | current_ = begin_; 174 | lastValueEnd_ = 0; 175 | lastValue_ = 0; 176 | commentsBefore_ = ""; 177 | errors_.clear(); 178 | while ( !nodes_.empty() ) 179 | nodes_.pop(); 180 | nodes_.push( &root ); 181 | 182 | bool successful = readValue(); 183 | Token token; 184 | skipCommentTokens( token ); 185 | if ( collectComments_ && !commentsBefore_.empty() ) 186 | root.setComment( commentsBefore_, commentAfter ); 187 | if ( features_.strictRoot_ ) 188 | { 189 | if ( !root.isArray() && !root.isObject() ) 190 | { 191 | // Set error location to start of doc, ideally should be first token found in doc 192 | token.type_ = tokenError; 193 | token.start_ = beginDoc; 194 | token.end_ = endDoc; 195 | addError( "A valid JSON document must be either an array or an object value.", 196 | token ); 197 | return false; 198 | } 199 | } 200 | return successful; 201 | } 202 | 203 | 204 | bool 205 | Reader::readValue() 206 | { 207 | Token token; 208 | skipCommentTokens( token ); 209 | bool successful = true; 210 | 211 | if ( collectComments_ && !commentsBefore_.empty() ) 212 | { 213 | currentValue().setComment( commentsBefore_, commentBefore ); 214 | commentsBefore_ = ""; 215 | } 216 | 217 | 218 | switch ( token.type_ ) 219 | { 220 | case tokenObjectBegin: 221 | successful = readObject( token ); 222 | break; 223 | case tokenArrayBegin: 224 | successful = readArray( token ); 225 | break; 226 | case tokenNumber: 227 | successful = decodeNumber( token ); 228 | break; 229 | case tokenString: 230 | successful = decodeString( token ); 231 | break; 232 | case tokenTrue: 233 | currentValue() = true; 234 | break; 235 | case tokenFalse: 236 | currentValue() = false; 237 | break; 238 | case tokenNull: 239 | currentValue() = Value(); 240 | break; 241 | default: 242 | return addError( "Syntax error: value, object or array expected.", token ); 243 | } 244 | 245 | if ( collectComments_ ) 246 | { 247 | lastValueEnd_ = current_; 248 | lastValue_ = ¤tValue(); 249 | } 250 | 251 | return successful; 252 | } 253 | 254 | 255 | void 256 | Reader::skipCommentTokens( Token &token ) 257 | { 258 | if ( features_.allowComments_ ) 259 | { 260 | do 261 | { 262 | readToken( token ); 263 | } 264 | while ( token.type_ == tokenComment ); 265 | } 266 | else 267 | { 268 | readToken( token ); 269 | } 270 | } 271 | 272 | 273 | bool 274 | Reader::expectToken( TokenType type, Token &token, const char *message ) 275 | { 276 | readToken( token ); 277 | if ( token.type_ != type ) 278 | return addError( message, token ); 279 | return true; 280 | } 281 | 282 | 283 | bool 284 | Reader::readToken( Token &token ) 285 | { 286 | skipSpaces(); 287 | token.start_ = current_; 288 | Char c = getNextChar(); 289 | bool ok = true; 290 | switch ( c ) 291 | { 292 | case '{': 293 | token.type_ = tokenObjectBegin; 294 | break; 295 | case '}': 296 | token.type_ = tokenObjectEnd; 297 | break; 298 | case '[': 299 | token.type_ = tokenArrayBegin; 300 | break; 301 | case ']': 302 | token.type_ = tokenArrayEnd; 303 | break; 304 | case '"': 305 | token.type_ = tokenString; 306 | ok = readString(); 307 | break; 308 | case '/': 309 | token.type_ = tokenComment; 310 | ok = readComment(); 311 | break; 312 | case '0': 313 | case '1': 314 | case '2': 315 | case '3': 316 | case '4': 317 | case '5': 318 | case '6': 319 | case '7': 320 | case '8': 321 | case '9': 322 | case '-': 323 | token.type_ = tokenNumber; 324 | readNumber(); 325 | break; 326 | case 't': 327 | token.type_ = tokenTrue; 328 | ok = match( "rue", 3 ); 329 | break; 330 | case 'f': 331 | token.type_ = tokenFalse; 332 | ok = match( "alse", 4 ); 333 | break; 334 | case 'n': 335 | token.type_ = tokenNull; 336 | ok = match( "ull", 3 ); 337 | break; 338 | case ',': 339 | token.type_ = tokenArraySeparator; 340 | break; 341 | case ':': 342 | token.type_ = tokenMemberSeparator; 343 | break; 344 | case 0: 345 | token.type_ = tokenEndOfStream; 346 | break; 347 | default: 348 | ok = false; 349 | break; 350 | } 351 | if ( !ok ) 352 | token.type_ = tokenError; 353 | token.end_ = current_; 354 | return true; 355 | } 356 | 357 | 358 | void 359 | Reader::skipSpaces() 360 | { 361 | while ( current_ != end_ ) 362 | { 363 | Char c = *current_; 364 | if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) 365 | ++current_; 366 | else 367 | break; 368 | } 369 | } 370 | 371 | 372 | bool 373 | Reader::match( Location pattern, 374 | int patternLength ) 375 | { 376 | if ( end_ - current_ < patternLength ) 377 | return false; 378 | int index = patternLength; 379 | while ( index-- ) 380 | if ( current_[index] != pattern[index] ) 381 | return false; 382 | current_ += patternLength; 383 | return true; 384 | } 385 | 386 | 387 | bool 388 | Reader::readComment() 389 | { 390 | Location commentBegin = current_ - 1; 391 | Char c = getNextChar(); 392 | bool successful = false; 393 | if ( c == '*' ) 394 | successful = readCStyleComment(); 395 | else if ( c == '/' ) 396 | successful = readCppStyleComment(); 397 | if ( !successful ) 398 | return false; 399 | 400 | if ( collectComments_ ) 401 | { 402 | CommentPlacement placement = commentBefore; 403 | if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) 404 | { 405 | if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) 406 | placement = commentAfterOnSameLine; 407 | } 408 | 409 | addComment( commentBegin, current_, placement ); 410 | } 411 | return true; 412 | } 413 | 414 | 415 | void 416 | Reader::addComment( Location begin, 417 | Location end, 418 | CommentPlacement placement ) 419 | { 420 | assert( collectComments_ ); 421 | if ( placement == commentAfterOnSameLine ) 422 | { 423 | assert( lastValue_ != 0 ); 424 | lastValue_->setComment( std::string( begin, end ), placement ); 425 | } 426 | else 427 | { 428 | if ( !commentsBefore_.empty() ) 429 | commentsBefore_ += "\n"; 430 | commentsBefore_ += std::string( begin, end ); 431 | } 432 | } 433 | 434 | 435 | bool 436 | Reader::readCStyleComment() 437 | { 438 | while ( current_ != end_ ) 439 | { 440 | Char c = getNextChar(); 441 | if ( c == '*' && *current_ == '/' ) 442 | break; 443 | } 444 | return getNextChar() == '/'; 445 | } 446 | 447 | 448 | bool 449 | Reader::readCppStyleComment() 450 | { 451 | while ( current_ != end_ ) 452 | { 453 | Char c = getNextChar(); 454 | if ( c == '\r' || c == '\n' ) 455 | break; 456 | } 457 | return true; 458 | } 459 | 460 | 461 | void 462 | Reader::readNumber() 463 | { 464 | while ( current_ != end_ ) 465 | { 466 | if ( !(*current_ >= '0' && *current_ <= '9') && 467 | !in( *current_, '.', 'e', 'E', '+', '-' ) ) 468 | break; 469 | ++current_; 470 | } 471 | } 472 | 473 | bool 474 | Reader::readString() 475 | { 476 | Char c = 0; 477 | while ( current_ != end_ ) 478 | { 479 | c = getNextChar(); 480 | if ( c == '\\' ) 481 | getNextChar(); 482 | else if ( c == '"' ) 483 | break; 484 | } 485 | return c == '"'; 486 | } 487 | 488 | 489 | bool 490 | Reader::readObject( Token &tokenStart ) 491 | { 492 | Token tokenName; 493 | std::string name; 494 | currentValue() = Value( objectValue ); 495 | while ( readToken( tokenName ) ) 496 | { 497 | bool initialTokenOk = true; 498 | while ( tokenName.type_ == tokenComment && initialTokenOk ) 499 | initialTokenOk = readToken( tokenName ); 500 | if ( !initialTokenOk ) 501 | break; 502 | if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object 503 | return true; 504 | if ( tokenName.type_ != tokenString ) 505 | break; 506 | 507 | name = ""; 508 | if ( !decodeString( tokenName, name ) ) 509 | return recoverFromError( tokenObjectEnd ); 510 | 511 | Token colon; 512 | if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) 513 | { 514 | return addErrorAndRecover( "Missing ':' after object member name", 515 | colon, 516 | tokenObjectEnd ); 517 | } 518 | Value &value = currentValue()[ name ]; 519 | nodes_.push( &value ); 520 | bool ok = readValue(); 521 | nodes_.pop(); 522 | if ( !ok ) // error already set 523 | return recoverFromError( tokenObjectEnd ); 524 | 525 | Token comma; 526 | if ( !readToken( comma ) 527 | || ( comma.type_ != tokenObjectEnd && 528 | comma.type_ != tokenArraySeparator && 529 | comma.type_ != tokenComment ) ) 530 | { 531 | return addErrorAndRecover( "Missing ',' or '}' in object declaration", 532 | comma, 533 | tokenObjectEnd ); 534 | } 535 | bool finalizeTokenOk = true; 536 | while ( comma.type_ == tokenComment && 537 | finalizeTokenOk ) 538 | finalizeTokenOk = readToken( comma ); 539 | if ( comma.type_ == tokenObjectEnd ) 540 | return true; 541 | } 542 | return addErrorAndRecover( "Missing '}' or object member name", 543 | tokenName, 544 | tokenObjectEnd ); 545 | } 546 | 547 | 548 | bool 549 | Reader::readArray( Token &tokenStart ) 550 | { 551 | currentValue() = Value( arrayValue ); 552 | skipSpaces(); 553 | if ( *current_ == ']' ) // empty array 554 | { 555 | Token endArray; 556 | readToken( endArray ); 557 | return true; 558 | } 559 | int index = 0; 560 | while ( true ) 561 | { 562 | Value &value = currentValue()[ index++ ]; 563 | nodes_.push( &value ); 564 | bool ok = readValue(); 565 | nodes_.pop(); 566 | if ( !ok ) // error already set 567 | return recoverFromError( tokenArrayEnd ); 568 | 569 | Token token; 570 | // Accept Comment after last item in the array. 571 | ok = readToken( token ); 572 | while ( token.type_ == tokenComment && ok ) 573 | { 574 | ok = readToken( token ); 575 | } 576 | bool badTokenType = ( token.type_ == tokenArraySeparator && 577 | token.type_ == tokenArrayEnd ); 578 | if ( !ok || badTokenType ) 579 | { 580 | return addErrorAndRecover( "Missing ',' or ']' in array declaration", 581 | token, 582 | tokenArrayEnd ); 583 | } 584 | if ( token.type_ == tokenArrayEnd ) 585 | break; 586 | } 587 | return true; 588 | } 589 | 590 | 591 | bool 592 | Reader::decodeNumber( Token &token ) 593 | { 594 | bool isDouble = false; 595 | for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) 596 | { 597 | isDouble = isDouble 598 | || in( *inspect, '.', 'e', 'E', '+' ) 599 | || ( *inspect == '-' && inspect != token.start_ ); 600 | } 601 | if ( isDouble ) 602 | return decodeDouble( token ); 603 | Location current = token.start_; 604 | bool isNegative = *current == '-'; 605 | if ( isNegative ) 606 | ++current; 607 | Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) 608 | : Value::maxUInt) / 10; 609 | Value::UInt value = 0; 610 | while ( current < token.end_ ) 611 | { 612 | Char c = *current++; 613 | if ( c < '0' || c > '9' ) 614 | return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); 615 | if ( value >= threshold ) 616 | return decodeDouble( token ); 617 | value = value * 10 + Value::UInt(c - '0'); 618 | } 619 | if ( isNegative ) 620 | currentValue() = -Value::Int( value ); 621 | else if ( value <= Value::UInt(Value::maxInt) ) 622 | currentValue() = Value::Int( value ); 623 | else 624 | currentValue() = value; 625 | return true; 626 | } 627 | 628 | 629 | bool 630 | Reader::decodeDouble( Token &token ) 631 | { 632 | double value = 0; 633 | const int bufferSize = 32; 634 | int count; 635 | int length = int(token.end_ - token.start_); 636 | if ( length <= bufferSize ) 637 | { 638 | Char buffer[bufferSize]; 639 | memcpy( buffer, token.start_, length ); 640 | buffer[length] = 0; 641 | count = sscanf( buffer, "%lf", &value ); 642 | } 643 | else 644 | { 645 | std::string buffer( token.start_, token.end_ ); 646 | count = sscanf( buffer.c_str(), "%lf", &value ); 647 | } 648 | 649 | if ( count != 1 ) 650 | return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); 651 | currentValue() = value; 652 | return true; 653 | } 654 | 655 | 656 | bool 657 | Reader::decodeString( Token &token ) 658 | { 659 | std::string decoded; 660 | if ( !decodeString( token, decoded ) ) 661 | return false; 662 | currentValue() = decoded; 663 | return true; 664 | } 665 | 666 | 667 | bool 668 | Reader::decodeString( Token &token, std::string &decoded ) 669 | { 670 | decoded.reserve( token.end_ - token.start_ - 2 ); 671 | Location current = token.start_ + 1; // skip '"' 672 | Location end = token.end_ - 1; // do not include '"' 673 | while ( current != end ) 674 | { 675 | Char c = *current++; 676 | if ( c == '"' ) 677 | break; 678 | else if ( c == '\\' ) 679 | { 680 | if ( current == end ) 681 | return addError( "Empty escape sequence in string", token, current ); 682 | Char escape = *current++; 683 | switch ( escape ) 684 | { 685 | case '"': decoded += '"'; break; 686 | case '/': decoded += '/'; break; 687 | case '\\': decoded += '\\'; break; 688 | case 'b': decoded += '\b'; break; 689 | case 'f': decoded += '\f'; break; 690 | case 'n': decoded += '\n'; break; 691 | case 'r': decoded += '\r'; break; 692 | case 't': decoded += '\t'; break; 693 | case 'u': 694 | { 695 | unsigned int unicode; 696 | if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) 697 | return false; 698 | decoded += codePointToUTF8(unicode); 699 | } 700 | break; 701 | default: 702 | return addError( "Bad escape sequence in string", token, current ); 703 | } 704 | } 705 | else 706 | { 707 | decoded += c; 708 | } 709 | } 710 | return true; 711 | } 712 | 713 | bool 714 | Reader::decodeUnicodeCodePoint( Token &token, 715 | Location ¤t, 716 | Location end, 717 | unsigned int &unicode ) 718 | { 719 | 720 | if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) 721 | return false; 722 | if (unicode >= 0xD800 && unicode <= 0xDBFF) 723 | { 724 | // surrogate pairs 725 | if (end - current < 6) 726 | return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); 727 | unsigned int surrogatePair; 728 | if (*(current++) == '\\' && *(current++)== 'u') 729 | { 730 | if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) 731 | { 732 | unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); 733 | } 734 | else 735 | return false; 736 | } 737 | else 738 | return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); 739 | } 740 | return true; 741 | } 742 | 743 | bool 744 | Reader::decodeUnicodeEscapeSequence( Token &token, 745 | Location ¤t, 746 | Location end, 747 | unsigned int &unicode ) 748 | { 749 | if ( end - current < 4 ) 750 | return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); 751 | unicode = 0; 752 | for ( int index =0; index < 4; ++index ) 753 | { 754 | Char c = *current++; 755 | unicode *= 16; 756 | if ( c >= '0' && c <= '9' ) 757 | unicode += c - '0'; 758 | else if ( c >= 'a' && c <= 'f' ) 759 | unicode += c - 'a' + 10; 760 | else if ( c >= 'A' && c <= 'F' ) 761 | unicode += c - 'A' + 10; 762 | else 763 | return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); 764 | } 765 | return true; 766 | } 767 | 768 | 769 | bool 770 | Reader::addError( const std::string &message, 771 | Token &token, 772 | Location extra ) 773 | { 774 | ErrorInfo info; 775 | info.token_ = token; 776 | info.message_ = message; 777 | info.extra_ = extra; 778 | errors_.push_back( info ); 779 | return false; 780 | } 781 | 782 | 783 | bool 784 | Reader::recoverFromError( TokenType skipUntilToken ) 785 | { 786 | int errorCount = int(errors_.size()); 787 | Token skip; 788 | while ( true ) 789 | { 790 | if ( !readToken(skip) ) 791 | errors_.resize( errorCount ); // discard errors caused by recovery 792 | if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) 793 | break; 794 | } 795 | errors_.resize( errorCount ); 796 | return false; 797 | } 798 | 799 | 800 | bool 801 | Reader::addErrorAndRecover( const std::string &message, 802 | Token &token, 803 | TokenType skipUntilToken ) 804 | { 805 | addError( message, token ); 806 | return recoverFromError( skipUntilToken ); 807 | } 808 | 809 | 810 | Value & 811 | Reader::currentValue() 812 | { 813 | return *(nodes_.top()); 814 | } 815 | 816 | 817 | Reader::Char 818 | Reader::getNextChar() 819 | { 820 | if ( current_ == end_ ) 821 | return 0; 822 | return *current_++; 823 | } 824 | 825 | 826 | void 827 | Reader::getLocationLineAndColumn( Location location, 828 | int &line, 829 | int &column ) const 830 | { 831 | Location current = begin_; 832 | Location lastLineStart = current; 833 | line = 0; 834 | while ( current < location && current != end_ ) 835 | { 836 | Char c = *current++; 837 | if ( c == '\r' ) 838 | { 839 | if ( *current == '\n' ) 840 | ++current; 841 | lastLineStart = current; 842 | ++line; 843 | } 844 | else if ( c == '\n' ) 845 | { 846 | lastLineStart = current; 847 | ++line; 848 | } 849 | } 850 | // column & line start at 1 851 | column = int(location - lastLineStart) + 1; 852 | ++line; 853 | } 854 | 855 | 856 | std::string 857 | Reader::getLocationLineAndColumn( Location location ) const 858 | { 859 | int line, column; 860 | getLocationLineAndColumn( location, line, column ); 861 | char buffer[18+16+16+1]; 862 | sprintf( buffer, "Line %d, Column %d", line, column ); 863 | return buffer; 864 | } 865 | 866 | 867 | std::string 868 | Reader::getFormatedErrorMessages() const 869 | { 870 | std::string formattedMessage; 871 | for ( Errors::const_iterator itError = errors_.begin(); 872 | itError != errors_.end(); 873 | ++itError ) 874 | { 875 | const ErrorInfo &error = *itError; 876 | formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; 877 | formattedMessage += " " + error.message_ + "\n"; 878 | if ( error.extra_ ) 879 | formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; 880 | } 881 | return formattedMessage; 882 | } 883 | 884 | 885 | std::istream& operator>>( std::istream &sin, Value &root ) 886 | { 887 | Json::Reader reader; 888 | bool ok = reader.parse(sin, root, true); 889 | //JSON_ASSERT( ok ); 890 | if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages()); 891 | return sin; 892 | } 893 | 894 | 895 | } // namespace Json 896 | -------------------------------------------------------------------------------- /json/src/json_valueiterator.inl: -------------------------------------------------------------------------------- 1 | // included by json_value.cpp 2 | // everything is within Json namespace 3 | 4 | 5 | // ////////////////////////////////////////////////////////////////// 6 | // ////////////////////////////////////////////////////////////////// 7 | // ////////////////////////////////////////////////////////////////// 8 | // class ValueIteratorBase 9 | // ////////////////////////////////////////////////////////////////// 10 | // ////////////////////////////////////////////////////////////////// 11 | // ////////////////////////////////////////////////////////////////// 12 | 13 | ValueIteratorBase::ValueIteratorBase() 14 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 15 | : current_() 16 | , isNull_( true ) 17 | { 18 | } 19 | #else 20 | : isArray_( true ) 21 | , isNull_( true ) 22 | { 23 | iterator_.array_ = ValueInternalArray::IteratorState(); 24 | } 25 | #endif 26 | 27 | 28 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 29 | ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) 30 | : current_( current ) 31 | , isNull_( false ) 32 | { 33 | } 34 | #else 35 | ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) 36 | : isArray_( true ) 37 | { 38 | iterator_.array_ = state; 39 | } 40 | 41 | 42 | ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) 43 | : isArray_( false ) 44 | { 45 | iterator_.map_ = state; 46 | } 47 | #endif 48 | 49 | Value & 50 | ValueIteratorBase::deref() const 51 | { 52 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 53 | return current_->second; 54 | #else 55 | if ( isArray_ ) 56 | return ValueInternalArray::dereference( iterator_.array_ ); 57 | return ValueInternalMap::value( iterator_.map_ ); 58 | #endif 59 | } 60 | 61 | 62 | void 63 | ValueIteratorBase::increment() 64 | { 65 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 66 | ++current_; 67 | #else 68 | if ( isArray_ ) 69 | ValueInternalArray::increment( iterator_.array_ ); 70 | ValueInternalMap::increment( iterator_.map_ ); 71 | #endif 72 | } 73 | 74 | 75 | void 76 | ValueIteratorBase::decrement() 77 | { 78 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 79 | --current_; 80 | #else 81 | if ( isArray_ ) 82 | ValueInternalArray::decrement( iterator_.array_ ); 83 | ValueInternalMap::decrement( iterator_.map_ ); 84 | #endif 85 | } 86 | 87 | 88 | ValueIteratorBase::difference_type 89 | ValueIteratorBase::computeDistance( const SelfType &other ) const 90 | { 91 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 92 | # ifdef JSON_USE_CPPTL_SMALLMAP 93 | return current_ - other.current_; 94 | # else 95 | // Iterator for null value are initialized using the default 96 | // constructor, which initialize current_ to the default 97 | // std::map::iterator. As begin() and end() are two instance 98 | // of the default std::map::iterator, they can not be compared. 99 | // To allow this, we handle this comparison specifically. 100 | if ( isNull_ && other.isNull_ ) 101 | { 102 | return 0; 103 | } 104 | 105 | 106 | // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, 107 | // which is the one used by default). 108 | // Using a portable hand-made version for non random iterator instead: 109 | // return difference_type( std::distance( current_, other.current_ ) ); 110 | difference_type myDistance = 0; 111 | for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) 112 | { 113 | ++myDistance; 114 | } 115 | return myDistance; 116 | # endif 117 | #else 118 | if ( isArray_ ) 119 | return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); 120 | return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); 121 | #endif 122 | } 123 | 124 | 125 | bool 126 | ValueIteratorBase::isEqual( const SelfType &other ) const 127 | { 128 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 129 | if ( isNull_ ) 130 | { 131 | return other.isNull_; 132 | } 133 | return current_ == other.current_; 134 | #else 135 | if ( isArray_ ) 136 | return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); 137 | return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); 138 | #endif 139 | } 140 | 141 | 142 | void 143 | ValueIteratorBase::copy( const SelfType &other ) 144 | { 145 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 146 | current_ = other.current_; 147 | #else 148 | if ( isArray_ ) 149 | iterator_.array_ = other.iterator_.array_; 150 | iterator_.map_ = other.iterator_.map_; 151 | #endif 152 | } 153 | 154 | 155 | Value 156 | ValueIteratorBase::key() const 157 | { 158 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 159 | const Value::CZString czstring = (*current_).first; 160 | if ( czstring.c_str() ) 161 | { 162 | if ( czstring.isStaticString() ) 163 | return Value( StaticString( czstring.c_str() ) ); 164 | return Value( czstring.c_str() ); 165 | } 166 | return Value( czstring.index() ); 167 | #else 168 | if ( isArray_ ) 169 | return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); 170 | bool isStatic; 171 | const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); 172 | if ( isStatic ) 173 | return Value( StaticString( memberName ) ); 174 | return Value( memberName ); 175 | #endif 176 | } 177 | 178 | 179 | UInt 180 | ValueIteratorBase::index() const 181 | { 182 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 183 | const Value::CZString czstring = (*current_).first; 184 | if ( !czstring.c_str() ) 185 | return czstring.index(); 186 | return Value::UInt( -1 ); 187 | #else 188 | if ( isArray_ ) 189 | return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); 190 | return Value::UInt( -1 ); 191 | #endif 192 | } 193 | 194 | 195 | const char * 196 | ValueIteratorBase::memberName() const 197 | { 198 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 199 | const char *name = (*current_).first.c_str(); 200 | return name ? name : ""; 201 | #else 202 | if ( !isArray_ ) 203 | return ValueInternalMap::key( iterator_.map_ ); 204 | return ""; 205 | #endif 206 | } 207 | 208 | 209 | // ////////////////////////////////////////////////////////////////// 210 | // ////////////////////////////////////////////////////////////////// 211 | // ////////////////////////////////////////////////////////////////// 212 | // class ValueConstIterator 213 | // ////////////////////////////////////////////////////////////////// 214 | // ////////////////////////////////////////////////////////////////// 215 | // ////////////////////////////////////////////////////////////////// 216 | 217 | ValueConstIterator::ValueConstIterator() 218 | { 219 | } 220 | 221 | 222 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 223 | ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) 224 | : ValueIteratorBase( current ) 225 | { 226 | } 227 | #else 228 | ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) 229 | : ValueIteratorBase( state ) 230 | { 231 | } 232 | 233 | ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) 234 | : ValueIteratorBase( state ) 235 | { 236 | } 237 | #endif 238 | 239 | ValueConstIterator & 240 | ValueConstIterator::operator =( const ValueIteratorBase &other ) 241 | { 242 | copy( other ); 243 | return *this; 244 | } 245 | 246 | 247 | // ////////////////////////////////////////////////////////////////// 248 | // ////////////////////////////////////////////////////////////////// 249 | // ////////////////////////////////////////////////////////////////// 250 | // class ValueIterator 251 | // ////////////////////////////////////////////////////////////////// 252 | // ////////////////////////////////////////////////////////////////// 253 | // ////////////////////////////////////////////////////////////////// 254 | 255 | ValueIterator::ValueIterator() 256 | { 257 | } 258 | 259 | 260 | #ifndef JSON_VALUE_USE_INTERNAL_MAP 261 | ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) 262 | : ValueIteratorBase( current ) 263 | { 264 | } 265 | #else 266 | ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) 267 | : ValueIteratorBase( state ) 268 | { 269 | } 270 | 271 | ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) 272 | : ValueIteratorBase( state ) 273 | { 274 | } 275 | #endif 276 | 277 | ValueIterator::ValueIterator( const ValueConstIterator &other ) 278 | : ValueIteratorBase( other ) 279 | { 280 | } 281 | 282 | ValueIterator::ValueIterator( const ValueIterator &other ) 283 | : ValueIteratorBase( other ) 284 | { 285 | } 286 | 287 | ValueIterator & 288 | ValueIterator::operator =( const SelfType &other ) 289 | { 290 | copy( other ); 291 | return *this; 292 | } 293 | -------------------------------------------------------------------------------- /json/src/json_writer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #if _MSC_VER >= 1400 // VC++ 8.0 11 | #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. 12 | #endif 13 | 14 | namespace Json { 15 | 16 | static bool isControlCharacter(char ch) 17 | { 18 | return ch > 0 && ch <= 0x1F; 19 | } 20 | 21 | static bool containsControlCharacter( const char* str ) 22 | { 23 | while ( *str ) 24 | { 25 | if ( isControlCharacter( *(str++) ) ) 26 | return true; 27 | } 28 | return false; 29 | } 30 | static void uintToString( unsigned int value, 31 | char *¤t ) 32 | { 33 | *--current = 0; 34 | do 35 | { 36 | *--current = (value % 10) + '0'; 37 | value /= 10; 38 | } 39 | while ( value != 0 ); 40 | } 41 | 42 | std::string valueToString( Int value ) 43 | { 44 | char buffer[32]; 45 | char *current = buffer + sizeof(buffer); 46 | bool isNegative = value < 0; 47 | if ( isNegative ) 48 | value = -value; 49 | uintToString( UInt(value), current ); 50 | if ( isNegative ) 51 | *--current = '-'; 52 | assert( current >= buffer ); 53 | return current; 54 | } 55 | 56 | 57 | std::string valueToString( UInt value ) 58 | { 59 | char buffer[32]; 60 | char *current = buffer + sizeof(buffer); 61 | uintToString( value, current ); 62 | assert( current >= buffer ); 63 | return current; 64 | } 65 | 66 | std::string valueToString( double value ) 67 | { 68 | char buffer[32]; 69 | #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. 70 | sprintf_s(buffer, sizeof(buffer), "%#.16g", value); 71 | #else 72 | sprintf(buffer, "%#.16g", value); 73 | #endif 74 | char* ch = buffer + strlen(buffer) - 1; 75 | if (*ch != '0') return buffer; // nothing to truncate, so save time 76 | while(ch > buffer && *ch == '0'){ 77 | --ch; 78 | } 79 | char* last_nonzero = ch; 80 | while(ch >= buffer){ 81 | switch(*ch){ 82 | case '0': 83 | case '1': 84 | case '2': 85 | case '3': 86 | case '4': 87 | case '5': 88 | case '6': 89 | case '7': 90 | case '8': 91 | case '9': 92 | --ch; 93 | continue; 94 | case '.': 95 | // Truncate zeroes to save bytes in output, but keep one. 96 | *(last_nonzero+2) = '\0'; 97 | return buffer; 98 | default: 99 | return buffer; 100 | } 101 | } 102 | return buffer; 103 | } 104 | 105 | 106 | std::string valueToString( bool value ) 107 | { 108 | return value ? "true" : "false"; 109 | } 110 | 111 | std::string valueToQuotedString( const char *value ) 112 | { 113 | // Not sure how to handle unicode... 114 | if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) 115 | return std::string("\"") + value + "\""; 116 | // We have to walk value and escape any special characters. 117 | // Appending to std::string is not efficient, but this should be rare. 118 | // (Note: forward slashes are *not* rare, but I am not escaping them.) 119 | unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL 120 | std::string result; 121 | result.reserve(maxsize); // to avoid lots of mallocs 122 | result += "\""; 123 | for (const char* c=value; *c != 0; ++c) 124 | { 125 | switch(*c) 126 | { 127 | case '\"': 128 | result += "\\\""; 129 | break; 130 | case '\\': 131 | result += "\\\\"; 132 | break; 133 | case '\b': 134 | result += "\\b"; 135 | break; 136 | case '\f': 137 | result += "\\f"; 138 | break; 139 | case '\n': 140 | result += "\\n"; 141 | break; 142 | case '\r': 143 | result += "\\r"; 144 | break; 145 | case '\t': 146 | result += "\\t"; 147 | break; 148 | //case '/': 149 | // Even though \/ is considered a legal escape in JSON, a bare 150 | // slash is also legal, so I see no reason to escape it. 151 | // (I hope I am not misunderstanding something. 152 | // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); 161 | result += oss.str(); 162 | } 163 | else 164 | { 165 | result += *c; 166 | } 167 | break; 168 | } 169 | } 170 | result += "\""; 171 | return result; 172 | } 173 | 174 | // Class Writer 175 | // ////////////////////////////////////////////////////////////////// 176 | Writer::~Writer() 177 | { 178 | } 179 | 180 | 181 | // Class FastWriter 182 | // ////////////////////////////////////////////////////////////////// 183 | 184 | FastWriter::FastWriter() 185 | : yamlCompatiblityEnabled_( false ) 186 | { 187 | } 188 | 189 | 190 | void 191 | FastWriter::enableYAMLCompatibility() 192 | { 193 | yamlCompatiblityEnabled_ = true; 194 | } 195 | 196 | 197 | std::string 198 | FastWriter::write( const Value &root ) 199 | { 200 | document_ = ""; 201 | writeValue( root ); 202 | document_ += "\n"; 203 | return document_; 204 | } 205 | 206 | 207 | void 208 | FastWriter::writeValue( const Value &value ) 209 | { 210 | switch ( value.type() ) 211 | { 212 | case nullValue: 213 | document_ += "null"; 214 | break; 215 | case intValue: 216 | document_ += valueToString( value.asInt() ); 217 | break; 218 | case uintValue: 219 | document_ += valueToString( value.asUInt() ); 220 | break; 221 | case realValue: 222 | document_ += valueToString( value.asDouble() ); 223 | break; 224 | case stringValue: 225 | document_ += valueToQuotedString( value.asCString() ); 226 | break; 227 | case booleanValue: 228 | document_ += valueToString( value.asBool() ); 229 | break; 230 | case arrayValue: 231 | { 232 | document_ += "["; 233 | int size = value.size(); 234 | for ( int index =0; index < size; ++index ) 235 | { 236 | if ( index > 0 ) 237 | document_ += ","; 238 | writeValue( value[index] ); 239 | } 240 | document_ += "]"; 241 | } 242 | break; 243 | case objectValue: 244 | { 245 | Value::Members members( value.getMemberNames() ); 246 | document_ += "{"; 247 | for ( Value::Members::iterator it = members.begin(); 248 | it != members.end(); 249 | ++it ) 250 | { 251 | const std::string &name = *it; 252 | if ( it != members.begin() ) 253 | document_ += ","; 254 | document_ += valueToQuotedString( name.c_str() ); 255 | document_ += yamlCompatiblityEnabled_ ? ": " 256 | : ":"; 257 | writeValue( value[name] ); 258 | } 259 | document_ += "}"; 260 | } 261 | break; 262 | } 263 | } 264 | 265 | 266 | // Class StyledWriter 267 | // ////////////////////////////////////////////////////////////////// 268 | 269 | StyledWriter::StyledWriter() 270 | : rightMargin_( 74 ) 271 | , indentSize_( 3 ) 272 | { 273 | } 274 | 275 | 276 | std::string 277 | StyledWriter::write( const Value &root ) 278 | { 279 | document_ = ""; 280 | addChildValues_ = false; 281 | indentString_ = ""; 282 | writeCommentBeforeValue( root ); 283 | writeValue( root ); 284 | writeCommentAfterValueOnSameLine( root ); 285 | document_ += "\n"; 286 | return document_; 287 | } 288 | 289 | 290 | void 291 | StyledWriter::writeValue( const Value &value ) 292 | { 293 | switch ( value.type() ) 294 | { 295 | case nullValue: 296 | pushValue( "null" ); 297 | break; 298 | case intValue: 299 | pushValue( valueToString( value.asInt() ) ); 300 | break; 301 | case uintValue: 302 | pushValue( valueToString( value.asUInt() ) ); 303 | break; 304 | case realValue: 305 | pushValue( valueToString( value.asDouble() ) ); 306 | break; 307 | case stringValue: 308 | pushValue( valueToQuotedString( value.asCString() ) ); 309 | break; 310 | case booleanValue: 311 | pushValue( valueToString( value.asBool() ) ); 312 | break; 313 | case arrayValue: 314 | writeArrayValue( value); 315 | break; 316 | case objectValue: 317 | { 318 | Value::Members members( value.getMemberNames() ); 319 | if ( members.empty() ) 320 | pushValue( "{}" ); 321 | else 322 | { 323 | writeWithIndent( "{" ); 324 | indent(); 325 | Value::Members::iterator it = members.begin(); 326 | while ( true ) 327 | { 328 | const std::string &name = *it; 329 | const Value &childValue = value[name]; 330 | writeCommentBeforeValue( childValue ); 331 | writeWithIndent( valueToQuotedString( name.c_str() ) ); 332 | document_ += " : "; 333 | writeValue( childValue ); 334 | if ( ++it == members.end() ) 335 | { 336 | writeCommentAfterValueOnSameLine( childValue ); 337 | break; 338 | } 339 | document_ += ","; 340 | writeCommentAfterValueOnSameLine( childValue ); 341 | } 342 | unindent(); 343 | writeWithIndent( "}" ); 344 | } 345 | } 346 | break; 347 | } 348 | } 349 | 350 | 351 | void 352 | StyledWriter::writeArrayValue( const Value &value ) 353 | { 354 | unsigned size = value.size(); 355 | if ( size == 0 ) 356 | pushValue( "[]" ); 357 | else 358 | { 359 | bool isArrayMultiLine = isMultineArray( value ); 360 | if ( isArrayMultiLine ) 361 | { 362 | writeWithIndent( "[" ); 363 | indent(); 364 | bool hasChildValue = !childValues_.empty(); 365 | unsigned index =0; 366 | while ( true ) 367 | { 368 | const Value &childValue = value[index]; 369 | writeCommentBeforeValue( childValue ); 370 | if ( hasChildValue ) 371 | writeWithIndent( childValues_[index] ); 372 | else 373 | { 374 | writeIndent(); 375 | writeValue( childValue ); 376 | } 377 | if ( ++index == size ) 378 | { 379 | writeCommentAfterValueOnSameLine( childValue ); 380 | break; 381 | } 382 | document_ += ","; 383 | writeCommentAfterValueOnSameLine( childValue ); 384 | } 385 | unindent(); 386 | writeWithIndent( "]" ); 387 | } 388 | else // output on a single line 389 | { 390 | assert( childValues_.size() == size ); 391 | document_ += "[ "; 392 | for ( unsigned index =0; index < size; ++index ) 393 | { 394 | if ( index > 0 ) 395 | document_ += ", "; 396 | document_ += childValues_[index]; 397 | } 398 | document_ += " ]"; 399 | } 400 | } 401 | } 402 | 403 | 404 | bool 405 | StyledWriter::isMultineArray( const Value &value ) 406 | { 407 | int size = value.size(); 408 | bool isMultiLine = size*3 >= rightMargin_ ; 409 | childValues_.clear(); 410 | for ( int index =0; index < size && !isMultiLine; ++index ) 411 | { 412 | const Value &childValue = value[index]; 413 | isMultiLine = isMultiLine || 414 | ( (childValue.isArray() || childValue.isObject()) && 415 | childValue.size() > 0 ); 416 | } 417 | if ( !isMultiLine ) // check if line length > max line length 418 | { 419 | childValues_.reserve( size ); 420 | addChildValues_ = true; 421 | int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' 422 | for ( int index =0; index < size && !isMultiLine; ++index ) 423 | { 424 | writeValue( value[index] ); 425 | lineLength += int( childValues_[index].length() ); 426 | isMultiLine = isMultiLine && hasCommentForValue( value[index] ); 427 | } 428 | addChildValues_ = false; 429 | isMultiLine = isMultiLine || lineLength >= rightMargin_; 430 | } 431 | return isMultiLine; 432 | } 433 | 434 | 435 | void 436 | StyledWriter::pushValue( const std::string &value ) 437 | { 438 | if ( addChildValues_ ) 439 | childValues_.push_back( value ); 440 | else 441 | document_ += value; 442 | } 443 | 444 | 445 | void 446 | StyledWriter::writeIndent() 447 | { 448 | if ( !document_.empty() ) 449 | { 450 | char last = document_[document_.length()-1]; 451 | if ( last == ' ' ) // already indented 452 | return; 453 | if ( last != '\n' ) // Comments may add new-line 454 | document_ += '\n'; 455 | } 456 | document_ += indentString_; 457 | } 458 | 459 | 460 | void 461 | StyledWriter::writeWithIndent( const std::string &value ) 462 | { 463 | writeIndent(); 464 | document_ += value; 465 | } 466 | 467 | 468 | void 469 | StyledWriter::indent() 470 | { 471 | indentString_ += std::string( indentSize_, ' ' ); 472 | } 473 | 474 | 475 | void 476 | StyledWriter::unindent() 477 | { 478 | assert( int(indentString_.size()) >= indentSize_ ); 479 | indentString_.resize( indentString_.size() - indentSize_ ); 480 | } 481 | 482 | 483 | void 484 | StyledWriter::writeCommentBeforeValue( const Value &root ) 485 | { 486 | if ( !root.hasComment( commentBefore ) ) 487 | return; 488 | document_ += normalizeEOL( root.getComment( commentBefore ) ); 489 | document_ += "\n"; 490 | } 491 | 492 | 493 | void 494 | StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) 495 | { 496 | if ( root.hasComment( commentAfterOnSameLine ) ) 497 | document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); 498 | 499 | if ( root.hasComment( commentAfter ) ) 500 | { 501 | document_ += "\n"; 502 | document_ += normalizeEOL( root.getComment( commentAfter ) ); 503 | document_ += "\n"; 504 | } 505 | } 506 | 507 | 508 | bool 509 | StyledWriter::hasCommentForValue( const Value &value ) 510 | { 511 | return value.hasComment( commentBefore ) 512 | || value.hasComment( commentAfterOnSameLine ) 513 | || value.hasComment( commentAfter ); 514 | } 515 | 516 | 517 | std::string 518 | StyledWriter::normalizeEOL( const std::string &text ) 519 | { 520 | std::string normalized; 521 | normalized.reserve( text.length() ); 522 | const char *begin = text.c_str(); 523 | const char *end = begin + text.length(); 524 | const char *current = begin; 525 | while ( current != end ) 526 | { 527 | char c = *current++; 528 | if ( c == '\r' ) // mac or dos EOL 529 | { 530 | if ( *current == '\n' ) // convert dos EOL 531 | ++current; 532 | normalized += '\n'; 533 | } 534 | else // handle unix EOL & other char 535 | normalized += c; 536 | } 537 | return normalized; 538 | } 539 | 540 | 541 | // Class StyledStreamWriter 542 | // ////////////////////////////////////////////////////////////////// 543 | 544 | StyledStreamWriter::StyledStreamWriter( std::string indentation ) 545 | : document_(NULL) 546 | , rightMargin_( 74 ) 547 | , indentation_( indentation ) 548 | { 549 | } 550 | 551 | 552 | void 553 | StyledStreamWriter::write( std::ostream &out, const Value &root ) 554 | { 555 | document_ = &out; 556 | addChildValues_ = false; 557 | indentString_ = ""; 558 | writeCommentBeforeValue( root ); 559 | writeValue( root ); 560 | writeCommentAfterValueOnSameLine( root ); 561 | *document_ << "\n"; 562 | document_ = NULL; // Forget the stream, for safety. 563 | } 564 | 565 | 566 | void 567 | StyledStreamWriter::writeValue( const Value &value ) 568 | { 569 | switch ( value.type() ) 570 | { 571 | case nullValue: 572 | pushValue( "null" ); 573 | break; 574 | case intValue: 575 | pushValue( valueToString( value.asInt() ) ); 576 | break; 577 | case uintValue: 578 | pushValue( valueToString( value.asUInt() ) ); 579 | break; 580 | case realValue: 581 | pushValue( valueToString( value.asDouble() ) ); 582 | break; 583 | case stringValue: 584 | pushValue( valueToQuotedString( value.asCString() ) ); 585 | break; 586 | case booleanValue: 587 | pushValue( valueToString( value.asBool() ) ); 588 | break; 589 | case arrayValue: 590 | writeArrayValue( value); 591 | break; 592 | case objectValue: 593 | { 594 | Value::Members members( value.getMemberNames() ); 595 | if ( members.empty() ) 596 | pushValue( "{}" ); 597 | else 598 | { 599 | writeWithIndent( "{" ); 600 | indent(); 601 | Value::Members::iterator it = members.begin(); 602 | while ( true ) 603 | { 604 | const std::string &name = *it; 605 | const Value &childValue = value[name]; 606 | writeCommentBeforeValue( childValue ); 607 | writeWithIndent( valueToQuotedString( name.c_str() ) ); 608 | *document_ << " : "; 609 | writeValue( childValue ); 610 | if ( ++it == members.end() ) 611 | { 612 | writeCommentAfterValueOnSameLine( childValue ); 613 | break; 614 | } 615 | *document_ << ","; 616 | writeCommentAfterValueOnSameLine( childValue ); 617 | } 618 | unindent(); 619 | writeWithIndent( "}" ); 620 | } 621 | } 622 | break; 623 | } 624 | } 625 | 626 | 627 | void 628 | StyledStreamWriter::writeArrayValue( const Value &value ) 629 | { 630 | unsigned size = value.size(); 631 | if ( size == 0 ) 632 | pushValue( "[]" ); 633 | else 634 | { 635 | bool isArrayMultiLine = isMultineArray( value ); 636 | if ( isArrayMultiLine ) 637 | { 638 | writeWithIndent( "[" ); 639 | indent(); 640 | bool hasChildValue = !childValues_.empty(); 641 | unsigned index =0; 642 | while ( true ) 643 | { 644 | const Value &childValue = value[index]; 645 | writeCommentBeforeValue( childValue ); 646 | if ( hasChildValue ) 647 | writeWithIndent( childValues_[index] ); 648 | else 649 | { 650 | writeIndent(); 651 | writeValue( childValue ); 652 | } 653 | if ( ++index == size ) 654 | { 655 | writeCommentAfterValueOnSameLine( childValue ); 656 | break; 657 | } 658 | *document_ << ","; 659 | writeCommentAfterValueOnSameLine( childValue ); 660 | } 661 | unindent(); 662 | writeWithIndent( "]" ); 663 | } 664 | else // output on a single line 665 | { 666 | assert( childValues_.size() == size ); 667 | *document_ << "[ "; 668 | for ( unsigned index =0; index < size; ++index ) 669 | { 670 | if ( index > 0 ) 671 | *document_ << ", "; 672 | *document_ << childValues_[index]; 673 | } 674 | *document_ << " ]"; 675 | } 676 | } 677 | } 678 | 679 | 680 | bool 681 | StyledStreamWriter::isMultineArray( const Value &value ) 682 | { 683 | int size = value.size(); 684 | bool isMultiLine = size*3 >= rightMargin_ ; 685 | childValues_.clear(); 686 | for ( int index =0; index < size && !isMultiLine; ++index ) 687 | { 688 | const Value &childValue = value[index]; 689 | isMultiLine = isMultiLine || 690 | ( (childValue.isArray() || childValue.isObject()) && 691 | childValue.size() > 0 ); 692 | } 693 | if ( !isMultiLine ) // check if line length > max line length 694 | { 695 | childValues_.reserve( size ); 696 | addChildValues_ = true; 697 | int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' 698 | for ( int index =0; index < size && !isMultiLine; ++index ) 699 | { 700 | writeValue( value[index] ); 701 | lineLength += int( childValues_[index].length() ); 702 | isMultiLine = isMultiLine && hasCommentForValue( value[index] ); 703 | } 704 | addChildValues_ = false; 705 | isMultiLine = isMultiLine || lineLength >= rightMargin_; 706 | } 707 | return isMultiLine; 708 | } 709 | 710 | 711 | void 712 | StyledStreamWriter::pushValue( const std::string &value ) 713 | { 714 | if ( addChildValues_ ) 715 | childValues_.push_back( value ); 716 | else 717 | *document_ << value; 718 | } 719 | 720 | 721 | void 722 | StyledStreamWriter::writeIndent() 723 | { 724 | /* 725 | Some comments in this method would have been nice. ;-) 726 | 727 | if ( !document_.empty() ) 728 | { 729 | char last = document_[document_.length()-1]; 730 | if ( last == ' ' ) // already indented 731 | return; 732 | if ( last != '\n' ) // Comments may add new-line 733 | *document_ << '\n'; 734 | } 735 | */ 736 | *document_ << '\n' << indentString_; 737 | } 738 | 739 | 740 | void 741 | StyledStreamWriter::writeWithIndent( const std::string &value ) 742 | { 743 | writeIndent(); 744 | *document_ << value; 745 | } 746 | 747 | 748 | void 749 | StyledStreamWriter::indent() 750 | { 751 | indentString_ += indentation_; 752 | } 753 | 754 | 755 | void 756 | StyledStreamWriter::unindent() 757 | { 758 | assert( indentString_.size() >= indentation_.size() ); 759 | indentString_.resize( indentString_.size() - indentation_.size() ); 760 | } 761 | 762 | 763 | void 764 | StyledStreamWriter::writeCommentBeforeValue( const Value &root ) 765 | { 766 | if ( !root.hasComment( commentBefore ) ) 767 | return; 768 | *document_ << normalizeEOL( root.getComment( commentBefore ) ); 769 | *document_ << "\n"; 770 | } 771 | 772 | 773 | void 774 | StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) 775 | { 776 | if ( root.hasComment( commentAfterOnSameLine ) ) 777 | *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); 778 | 779 | if ( root.hasComment( commentAfter ) ) 780 | { 781 | *document_ << "\n"; 782 | *document_ << normalizeEOL( root.getComment( commentAfter ) ); 783 | *document_ << "\n"; 784 | } 785 | } 786 | 787 | 788 | bool 789 | StyledStreamWriter::hasCommentForValue( const Value &value ) 790 | { 791 | return value.hasComment( commentBefore ) 792 | || value.hasComment( commentAfterOnSameLine ) 793 | || value.hasComment( commentAfter ); 794 | } 795 | 796 | 797 | std::string 798 | StyledStreamWriter::normalizeEOL( const std::string &text ) 799 | { 800 | std::string normalized; 801 | normalized.reserve( text.length() ); 802 | const char *begin = text.c_str(); 803 | const char *end = begin + text.length(); 804 | const char *current = begin; 805 | while ( current != end ) 806 | { 807 | char c = *current++; 808 | if ( c == '\r' ) // mac or dos EOL 809 | { 810 | if ( *current == '\n' ) // convert dos EOL 811 | ++current; 812 | normalized += '\n'; 813 | } 814 | else // handle unix EOL & other char 815 | normalized += c; 816 | } 817 | return normalized; 818 | } 819 | 820 | 821 | std::ostream& operator<<( std::ostream &sout, const Value &root ) 822 | { 823 | Json::StyledStreamWriter writer; 824 | writer.write(sout, root); 825 | return sout; 826 | } 827 | 828 | 829 | } // namespace Json 830 | -------------------------------------------------------------------------------- /json/writer.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_WRITER_H_INCLUDED 2 | # define JSON_WRITER_H_INCLUDED 3 | 4 | # include "value.h" 5 | # include 6 | # include 7 | # include 8 | 9 | namespace Json { 10 | 11 | class Value; 12 | 13 | /** \brief Abstract class for writers. 14 | */ 15 | class JSON_API Writer 16 | { 17 | public: 18 | virtual ~Writer(); 19 | 20 | virtual std::string write( const Value &root ) = 0; 21 | }; 22 | 23 | /** \brief Outputs a Value in JSON format without formatting (not human friendly). 24 | * 25 | * The JSON document is written in a single line. It is not intended for 'human' consumption, 26 | * but may be usefull to support feature such as RPC where bandwith is limited. 27 | * \sa Reader, Value 28 | */ 29 | class JSON_API FastWriter : public Writer 30 | { 31 | public: 32 | FastWriter(); 33 | virtual ~FastWriter(){} 34 | 35 | void enableYAMLCompatibility(); 36 | 37 | public: // overridden from Writer 38 | virtual std::string write( const Value &root ); 39 | 40 | private: 41 | void writeValue( const Value &value ); 42 | 43 | std::string document_; 44 | bool yamlCompatiblityEnabled_; 45 | }; 46 | 47 | /** \brief Writes a Value in JSON format in a human friendly way. 48 | * 49 | * The rules for line break and indent are as follow: 50 | * - Object value: 51 | * - if empty then print {} without indent and line break 52 | * - if not empty the print '{', line break & indent, print one value per line 53 | * and then unindent and line break and print '}'. 54 | * - Array value: 55 | * - if empty then print [] without indent and line break 56 | * - if the array contains no object value, empty array or some other value types, 57 | * and all the values fit on one lines, then print the array on a single line. 58 | * - otherwise, it the values do not fit on one line, or the array contains 59 | * object or non empty array, then print one value per line. 60 | * 61 | * If the Value have comments then they are outputed according to their #CommentPlacement. 62 | * 63 | * \sa Reader, Value, Value::setComment() 64 | */ 65 | class JSON_API StyledWriter: public Writer 66 | { 67 | public: 68 | StyledWriter(); 69 | virtual ~StyledWriter(){} 70 | 71 | public: // overridden from Writer 72 | /** \brief Serialize a Value in JSON format. 73 | * \param root Value to serialize. 74 | * \return String containing the JSON document that represents the root value. 75 | */ 76 | virtual std::string write( const Value &root ); 77 | 78 | private: 79 | void writeValue( const Value &value ); 80 | void writeArrayValue( const Value &value ); 81 | bool isMultineArray( const Value &value ); 82 | void pushValue( const std::string &value ); 83 | void writeIndent(); 84 | void writeWithIndent( const std::string &value ); 85 | void indent(); 86 | void unindent(); 87 | void writeCommentBeforeValue( const Value &root ); 88 | void writeCommentAfterValueOnSameLine( const Value &root ); 89 | bool hasCommentForValue( const Value &value ); 90 | static std::string normalizeEOL( const std::string &text ); 91 | 92 | typedef std::vector ChildValues; 93 | 94 | ChildValues childValues_; 95 | std::string document_; 96 | std::string indentString_; 97 | int rightMargin_; 98 | int indentSize_; 99 | bool addChildValues_; 100 | }; 101 | 102 | /** \brief Writes a Value in JSON format in a human friendly way, 103 | to a stream rather than to a string. 104 | * 105 | * The rules for line break and indent are as follow: 106 | * - Object value: 107 | * - if empty then print {} without indent and line break 108 | * - if not empty the print '{', line break & indent, print one value per line 109 | * and then unindent and line break and print '}'. 110 | * - Array value: 111 | * - if empty then print [] without indent and line break 112 | * - if the array contains no object value, empty array or some other value types, 113 | * and all the values fit on one lines, then print the array on a single line. 114 | * - otherwise, it the values do not fit on one line, or the array contains 115 | * object or non empty array, then print one value per line. 116 | * 117 | * If the Value have comments then they are outputed according to their #CommentPlacement. 118 | * 119 | * \param indentation Each level will be indented by this amount extra. 120 | * \sa Reader, Value, Value::setComment() 121 | */ 122 | class JSON_API StyledStreamWriter 123 | { 124 | public: 125 | StyledStreamWriter( std::string indentation="\t" ); 126 | ~StyledStreamWriter(){} 127 | 128 | public: 129 | /** \brief Serialize a Value in JSON format. 130 | * \param out Stream to write to. (Can be ostringstream, e.g.) 131 | * \param root Value to serialize. 132 | * \note There is no point in deriving from Writer, since write() should not return a value. 133 | */ 134 | void write( std::ostream &out, const Value &root ); 135 | 136 | private: 137 | void writeValue( const Value &value ); 138 | void writeArrayValue( const Value &value ); 139 | bool isMultineArray( const Value &value ); 140 | void pushValue( const std::string &value ); 141 | void writeIndent(); 142 | void writeWithIndent( const std::string &value ); 143 | void indent(); 144 | void unindent(); 145 | void writeCommentBeforeValue( const Value &root ); 146 | void writeCommentAfterValueOnSameLine( const Value &root ); 147 | bool hasCommentForValue( const Value &value ); 148 | static std::string normalizeEOL( const std::string &text ); 149 | 150 | typedef std::vector ChildValues; 151 | 152 | ChildValues childValues_; 153 | std::ostream* document_; 154 | std::string indentString_; 155 | int rightMargin_; 156 | std::string indentation_; 157 | bool addChildValues_; 158 | }; 159 | 160 | std::string JSON_API valueToString( Int value ); 161 | std::string JSON_API valueToString( UInt value ); 162 | std::string JSON_API valueToString( double value ); 163 | std::string JSON_API valueToString( bool value ); 164 | std::string JSON_API valueToQuotedString( const char *value ); 165 | 166 | /// \brief Output using the StyledStreamWriter. 167 | /// \see Json::operator>>() 168 | std::ostream& operator<<( std::ostream&, const Value &root ); 169 | 170 | } // namespace Json 171 | 172 | 173 | 174 | #endif // JSON_WRITER_H_INCLUDED 175 | -------------------------------------------------------------------------------- /netmon.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2042 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netmonsys", "netmonsys\netmonsys.vcxproj", "{6F0EFE83-BD00-4E56-A5EC-E36C6B349577}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netmonlog", "netmonlog\netmonlog.vcxproj", "{0B2260B2-2D1C-48C7-A75F-9C715219EBA8}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "netmonset", "netmonset\netmonset.vcxproj", "{C0C4E86F-660C-4FC4-9723-FAF3649B350E}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|ARM = Debug|ARM 15 | Debug|ARM64 = Debug|ARM64 16 | Debug|x64 = Debug|x64 17 | Debug|x86 = Debug|x86 18 | Release|ARM = Release|ARM 19 | Release|ARM64 = Release|ARM64 20 | Release|x64 = Release|x64 21 | Release|x86 = Release|x86 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Debug|ARM.ActiveCfg = Debug|ARM 25 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Debug|ARM.Build.0 = Debug|ARM 26 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Debug|ARM.Deploy.0 = Debug|ARM 27 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Debug|ARM64.ActiveCfg = Debug|ARM64 28 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Debug|ARM64.Build.0 = Debug|ARM64 29 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Debug|ARM64.Deploy.0 = Debug|ARM64 30 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Debug|x64.ActiveCfg = Debug|x64 31 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Debug|x64.Build.0 = Debug|x64 32 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Debug|x64.Deploy.0 = Debug|x64 33 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Debug|x86.ActiveCfg = Debug|Win32 34 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Debug|x86.Build.0 = Debug|Win32 35 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Debug|x86.Deploy.0 = Debug|Win32 36 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Release|ARM.ActiveCfg = Release|ARM 37 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Release|ARM.Build.0 = Release|ARM 38 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Release|ARM.Deploy.0 = Release|ARM 39 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Release|ARM64.ActiveCfg = Release|ARM64 40 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Release|ARM64.Build.0 = Release|ARM64 41 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Release|ARM64.Deploy.0 = Release|ARM64 42 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Release|x64.ActiveCfg = Release|x64 43 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Release|x64.Build.0 = Release|x64 44 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Release|x64.Deploy.0 = Release|x64 45 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Release|x86.ActiveCfg = Release|Win32 46 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Release|x86.Build.0 = Release|Win32 47 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577}.Release|x86.Deploy.0 = Release|Win32 48 | {0B2260B2-2D1C-48C7-A75F-9C715219EBA8}.Debug|ARM.ActiveCfg = Debug|Win32 49 | {0B2260B2-2D1C-48C7-A75F-9C715219EBA8}.Debug|ARM64.ActiveCfg = Debug|Win32 50 | {0B2260B2-2D1C-48C7-A75F-9C715219EBA8}.Debug|x64.ActiveCfg = Debug|Win32 51 | {0B2260B2-2D1C-48C7-A75F-9C715219EBA8}.Debug|x64.Build.0 = Debug|Win32 52 | {0B2260B2-2D1C-48C7-A75F-9C715219EBA8}.Debug|x86.ActiveCfg = Debug|Win32 53 | {0B2260B2-2D1C-48C7-A75F-9C715219EBA8}.Debug|x86.Build.0 = Debug|Win32 54 | {0B2260B2-2D1C-48C7-A75F-9C715219EBA8}.Release|ARM.ActiveCfg = Release|Win32 55 | {0B2260B2-2D1C-48C7-A75F-9C715219EBA8}.Release|ARM64.ActiveCfg = Release|Win32 56 | {0B2260B2-2D1C-48C7-A75F-9C715219EBA8}.Release|x64.ActiveCfg = Release|x64 57 | {0B2260B2-2D1C-48C7-A75F-9C715219EBA8}.Release|x64.Build.0 = Release|x64 58 | {0B2260B2-2D1C-48C7-A75F-9C715219EBA8}.Release|x86.ActiveCfg = Release|Win32 59 | {0B2260B2-2D1C-48C7-A75F-9C715219EBA8}.Release|x86.Build.0 = Release|Win32 60 | {C0C4E86F-660C-4FC4-9723-FAF3649B350E}.Debug|ARM.ActiveCfg = Debug|Win32 61 | {C0C4E86F-660C-4FC4-9723-FAF3649B350E}.Debug|ARM64.ActiveCfg = Debug|Win32 62 | {C0C4E86F-660C-4FC4-9723-FAF3649B350E}.Debug|x64.ActiveCfg = Debug|Win32 63 | {C0C4E86F-660C-4FC4-9723-FAF3649B350E}.Debug|x64.Build.0 = Debug|Win32 64 | {C0C4E86F-660C-4FC4-9723-FAF3649B350E}.Debug|x86.ActiveCfg = Debug|Win32 65 | {C0C4E86F-660C-4FC4-9723-FAF3649B350E}.Debug|x86.Build.0 = Debug|Win32 66 | {C0C4E86F-660C-4FC4-9723-FAF3649B350E}.Release|ARM.ActiveCfg = Release|Win32 67 | {C0C4E86F-660C-4FC4-9723-FAF3649B350E}.Release|ARM64.ActiveCfg = Release|Win32 68 | {C0C4E86F-660C-4FC4-9723-FAF3649B350E}.Release|x64.ActiveCfg = Release|x64 69 | {C0C4E86F-660C-4FC4-9723-FAF3649B350E}.Release|x64.Build.0 = Release|x64 70 | {C0C4E86F-660C-4FC4-9723-FAF3649B350E}.Release|x86.ActiveCfg = Release|Win32 71 | {C0C4E86F-660C-4FC4-9723-FAF3649B350E}.Release|x86.Build.0 = Release|Win32 72 | EndGlobalSection 73 | GlobalSection(SolutionProperties) = preSolution 74 | HideSolutionNode = FALSE 75 | EndGlobalSection 76 | GlobalSection(ExtensibilityGlobals) = postSolution 77 | BuildVersion_StartDate = 2000/1/1 78 | SolutionGuid = {0798B303-3E19-42AC-8524-AD45908AEFA7} 79 | EndGlobalSection 80 | EndGlobal 81 | -------------------------------------------------------------------------------- /netmonlog/netmonlog.cpp: -------------------------------------------------------------------------------- 1 | // netmontest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 2 | // 3 | 4 | #include "pch.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | 14 | BOOL SetConsoleColor(WORD wAttributes) 15 | { 16 | HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 17 | if (hConsole == INVALID_HANDLE_VALUE) 18 | return FALSE; 19 | 20 | return SetConsoleTextAttribute(hConsole, wAttributes); 21 | } 22 | 23 | 24 | VOID PrintDns(LPCSTR lpszMsg) 25 | { 26 | Json::Value Value; 27 | if (Json::Reader().parse(lpszMsg, Value) ) 28 | { 29 | std::wstring Process = Value["Process"].asWString(); 30 | std::wstring RemoteIp = Value["RemoteIp"].asWString(); 31 | std::wstring Domain = Value["Domain"].asWString(); 32 | std::wstring Action = Value["Action"].asWString(); 33 | 34 | if (Action.compare(L"allow") == 0) 35 | SetConsoleColor(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); 36 | else 37 | SetConsoleColor(FOREGROUND_RED); 38 | 39 | std::wcout << L"DNS过滤:" << L"进程:" << Process << L"\t域名:" << Domain << std::endl; 40 | } 41 | } 42 | 43 | VOID PrintIP(LPCSTR lpszMsg) 44 | { 45 | Json::Value Value; 46 | if ( Json::Reader().parse(lpszMsg,Value)) 47 | { 48 | std::wstring Process = Value["Process"].asWString(); 49 | std::wstring RemoteIp = Value["RemoteIp"].asWString(); 50 | std::wstring Action = Value["Action"].asWString(); 51 | WORD RemotePort = Value["RemotePort"].asInt(); 52 | 53 | if (Action.compare(L"allow") == 0) 54 | SetConsoleColor(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); 55 | else 56 | SetConsoleColor(FOREGROUND_RED); 57 | 58 | std::wcout << L"IP过滤:" << L"进程:" << Process << L"\t地址:" << RemoteIp << L":" << RemotePort << std::endl; 59 | } 60 | } 61 | 62 | int _stdcall frame_call(void* param, int uCode, void *pInBuf, int nInCch, void * pOutBuf, int nOutCch, int* nOutSize) 63 | { 64 | switch (uCode) 65 | { 66 | case LPC_MESSAGE_ID_DNS_VISIT: 67 | PrintDns((LPCSTR)pInBuf); 68 | break; 69 | case LPC_MESSAGE_ID_IP_VISIT: 70 | PrintIP((LPCSTR)pInBuf); 71 | break; 72 | default: 73 | break; 74 | } 75 | return 0; 76 | } 77 | 78 | int main() 79 | { 80 | setlocale(LC_ALL, "chs"); 81 | frame_create(NETMONSYS_NAMESPACE, NULL, frame_call); 82 | MSG msg = { 0 }; 83 | while (GetMessage(&msg, NULL, 0, 0)) 84 | { 85 | 86 | } 87 | std::cout << "Hello World!\n"; 88 | } 89 | -------------------------------------------------------------------------------- /netmonlog/netmonlog.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonlog/netmonlog.rc -------------------------------------------------------------------------------- /netmonlog/netmonlog.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {0B2260B2-2D1C-48C7-A75F-9C715219EBA8} 24 | Win32Proj 25 | netmontest 26 | 10.0.17763.0 27 | netmonlog 28 | 29 | 30 | 31 | Application 32 | true 33 | v100 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v141 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v100 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v141 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | 77 | 78 | true 79 | 80 | 81 | false 82 | 83 | 84 | false 85 | 86 | 87 | 88 | Use 89 | Level3 90 | Disabled 91 | true 92 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 93 | true 94 | pch.h 95 | $(msddk)\user\include;..\include;%(AdditionalIncludeDirectories) 96 | 97 | 98 | Console 99 | true 100 | $(msddk)\user\bin 101 | 102 | 103 | 104 | 105 | Use 106 | Level3 107 | Disabled 108 | false 109 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 110 | false 111 | pch.h 112 | $(msddk)\user\include;..\include;..\ 113 | MultiThreadedDebug 114 | 115 | 116 | Console 117 | true 118 | $(msddk)\user\bin 119 | RequireAdministrator 120 | 121 | 122 | 123 | 124 | Use 125 | Level3 126 | MaxSpeed 127 | true 128 | true 129 | true 130 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 131 | true 132 | pch.h 133 | 134 | 135 | Console 136 | true 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | Use 144 | Level3 145 | MaxSpeed 146 | true 147 | true 148 | true 149 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 150 | true 151 | pch.h 152 | 153 | 154 | Console 155 | true 156 | true 157 | true 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | Create 168 | Create 169 | Create 170 | Create 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /netmonlog/netmonlog.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 头文件 20 | 21 | 22 | 头文件 23 | 24 | 25 | 26 | 27 | 源文件 28 | 29 | 30 | 源文件 31 | 32 | 33 | 34 | 35 | 资源文件 36 | 37 | 38 | -------------------------------------------------------------------------------- /netmonlog/pch.cpp: -------------------------------------------------------------------------------- 1 | // pch.cpp: 与预编译标头对应的源文件;编译成功所必需的 2 | 3 | #include "pch.h" 4 | 5 | // 一般情况下,忽略此文件,但如果你使用的是预编译标头,请保留它。 6 | -------------------------------------------------------------------------------- /netmonlog/pch.h: -------------------------------------------------------------------------------- 1 | // 入门提示: 2 | // 1. 使用解决方案资源管理器窗口添加/管理文件 3 | // 2. 使用团队资源管理器窗口连接到源代码管理 4 | // 3. 使用输出窗口查看生成输出和其他消息 5 | // 4. 使用错误列表窗口查看错误 6 | // 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目 7 | // 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件 8 | 9 | #ifndef PCH_H 10 | #define PCH_H 11 | 12 | // TODO: 添加要在此处预编译的标头 13 | 14 | #endif //PCH_H 15 | -------------------------------------------------------------------------------- /netmonlog/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonlog/resource.h -------------------------------------------------------------------------------- /netmonset/cconv.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonset/cconv.h -------------------------------------------------------------------------------- /netmonset/netmonset.cpp: -------------------------------------------------------------------------------- 1 | // netmonset.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 2 | // 3 | 4 | #include "pch.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "cconv.h" 10 | #include 11 | using namespace msdk; 12 | HRESULT InsertWhiteRule(LPCWSTR lpszProcess) 13 | { 14 | Json::Value value; 15 | value["Process"] = w2utf8(lpszProcess); 16 | 17 | std::string json = Json::FastWriter().write(value); 18 | HRESULT hResult = frame_send2(NETMONSYS_NAMESPACE, IOCT_ADD_WHITE_RULE, (LPVOID)json.c_str(), json.length() + 1, 0, 0, 0); 19 | if ( SUCCEEDED(hResult) ) 20 | { 21 | std::wcout << L"设置白名单策略成功" << lpszProcess << std::endl; 22 | } 23 | return hResult; 24 | } 25 | 26 | HRESULT InsertIPRule(LPCWSTR lpszIP, WORD Port) 27 | { 28 | Json::Value value; 29 | value["RemoteIp"] = lpszIP; 30 | value["RemotePort"] = Port; 31 | 32 | std::string json = Json::FastWriter().write(value); 33 | HRESULT hResult = frame_send2(NETMONSYS_NAMESPACE, IOCT_ADD_IP_RULE, (LPVOID)json.c_str(), json.length() + 1, 0, 0, 0); 34 | if (SUCCEEDED(hResult)) 35 | { 36 | std::wcout << L"设置IP策略成功" << lpszIP << std::endl; 37 | } 38 | return hResult; 39 | } 40 | 41 | 42 | HRESULT InsertDomainRule(LPCSTR lpszDomain) 43 | { 44 | Json::Value value; 45 | value["Domain"] = lpszDomain; 46 | 47 | 48 | std::string json = Json::FastWriter().write(value); 49 | HRESULT hResult = frame_send2(NETMONSYS_NAMESPACE, IOCT_ADD_DOMAIN_RULE, (LPVOID)json.c_str(), json.length() + 1, 0, 0, 0); 50 | if (SUCCEEDED(hResult)) 51 | { 52 | std::cout << L"Domain" << lpszDomain << std::endl; 53 | } 54 | 55 | return hResult; 56 | } 57 | 58 | int main() 59 | { 60 | setlocale(LC_ALL, "chs"); 61 | 62 | frame_send2(NETMONSYS_NAMESPACE, IOCT_CLEAR_WHITE_RULE, 0, 0, 0, 0, 0); 63 | frame_send2(NETMONSYS_NAMESPACE, IOCT_CLEAR_IP_RULE, 0, 0, 0, 0, 0); 64 | frame_send2(NETMONSYS_NAMESPACE, IOCT_CLEAR_DOMAIN_RULE, 0, 0, 0, 0, 0); 65 | 66 | InsertWhiteRule(L"iexplore.exe"); 67 | InsertIPRule(L"220.181.111.37", 443); 68 | InsertIPRule(L"220.181.57.216", 443); 69 | InsertIPRule(L"69.171.224.12", 443); 70 | InsertIPRule(L"216.58.197.110", 443); 71 | InsertIPRule(L"220.181.112.244", 443); //百度的网址 72 | InsertDomainRule(".*.hao123.com"); 73 | InsertDomainRule(".*.2345.com"); 74 | std::cout << "Hello World!\n"; 75 | } -------------------------------------------------------------------------------- /netmonset/netmonset.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonset/netmonset.rc -------------------------------------------------------------------------------- /netmonset/netmonset.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {C0C4E86F-660C-4FC4-9723-FAF3649B350E} 24 | Win32Proj 25 | netmonset 26 | 10.0.17763.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v100 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v141 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v141 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v141 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Use 88 | Level3 89 | Disabled 90 | true 91 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | pch.h 94 | 95 | 96 | Console 97 | true 98 | 99 | 100 | 101 | 102 | Use 103 | Level3 104 | Disabled 105 | false 106 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | false 108 | pch.h 109 | $(msddk)\user\include;..\include;..\ 110 | MultiThreadedDebug 111 | 112 | 113 | Console 114 | true 115 | $(msddk)\user\bin 116 | RequireAdministrator 117 | %(AdditionalDependencies) 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | Use 127 | Level3 128 | MaxSpeed 129 | true 130 | true 131 | true 132 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 133 | true 134 | pch.h 135 | 136 | 137 | Console 138 | true 139 | true 140 | true 141 | 142 | 143 | AutoVersion.exe 144 | 145 | 146 | 147 | 148 | Use 149 | Level3 150 | MaxSpeed 151 | true 152 | true 153 | true 154 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 155 | true 156 | pch.h 157 | 158 | 159 | Console 160 | true 161 | true 162 | true 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | Create 173 | Create 174 | Create 175 | Create 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /netmonset/netmonset.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 头文件 20 | 21 | 22 | 头文件 23 | 24 | 25 | 26 | 27 | 源文件 28 | 29 | 30 | 源文件 31 | 32 | 33 | 34 | 35 | 资源文件 36 | 37 | 38 | -------------------------------------------------------------------------------- /netmonset/netmonset.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /netmonset/pch.cpp: -------------------------------------------------------------------------------- 1 | // pch.cpp: 与预编译标头对应的源文件;编译成功所必需的 2 | 3 | #include "pch.h" 4 | 5 | // 一般情况下,忽略此文件,但如果你使用的是预编译标头,请保留它。 6 | -------------------------------------------------------------------------------- /netmonset/pch.h: -------------------------------------------------------------------------------- 1 | // 入门提示: 2 | // 1. 使用解决方案资源管理器窗口添加/管理文件 3 | // 2. 使用团队资源管理器窗口连接到源代码管理 4 | // 3. 使用输出窗口查看生成输出和其他消息 5 | // 4. 使用错误列表窗口查看错误 6 | // 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目 7 | // 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件 8 | 9 | #ifndef PCH_H 10 | #define PCH_H 11 | 12 | // TODO: 添加要在此处预编译的标头 13 | 14 | #endif //PCH_H 15 | -------------------------------------------------------------------------------- /netmonset/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonset/resource.h -------------------------------------------------------------------------------- /netmonsys/AutoVersion.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonsys/AutoVersion.exe -------------------------------------------------------------------------------- /netmonsys/CDnsDomainParse.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonsys/CDnsDomainParse.cpp -------------------------------------------------------------------------------- /netmonsys/CDnsDomainParse.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | class CDnsDomainParse 3 | { 4 | public: 5 | CDnsDomainParse(); 6 | ~CDnsDomainParse(); 7 | 8 | NTSTATUS DecodeDotStr(char *szEncodedStr, USHORT *pusEncodedStrLen, char *szDotStr, USHORT nDotStrSize, char *szPacketStartPos = NULL); 9 | }; 10 | 11 | -------------------------------------------------------------------------------- /netmonsys/CDnsTask.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CDnsTask.h" 3 | #include "WfpHelp.h" 4 | #include "kfile/path.h" 5 | #include 6 | #include 7 | 8 | 9 | CDnsTask::CDnsTask(IP_Classify* ipClassify, LPCSTR lpszDomain, NTSTATUS ntAccess) 10 | :CIPTask(ipClassify, ntAccess) 11 | { 12 | strcpy_s(m_szDomain, _countof(m_szDomain), lpszDomain); 13 | } 14 | 15 | 16 | CDnsTask::~CDnsTask() 17 | { 18 | } 19 | 20 | VOID CDnsTask::DoTask() 21 | { 22 | WCHAR szIpAddress[128]; 23 | LPCWSTR pAddressEnd; 24 | CKePageStringW ProcPath; 25 | 26 | ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); 27 | pAddressEnd = Ipv4AddressToString(uRemoteIp, szIpAddress, _countof(szIpAddress)); 28 | CKePath::NtFileNameToDosFileName(ProcessImage, ProcPath); 29 | 30 | json_ptr root = json_object(); 31 | json_ptr value = json_string(u2utf8(ProcPath)); 32 | json_object_set(root, "Process", value); 33 | 34 | value = json_string(u2utf8(szIpAddress)); 35 | json_object_set(root, "RemoteIp", value); 36 | 37 | value = json_string(m_szDomain); 38 | json_object_set(root, "Domain", value); 39 | 40 | value = json_string(NT_SUCCESS(Action) ? "allow" : "denied"); 41 | json_object_set(root, "Action", value); 42 | 43 | char* data = json_dumps(root, 0); 44 | SendMessage2(LPC_MESSAGE_ID_DNS_VISIT, data); 45 | jsonp_free(data); 46 | } 47 | -------------------------------------------------------------------------------- /netmonsys/CDnsTask.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CIPTask.h" 3 | class CDnsTask : public CIPTask 4 | { 5 | public: 6 | CDnsTask(IP_Classify* ipClassify, LPCSTR lpszDomain, NTSTATUS ntAccess); 7 | ~CDnsTask(); 8 | 9 | protected: 10 | virtual VOID DoTask(); 11 | public: 12 | CHAR m_szDomain[MAX_PATH]; 13 | }; 14 | 15 | -------------------------------------------------------------------------------- /netmonsys/CFlowContext.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CFlowContext.h" 3 | 4 | 5 | LONG CFlowContext::g_FlowCount = 0; 6 | 7 | 8 | CFlowContext::CFlowContext(UINT64 flowHandle, UINT16 layerId, UINT32 calloutId) 9 | { 10 | FlowHandle = flowHandle; 11 | LayerId = layerId; 12 | CalloutId = calloutId; 13 | ProcessID = 0; 14 | ULONG count = InterlockedIncrement(&g_FlowCount); (count); 15 | KdPrint(("FlowContext->g_FlowCount:%d\n", count)); 16 | } 17 | 18 | CFlowContext::~CFlowContext() 19 | { 20 | ULONG count = InterlockedDecrement(&g_FlowCount); (count); 21 | KdPrint(("FlowContext->g_FlowCount:%d\n", count)); 22 | } 23 | -------------------------------------------------------------------------------- /netmonsys/CFlowContext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | using namespace msddk; 4 | class CFlowContext:public NonPagedObject 5 | { 6 | public: 7 | CFlowContext(UINT64 flowHandle, UINT16 layerId, UINT32 calloutId); 8 | ~CFlowContext(); 9 | 10 | public: 11 | UINT64 FlowHandle; 12 | UINT16 LayerId; 13 | UINT32 CalloutId; 14 | UINT64 ProcessID; 15 | CKeStringW ProcessImage; 16 | public: 17 | static LONG g_FlowCount; 18 | }; 19 | 20 | -------------------------------------------------------------------------------- /netmonsys/CIPTask.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonsys/CIPTask.cpp -------------------------------------------------------------------------------- /netmonsys/CIPTask.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonsys/CIPTask.h -------------------------------------------------------------------------------- /netmonsys/CMetaValue.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CMetaValue.h" 3 | 4 | 5 | CMetaValue::CMetaValue(const FWPS_INCOMING_METADATA_VALUES* inMetaValues) 6 | { 7 | m_inMetaValues = inMetaValues; 8 | ProcessId = inMetaValues->processId; 9 | } 10 | 11 | 12 | CMetaValue::~CMetaValue() 13 | { 14 | } 15 | 16 | msddk::CKeStringW CMetaValue::GetProcessPath() 17 | { 18 | CKeStringW Path; 19 | if ( m_inMetaValues ) 20 | { 21 | UINT32 uLenght = m_inMetaValues->processPath->size / 2; 22 | LPWSTR lpBuf = Path.GetBufferSetLength(uLenght); 23 | memcpy(lpBuf, m_inMetaValues->processPath->data, m_inMetaValues->processPath->size); 24 | Path.ReleaseBuffer(); 25 | } 26 | return Path; 27 | } 28 | 29 | UINT CMetaValue::GetProcessID() 30 | { 31 | return (UINT)m_inMetaValues->processId; 32 | } 33 | -------------------------------------------------------------------------------- /netmonsys/CMetaValue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | using namespace msddk; 4 | class CMetaValue 5 | { 6 | public: 7 | CMetaValue(const FWPS_INCOMING_METADATA_VALUES* inMetaValues); 8 | ~CMetaValue(); 9 | 10 | CKeStringW GetProcessPath(); 11 | UINT GetProcessID(); 12 | public: 13 | UINT64 ProcessId; 14 | private: 15 | const FWPS_INCOMING_METADATA_VALUES* m_inMetaValues; 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /netmonsys/CTaskBase.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.h" 3 | #include "CTaskBase.h" 4 | #include 5 | 6 | NTSTATUS CTaskBase::SendMessage2(int msg, const char* data) 7 | { 8 | return CKeLpcClient(NETMONSYS_NAMESPACE).SendMessage(msg, (LPVOID)data, (int)strlen(data) + 1, NULL, 0, NULL, NULL); 9 | } 10 | 11 | -------------------------------------------------------------------------------- /netmonsys/CTaskBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | using namespace msddk; 5 | class CTaskBase : public NonPagedObject 6 | { 7 | public: 8 | CTaskBase() {} 9 | virtual ~CTaskBase() {} 10 | 11 | NTSTATUS SendMessage2(int msg, const char* data); 12 | 13 | public: 14 | virtual VOID DoTask() = 0; 15 | }; 16 | -------------------------------------------------------------------------------- /netmonsys/CTaskCenter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "CTaskBase.h" 5 | #include 6 | using namespace msddk; 7 | class CTaskCenter : public CkeWorkerThread 8 | { 9 | public: 10 | CTaskCenter() {} 11 | ~CTaskCenter(){} 12 | 13 | protected: 14 | virtual void DispatchItem(void *pItem) 15 | { 16 | CTaskBase* pTask = (CTaskBase*)pItem; 17 | if (pTask) 18 | { 19 | pTask->DoTask(); 20 | delete pTask; 21 | } 22 | } 23 | }; 24 | 25 | -------------------------------------------------------------------------------- /netmonsys/CalloutImpl.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CalloutImpl.h" 3 | #include "kutil\dbg.h" 4 | 5 | 6 | using namespace msddk; 7 | CalloutImpl::CalloutImpl() 8 | { 9 | CalloutID = 0; 10 | fwpmId = 0; 11 | filterId = 0; 12 | } 13 | 14 | CalloutImpl::~CalloutImpl() 15 | { 16 | } 17 | 18 | VOID CalloutImpl::Initialize(PDEVICE_OBJECT obj, HANDLE hEngine) 19 | { 20 | m_DeviceObject = obj; 21 | m_hEngine = hEngine; 22 | } 23 | 24 | NTSTATUS CalloutImpl::Register(IN PWCHAR wszName, IN PWCHAR wszDesc, IN const GUID* calloutKey, IN const GUID* layerKey, IN FWPS_CALLOUT_CLASSIFY_FN classifyFn, IN FWPS_CALLOUT_NOTIFY_FN notifyFn, IN FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN flowDeleteNotifyFn, IN UINT32 flags) 25 | { 26 | NTSTATUS status = STATUS_SUCCESS; 27 | FWPS_CALLOUT sCallout = { 0 }; 28 | FWPM_CALLOUT mCallout = { 0 }; 29 | FWPM_FILTER mFilter = { 0 }; 30 | 31 | sCallout.calloutKey = *calloutKey; 32 | sCallout.flags = flags; 33 | sCallout.classifyFn = classifyFn; 34 | sCallout.flowDeleteFn = flowDeleteNotifyFn; 35 | sCallout.notifyFn = notifyFn; 36 | status = FwpsCalloutRegister(m_DeviceObject, &sCallout, &CalloutID); 37 | if ( !NT_SUCCESS(status) ) 38 | { 39 | KdPrint(("FwpsCalloutRegister(%ws,%ws) faild.%ws", wszName, wszDesc, MapNTStatus(status))); 40 | return status; 41 | } 42 | 43 | mCallout.displayData.name = wszName; 44 | mCallout.displayData.description = wszDesc; 45 | mCallout.calloutKey = *calloutKey; 46 | mCallout.applicableLayer = *layerKey; 47 | status = FwpmCalloutAdd(m_hEngine, &mCallout, NULL, &fwpmId); 48 | if ( !NT_SUCCESS( status) ) 49 | { 50 | KdPrint(("FwpmCalloutAdd(%ws,%ws) faild.%ws", wszName, wszDesc, MapNTStatus(status))); 51 | return status; 52 | } 53 | 54 | 55 | 56 | mFilter.action.calloutKey = *calloutKey; 57 | mFilter.action.type = FWP_ACTION_CALLOUT_TERMINATING; 58 | mFilter.displayData.name = wszName; 59 | mFilter.displayData.description = wszDesc; 60 | mFilter.layerKey = *layerKey; 61 | mFilter.numFilterConditions = 0; 62 | mFilter.filterCondition = NULL; 63 | mFilter.subLayerKey = FWPM_SUBLAYER_UNIVERSAL; 64 | mFilter.weight.type = FWP_EMPTY; 65 | status = FwpmFilterAdd(m_hEngine, &mFilter, NULL, &filterId); 66 | if ( !NT_SUCCESS(status) ) 67 | { 68 | KdPrint(("FwpmFilterAdd(%ws,%ws) faild.%ws", wszName, wszDesc, MapNTStatus(status))); 69 | return status; 70 | } 71 | 72 | return status; 73 | } 74 | 75 | NTSTATUS CalloutImpl::UnRegister() 76 | { 77 | if (filterId) 78 | { 79 | FwpmFilterDeleteById(m_hEngine, filterId); 80 | filterId = 0; 81 | } 82 | 83 | if (fwpmId) 84 | { 85 | FwpmCalloutDeleteById(m_hEngine, fwpmId); 86 | fwpmId = 0; 87 | } 88 | 89 | if (CalloutID) 90 | { 91 | FwpsCalloutUnregisterById(CalloutID); 92 | CalloutID = 0; 93 | } 94 | 95 | return STATUS_SUCCESS; 96 | } 97 | -------------------------------------------------------------------------------- /netmonsys/CalloutImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | class CalloutImpl 5 | { 6 | public: 7 | CalloutImpl(); 8 | ~CalloutImpl(); 9 | 10 | VOID Initialize(PDEVICE_OBJECT obj, HANDLE hEngine); 11 | 12 | NTSTATUS Register(IN PWCHAR wszName, 13 | IN PWCHAR wszDesc, 14 | IN const GUID* calloutKey, 15 | IN const GUID* layerKey, 16 | IN FWPS_CALLOUT_CLASSIFY_FN classifyFn, 17 | IN FWPS_CALLOUT_NOTIFY_FN notifyFn, 18 | IN FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN flowDeleteNotifyFn, 19 | IN UINT32 flags); 20 | 21 | NTSTATUS UnRegister(); 22 | 23 | public: 24 | UINT32 CalloutID; 25 | UINT32 fwpmId; 26 | UINT64 filterId; 27 | private: 28 | HANDLE m_hEngine; 29 | PDEVICE_OBJECT m_DeviceObject; 30 | 31 | }; 32 | 33 | -------------------------------------------------------------------------------- /netmonsys/Callouts.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Callouts.h" 3 | #include "NetMonDevice.h" 4 | NTSTATUS CalloutNotifyFn( 5 | _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType, 6 | _In_ const GUID* filterKey, 7 | _Inout_ FWPS_FILTER* filter) 8 | { 9 | return CNetMonDevice::g_NetMonDevice->CalloutNotifyFn 10 | ( 11 | notifyType, 12 | filterKey, 13 | filter 14 | ); 15 | } 16 | 17 | VOID CalloutFlowDeleteFn(IN UINT16 layerId, IN UINT32 calloutId, IN UINT64 flowContext) 18 | { 19 | CNetMonDevice::g_NetMonDevice->CalloutFlowDeleteFn 20 | ( 21 | layerId, 22 | calloutId, 23 | flowContext 24 | ); 25 | } 26 | 27 | VOID CalloutClassifyFn( 28 | IN const FWPS_INCOMING_VALUES* inFixedValues, 29 | IN const FWPS_INCOMING_METADATA_VALUES* inMetaValues, 30 | IN VOID* layerData, 31 | IN const void* classifyContext, 32 | IN const FWPS_FILTER* filter, 33 | IN UINT64 flowContext, 34 | OUT FWPS_CLASSIFY_OUT* classifyOut) 35 | { 36 | CNetMonDevice::g_NetMonDevice->CalloutClassifyFn 37 | ( 38 | inFixedValues, 39 | inMetaValues, 40 | layerData, 41 | classifyContext, 42 | filter, 43 | flowContext, 44 | classifyOut 45 | ); 46 | } -------------------------------------------------------------------------------- /netmonsys/Callouts.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | NTSTATUS CalloutNotifyFn( 4 | _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType, 5 | _In_ const GUID* filterKey, 6 | _Inout_ FWPS_FILTER* filter); 7 | 8 | VOID CalloutFlowDeleteFn( 9 | IN UINT16 layerId, 10 | IN UINT32 calloutId, 11 | IN UINT64 flowContext 12 | ); 13 | VOID CalloutClassifyFn( 14 | IN const FWPS_INCOMING_VALUES* inFixedValues, 15 | IN const FWPS_INCOMING_METADATA_VALUES* inMetaValues, 16 | IN VOID* layerData, 17 | IN const void* classifyContext, 18 | IN const FWPS_FILTER* filter, 19 | IN UINT64 flowContext, 20 | OUT FWPS_CLASSIFY_OUT* classifyOut 21 | ); -------------------------------------------------------------------------------- /netmonsys/ClassDefine.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "ClassDefine.h" 3 | #include "WfpHelp.h" 4 | #include "CMetaValue.h" 5 | 6 | IP_Classify::IP_Classify(const FWPS_INCOMING_VALUES* inFixedValues,const FWPS_INCOMING_METADATA_VALUES* inMetaValues) 7 | { 8 | UINT32 nIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT; 9 | wLocalPort = inFixedValues->incomingValue[nIndex].value.int16; 10 | 11 | nIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS; 12 | uLocalIp = s_htonl(inFixedValues->incomingValue[nIndex].value.int32); 13 | 14 | nIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT; 15 | wRemotePort = inFixedValues->incomingValue[nIndex].value.int16; 16 | 17 | nIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS; 18 | uRemoteIp = s_htonl(inFixedValues->incomingValue[nIndex].value.int32); 19 | 20 | nIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL; 21 | wProtocol = inFixedValues->incomingValue[nIndex].value.uint8; 22 | 23 | memcpy_s(ProcessImage, sizeof(ProcessImage), inMetaValues->processPath->data, inMetaValues->processPath->size); 24 | ProcessImage[_countof(ProcessImage) - 1] = 0; 25 | ProcessID = (UINT)inMetaValues->processId; 26 | } 27 | -------------------------------------------------------------------------------- /netmonsys/ClassDefine.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonsys/ClassDefine.h -------------------------------------------------------------------------------- /netmonsys/NetMonDevice.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonsys/NetMonDevice.cpp -------------------------------------------------------------------------------- /netmonsys/NetMonDevice.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonsys/NetMonDevice.h -------------------------------------------------------------------------------- /netmonsys/WfpHelp.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #include "WfpHelp.h" 4 | #include 5 | #include 6 | LPCWSTR Ipv4AddressToString(UINT32 ipAddr, LPWSTR Str, INT nLen) 7 | { 8 | BYTE *pbyIPSegment = (BYTE*)(&ipAddr); 9 | _snwprintf(Str, nLen, L"%d.%d.%d.%d", pbyIPSegment[0], pbyIPSegment[1], pbyIPSegment[2], pbyIPSegment[3]); 10 | return Str; 11 | } 12 | 13 | NTSTATUS IpV4StringToAddress(LPCWSTR Str, UINT32& Addr) 14 | { 15 | LPCWSTR lpEnd; 16 | IN_ADDR IpAddr; 17 | NTSTATUS status = RtlIpv4StringToAddressW(Str, FALSE, &lpEnd, &IpAddr); 18 | if ( NT_SUCCESS(status) ) 19 | Addr = IpAddr.S_un.S_addr; 20 | 21 | return status; 22 | } 23 | 24 | NTSTATUS IpV4StringToAddress(LPCSTR Str, UINT32& Addr) 25 | { 26 | LPCSTR lpEnd; 27 | IN_ADDR IpAddr; 28 | NTSTATUS status = RtlIpv4StringToAddressA(Str, FALSE, &lpEnd, &IpAddr); 29 | if (NT_SUCCESS(status)) 30 | Addr = IpAddr.S_un.S_addr; 31 | 32 | return status; 33 | } 34 | -------------------------------------------------------------------------------- /netmonsys/WfpHelp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct _UDP_HEADER_ 4 | { 5 | UINT16 sourcePort; 6 | UINT16 destinationPort; 7 | UINT16 length; 8 | UINT16 checksum; 9 | }UDP_HEADER, *PUDP_HEADER; 10 | 11 | #ifndef s_htons 12 | #define s_htons(num) ( \ 13 | ( ((USHORT)(num) & 0xff00) >> 8 ) | \ 14 | ( ((USHORT)(num) & 0x00ff) << 8 ) ) 15 | #define s_ntohs s_htons 16 | 17 | #endif // !s_htons 18 | 19 | 20 | #ifndef s_htonl 21 | #define s_htonl(num) ( \ 22 | ( ((UINT32)(num) & 0xff000000) >> 24 ) | \ 23 | ( ((UINT32)(num) & 0x00ff0000) >> 8 ) | \ 24 | ( ((UINT32)(num) & 0x0000ff00) << 8 ) | \ 25 | ( ((UINT32)(num) & 0x000000ff) << 24 ) ) 26 | #define s_ntohl s_htonl 27 | #endif 28 | 29 | LPCWSTR Ipv4AddressToString(UINT32 ipAddr, LPWSTR Str, INT nLen); 30 | NTSTATUS IpV4StringToAddress(LPCWSTR Str, UINT32& Addr); 31 | NTSTATUS IpV4StringToAddress(LPCSTR Str, UINT32& Addr); -------------------------------------------------------------------------------- /netmonsys/deelx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonsys/deelx.h -------------------------------------------------------------------------------- /netmonsys/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "stdafx.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "NetMonDevice.h" 9 | 10 | #include 11 | 12 | using namespace msddk; 13 | DRIVER_ENTRY(SimpleDrive); -------------------------------------------------------------------------------- /netmonsys/netmonsys.inf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonsys/netmonsys.inf -------------------------------------------------------------------------------- /netmonsys/netmonsys.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonsys/netmonsys.rc -------------------------------------------------------------------------------- /netmonsys/netmonsys.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | Debug 22 | ARM 23 | 24 | 25 | Release 26 | ARM 27 | 28 | 29 | Debug 30 | ARM64 31 | 32 | 33 | Release 34 | ARM64 35 | 36 | 37 | 38 | {6F0EFE83-BD00-4E56-A5EC-E36C6B349577} 39 | {1bc93793-694f-48fe-9372-81e2b05556fd} 40 | v4.5 41 | 12.0 42 | Debug 43 | Win32 44 | netmonsys 45 | 46 | 47 | 48 | Windows7 49 | true 50 | WindowsKernelModeDriver10.0 51 | Driver 52 | WDM 53 | Desktop 54 | 55 | 56 | Windows7 57 | false 58 | WindowsKernelModeDriver10.0 59 | Driver 60 | KMDF 61 | Desktop 62 | 63 | 64 | Windows7 65 | true 66 | WindowsKernelModeDriver10.0 67 | Driver 68 | WDM 69 | Desktop 70 | 71 | 72 | Windows7 73 | false 74 | WindowsKernelModeDriver10.0 75 | Driver 76 | WDM 77 | Desktop 78 | 79 | 80 | Windows7 81 | true 82 | WindowsKernelModeDriver10.0 83 | Driver 84 | KMDF 85 | Desktop 86 | 87 | 88 | Windows7 89 | false 90 | WindowsKernelModeDriver10.0 91 | Driver 92 | KMDF 93 | Desktop 94 | 95 | 96 | Windows7 97 | true 98 | WindowsKernelModeDriver10.0 99 | Driver 100 | KMDF 101 | Desktop 102 | 103 | 104 | Windows7 105 | false 106 | WindowsKernelModeDriver10.0 107 | Driver 108 | KMDF 109 | Desktop 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | DbgengKernelDebugger 121 | 122 | 123 | DbgengKernelDebugger 124 | 125 | 126 | DbgengKernelDebugger 127 | true 128 | 129 | 130 | DbgengKernelDebugger 131 | false 132 | 133 | 134 | DbgengKernelDebugger 135 | 136 | 137 | DbgengKernelDebugger 138 | 139 | 140 | DbgengKernelDebugger 141 | 142 | 143 | DbgengKernelDebugger 144 | 145 | 146 | 147 | $(msddk)\kernel\include;%(AdditionalIncludeDirectories) 148 | Create 149 | 150 | 151 | fwpkclnt.lib;%(AdditionalDependencies) 152 | 153 | 154 | 155 | 156 | $(msddk)\kernel\include;%(AdditionalIncludeDirectories) 157 | Create 158 | 159 | 160 | fwpkclnt.lib;%(AdditionalDependencies) 161 | 162 | 163 | 164 | 165 | $(msddk)\kernel\include;%(AdditionalIncludeDirectories) 166 | Create 167 | 168 | 169 | fwpkclnt.lib;%(AdditionalDependencies) 170 | 171 | 172 | 173 | 174 | $(msddk)\kernel\include;%(AdditionalIncludeDirectories) 175 | Create 176 | 177 | 178 | fwpkclnt.lib;%(AdditionalDependencies) 179 | 180 | 181 | 182 | 183 | $(msddk)\kernel\include;..\include;%(AdditionalIncludeDirectories) 184 | Create 185 | false 186 | 187 | 188 | fwpkclnt.lib;$(DDK_LIB_PATH)\ndis.lib;libcntpr.lib;%(AdditionalDependencies) 189 | 190 | 191 | AutoVersion.exe 192 | 193 | 194 | 195 | 196 | $(msddk)\kernel\include;%(AdditionalIncludeDirectories) 197 | Create 198 | 199 | 200 | fwpkclnt.lib;%(AdditionalDependencies) 201 | 202 | 203 | 204 | 205 | $(msddk)\kernel\include;..\include;%(AdditionalIncludeDirectories) 206 | Create 207 | 208 | 209 | fwpkclnt.lib;$(DDK_LIB_PATH)\ndis.lib;libcntpr.lib;%(AdditionalDependencies) 210 | 211 | 212 | true 213 | 214 | 215 | AutoVersion.exe 216 | 217 | 218 | 219 | 220 | $(msddk)\kernel\include;..\include;%(AdditionalIncludeDirectories) 221 | Create 222 | 223 | 224 | fwpkclnt.lib;$(DDK_LIB_PATH)\ndis.lib;libcntpr.lib;%(AdditionalDependencies) 225 | 226 | 227 | AutoVersion.exe 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | Use 239 | Use 240 | Use 241 | Use 242 | Use 243 | Use 244 | Use 245 | Use 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | -------------------------------------------------------------------------------- /netmonsys/netmonsys.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | 22 | 23 | Driver Files 24 | 25 | 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files 59 | 60 | 61 | Source Files 62 | 63 | 64 | Source Files 65 | 66 | 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | Header Files 76 | 77 | 78 | Header Files 79 | 80 | 81 | Header Files 82 | 83 | 84 | Header Files 85 | 86 | 87 | Header Files 88 | 89 | 90 | Header Files 91 | 92 | 93 | Header Files 94 | 95 | 96 | Header Files 97 | 98 | 99 | Header Files 100 | 101 | 102 | Header Files 103 | 104 | 105 | Header Files 106 | 107 | 108 | Header Files 109 | 110 | 111 | Header Files 112 | 113 | 114 | Header Files 115 | 116 | 117 | 118 | 119 | Resource Files 120 | 121 | 122 | -------------------------------------------------------------------------------- /netmonsys/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/netmonsys/resource.h -------------------------------------------------------------------------------- /netmonsys/slre.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2013 Sergey Lyubka 3 | * Copyright (c) 2013 Cesanta Software Limited 4 | * All rights reserved 5 | * 6 | * This library is dual-licensed: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 as 8 | * published by the Free Software Foundation. For the terms of this 9 | * license, see . 10 | * 11 | * You are free to use this library under the terms of the GNU General 12 | * Public License, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the GNU General Public License for more details. 15 | * 16 | * Alternatively, you can license this library under a commercial 17 | * license, as set out in . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "stdafx.h" 25 | 26 | #include "slre.h" 27 | 28 | #define MAX_BRANCHES 100 29 | #define MAX_BRACKETS 100 30 | #define FAIL_IF(condition, error_code) if (condition) return (error_code) 31 | 32 | #ifndef ARRAY_SIZE 33 | #define ARRAY_SIZE(ar) (sizeof(ar) / sizeof((ar)[0])) 34 | #endif 35 | 36 | #ifdef SLRE_DEBUG 37 | #define SLRE_DBG(x) KdPrint(x) 38 | #else 39 | #define SLRE_DBG(x) 40 | #endif 41 | 42 | struct bracket_pair { 43 | const char *ptr; /* Points to the first char after '(' in regex */ 44 | int len; /* Length of the text between '(' and ')' */ 45 | int branches; /* Index in the branches array for this pair */ 46 | int num_branches; /* Number of '|' in this bracket pair */ 47 | }; 48 | 49 | struct branch { 50 | int bracket_index; /* index for 'struct bracket_pair brackets' */ 51 | /* array defined below */ 52 | const char *schlong; /* points to the '|' character in the regex */ 53 | }; 54 | 55 | struct regex_info { 56 | /* 57 | * Describes all bracket pairs in the regular expression. 58 | * First entry is always present, and grabs the whole regex. 59 | */ 60 | struct bracket_pair brackets[MAX_BRACKETS]; 61 | int num_brackets; 62 | 63 | /* 64 | * Describes alternations ('|' operators) in the regular expression. 65 | * Each branch falls into a specific branch pair. 66 | */ 67 | struct branch branches[MAX_BRANCHES]; 68 | int num_branches; 69 | 70 | /* Array of captures provided by the user */ 71 | struct slre_cap *caps; 72 | int num_caps; 73 | 74 | /* E.g. SLRE_IGNORE_CASE. See enum below */ 75 | int flags; 76 | }; 77 | 78 | static int is_metacharacter(const unsigned char *s) { 79 | static const char *metacharacters = "^$().[]*+?|\\Ssdbfnrtv"; 80 | return strchr(metacharacters, *s) != NULL; 81 | } 82 | 83 | static int op_len(const char *re) { 84 | return re[0] == '\\' && re[1] == 'x' ? 4 : re[0] == '\\' ? 2 : 1; 85 | } 86 | 87 | static int set_len(const char *re, int re_len) { 88 | int len = 0; 89 | 90 | while (len < re_len && re[len] != ']') { 91 | len += op_len(re + len); 92 | } 93 | 94 | return len <= re_len ? len + 1 : -1; 95 | } 96 | 97 | static int get_op_len(const char *re, int re_len) { 98 | return re[0] == '[' ? set_len(re + 1, re_len - 1) + 1 : op_len(re); 99 | } 100 | 101 | static int is_quantifier(const char *re) { 102 | return re[0] == '*' || re[0] == '+' || re[0] == '?'; 103 | } 104 | 105 | static int toi(int x) { 106 | return isdigit(x) ? x - '0' : x - 'W'; 107 | } 108 | 109 | static int hextoi(const unsigned char *s) { 110 | return (toi(tolower(s[0])) << 4) | toi(tolower(s[1])); 111 | } 112 | 113 | static int match_op(const unsigned char *re, const unsigned char *s, 114 | struct regex_info *info) { 115 | int result = 0; 116 | switch (*re) { 117 | case '\\': 118 | /* Metacharacters */ 119 | switch (re[1]) { 120 | case 'S': FAIL_IF(isspace(*s), SLRE_NO_MATCH); result++; break; 121 | case 's': FAIL_IF(!isspace(*s), SLRE_NO_MATCH); result++; break; 122 | case 'd': FAIL_IF(!isdigit(*s), SLRE_NO_MATCH); result++; break; 123 | case 'b': FAIL_IF(*s != '\b', SLRE_NO_MATCH); result++; break; 124 | case 'f': FAIL_IF(*s != '\f', SLRE_NO_MATCH); result++; break; 125 | case 'n': FAIL_IF(*s != '\n', SLRE_NO_MATCH); result++; break; 126 | case 'r': FAIL_IF(*s != '\r', SLRE_NO_MATCH); result++; break; 127 | case 't': FAIL_IF(*s != '\t', SLRE_NO_MATCH); result++; break; 128 | case 'v': FAIL_IF(*s != '\v', SLRE_NO_MATCH); result++; break; 129 | 130 | case 'x': 131 | /* Match byte, \xHH where HH is hexadecimal byte representaion */ 132 | FAIL_IF(hextoi(re + 2) != *s, SLRE_NO_MATCH); 133 | result++; 134 | break; 135 | 136 | default: 137 | /* Valid metacharacter check is done in bar() */ 138 | FAIL_IF(re[1] != s[0], SLRE_NO_MATCH); 139 | result++; 140 | break; 141 | } 142 | break; 143 | 144 | case '|': FAIL_IF(1, SLRE_INTERNAL_ERROR); break; 145 | case '$': FAIL_IF(1, SLRE_NO_MATCH); break; 146 | case '.': result++; break; 147 | 148 | default: 149 | if (info->flags & SLRE_IGNORE_CASE) { 150 | FAIL_IF(tolower(*re) != tolower(*s), SLRE_NO_MATCH); 151 | } else { 152 | FAIL_IF(*re != *s, SLRE_NO_MATCH); 153 | } 154 | result++; 155 | break; 156 | } 157 | 158 | return result; 159 | } 160 | 161 | static int match_set(const char *re, int re_len, const char *s, 162 | struct regex_info *info) { 163 | int len = 0, result = -1, invert = re[0] == '^'; 164 | 165 | if (invert) re++, re_len--; 166 | 167 | while (len <= re_len && re[len] != ']' && result <= 0) { 168 | /* Support character range */ 169 | if (re[len] != '-' && re[len + 1] == '-' && re[len + 2] != ']' && 170 | re[len + 2] != '\0') { 171 | result = info->flags & SLRE_IGNORE_CASE ? 172 | tolower(*s) >= tolower(re[len]) && tolower(*s) <= tolower(re[len + 2]) : 173 | *s >= re[len] && *s <= re[len + 2]; 174 | len += 3; 175 | } else { 176 | result = match_op((const unsigned char *) re + len, (const unsigned char *) s, info); 177 | len += op_len(re + len); 178 | } 179 | } 180 | return (!invert && result > 0) || (invert && result <= 0) ? 1 : -1; 181 | } 182 | 183 | static int doh(const char *s, int s_len, struct regex_info *info, int bi); 184 | 185 | static int bar(const char *re, int re_len, const char *s, int s_len, 186 | struct regex_info *info, int bi) { 187 | /* i is offset in re, j is offset in s, bi is brackets index */ 188 | int i, j, n, step; 189 | 190 | for (i = j = 0; i < re_len && j <= s_len; i += step) { 191 | 192 | /* Handle quantifiers. Get the length of the chunk. */ 193 | step = re[i] == '(' ? info->brackets[bi + 1].len + 2 : 194 | get_op_len(re + i, re_len - i); 195 | 196 | SLRE_DBG(("%s [%.*s] [%.*s] re_len=%d step=%d i=%d j=%d\n", __func__, 197 | re_len - i, re + i, s_len - j, s + j, re_len, step, i, j)); 198 | 199 | FAIL_IF(is_quantifier(&re[i]), SLRE_UNEXPECTED_QUANTIFIER); 200 | FAIL_IF(step <= 0, SLRE_INVALID_CHARACTER_SET); 201 | 202 | if (i + step < re_len && is_quantifier(re + i + step)) { 203 | SLRE_DBG(("QUANTIFIER: [%.*s]%c [%.*s]\n", step, re + i, 204 | re[i + step], s_len - j, s + j)); 205 | if (re[i + step] == '?') { 206 | int result = bar(re + i, step, s + j, s_len - j, info, bi); 207 | j += result > 0 ? result : 0; 208 | i++; 209 | } else if (re[i + step] == '+' || re[i + step] == '*') { 210 | int j2 = j, nj = j, n1, n2 = -1, ni, non_greedy = 0; 211 | 212 | /* Points to the regexp code after the quantifier */ 213 | ni = i + step + 1; 214 | if (ni < re_len && re[ni] == '?') { 215 | non_greedy = 1; 216 | ni++; 217 | } 218 | 219 | do { 220 | if ((n1 = bar(re + i, step, s + j2, s_len - j2, info, bi)) > 0) { 221 | j2 += n1; 222 | } 223 | if (re[i + step] == '+' && n1 < 0) break; 224 | 225 | if (ni >= re_len) { 226 | /* After quantifier, there is nothing */ 227 | nj = j2; 228 | } else if ((n2 = bar(re + ni, re_len - ni, s + j2, 229 | s_len - j2, info, bi)) >= 0) { 230 | /* Regex after quantifier matched */ 231 | nj = j2 + n2; 232 | } 233 | if (nj > j && non_greedy) break; 234 | } while (n1 > 0); 235 | 236 | /* 237 | * Even if we found one or more pattern, this branch will be executed, 238 | * changing the next captures. 239 | */ 240 | if (n1 < 0 && n2 < 0 && re[i + step] == '*' && 241 | (n2 = bar(re + ni, re_len - ni, s + j, s_len - j, info, bi)) > 0) { 242 | nj = j + n2; 243 | } 244 | 245 | SLRE_DBG(("STAR/PLUS END: %d %d %d %d %d\n", j, nj, re_len - ni, n1, n2)); 246 | FAIL_IF(re[i + step] == '+' && nj == j, SLRE_NO_MATCH); 247 | 248 | /* If while loop body above was not executed for the * quantifier, */ 249 | /* make sure the rest of the regex matches */ 250 | FAIL_IF(nj == j && ni < re_len && n2 < 0, SLRE_NO_MATCH); 251 | 252 | /* Returning here cause we've matched the rest of RE already */ 253 | return nj; 254 | } 255 | continue; 256 | } 257 | 258 | if (re[i] == '[') { 259 | n = match_set(re + i + 1, re_len - (i + 2), s + j, info); 260 | SLRE_DBG(("SET %.*s [%.*s] -> %d\n", step, re + i, s_len - j, s + j, n)); 261 | FAIL_IF(n <= 0, SLRE_NO_MATCH); 262 | j += n; 263 | } else if (re[i] == '(') { 264 | n = SLRE_NO_MATCH; 265 | bi++; 266 | FAIL_IF(bi >= info->num_brackets, SLRE_INTERNAL_ERROR); 267 | SLRE_DBG(("CAPTURING [%.*s] [%.*s] [%s]\n", 268 | step, re + i, s_len - j, s + j, re + i + step)); 269 | 270 | if (re_len - (i + step) <= 0) { 271 | /* Nothing follows brackets */ 272 | n = doh(s + j, s_len - j, info, bi); 273 | } else { 274 | int j2; 275 | for (j2 = 0; j2 <= s_len - j; j2++) { 276 | if ((n = doh(s + j, s_len - (j + j2), info, bi)) >= 0 && 277 | bar(re + i + step, re_len - (i + step), 278 | s + j + n, s_len - (j + n), info, bi) >= 0) break; 279 | } 280 | } 281 | 282 | SLRE_DBG(("CAPTURED [%.*s] [%.*s]:%d\n", step, re + i, s_len - j, s + j, n)); 283 | FAIL_IF(n < 0, n); 284 | if (info->caps != NULL && n > 0) { 285 | info->caps[bi - 1].ptr = s + j; 286 | info->caps[bi - 1].len = n; 287 | } 288 | j += n; 289 | } else if (re[i] == '^') { 290 | FAIL_IF(j != 0, SLRE_NO_MATCH); 291 | } else if (re[i] == '$') { 292 | FAIL_IF(j != s_len, SLRE_NO_MATCH); 293 | } else { 294 | FAIL_IF(j >= s_len, SLRE_NO_MATCH); 295 | n = match_op((const unsigned char *) (re + i), (const unsigned char *) (s + j), info); 296 | FAIL_IF(n <= 0, n); 297 | j += n; 298 | } 299 | } 300 | 301 | return j; 302 | } 303 | 304 | /* Process branch points */ 305 | static int doh(const char *s, int s_len, struct regex_info *info, int bi) { 306 | const struct bracket_pair *b = &info->brackets[bi]; 307 | int i = 0, len, result; 308 | const char *p; 309 | 310 | do { 311 | p = i == 0 ? b->ptr : info->branches[b->branches + i - 1].schlong + 1; 312 | len = b->num_branches == 0 ? b->len : 313 | i == b->num_branches ? (int) (b->ptr + b->len - p) : 314 | (int) (info->branches[b->branches + i].schlong - p); 315 | SLRE_DBG(("%s %d %d [%.*s] [%.*s]\n", __func__, bi, i, len, p, s_len, s)); 316 | result = bar(p, len, s, s_len, info, bi); 317 | SLRE_DBG(("%s <- %d\n", __func__, result)); 318 | } while (result <= 0 && i++ < b->num_branches); /* At least 1 iteration */ 319 | 320 | return result; 321 | } 322 | 323 | static int baz(const char *s, int s_len, struct regex_info *info) { 324 | int i, result = -1, is_anchored = info->brackets[0].ptr[0] == '^'; 325 | 326 | for (i = 0; i <= s_len; i++) { 327 | result = doh(s + i, s_len - i, info, 0); 328 | if (result >= 0) { 329 | result += i; 330 | break; 331 | } 332 | if (is_anchored) break; 333 | } 334 | 335 | return result; 336 | } 337 | 338 | static void setup_branch_points(struct regex_info *info) { 339 | int i, j; 340 | struct branch tmp; 341 | 342 | /* First, sort branches. Must be stable, no qsort. Use bubble algo. */ 343 | for (i = 0; i < info->num_branches; i++) { 344 | for (j = i + 1; j < info->num_branches; j++) { 345 | if (info->branches[i].bracket_index > info->branches[j].bracket_index) { 346 | tmp = info->branches[i]; 347 | info->branches[i] = info->branches[j]; 348 | info->branches[j] = tmp; 349 | } 350 | } 351 | } 352 | 353 | /* 354 | * For each bracket, set their branch points. This way, for every bracket 355 | * (i.e. every chunk of regex) we know all branch points before matching. 356 | */ 357 | for (i = j = 0; i < info->num_brackets; i++) { 358 | info->brackets[i].num_branches = 0; 359 | info->brackets[i].branches = j; 360 | while (j < info->num_branches && info->branches[j].bracket_index == i) { 361 | info->brackets[i].num_branches++; 362 | j++; 363 | } 364 | } 365 | } 366 | 367 | static int foo(const char *re, int re_len, const char *s, int s_len, 368 | struct regex_info *info) { 369 | int i, step, depth = 0; 370 | 371 | /* First bracket captures everything */ 372 | info->brackets[0].ptr = re; 373 | info->brackets[0].len = re_len; 374 | info->num_brackets = 1; 375 | 376 | /* Make a single pass over regex string, memorize brackets and branches */ 377 | for (i = 0; i < re_len; i += step) { 378 | step = get_op_len(re + i, re_len - i); 379 | 380 | if (re[i] == '|') { 381 | FAIL_IF(info->num_branches >= (int) ARRAY_SIZE(info->branches), 382 | SLRE_TOO_MANY_BRANCHES); 383 | info->branches[info->num_branches].bracket_index = 384 | info->brackets[info->num_brackets - 1].len == -1 ? 385 | info->num_brackets - 1 : depth; 386 | info->branches[info->num_branches].schlong = &re[i]; 387 | info->num_branches++; 388 | } else if (re[i] == '\\') { 389 | FAIL_IF(i >= re_len - 1, SLRE_INVALID_METACHARACTER); 390 | if (re[i + 1] == 'x') { 391 | /* Hex digit specification must follow */ 392 | FAIL_IF(re[i + 1] == 'x' && i >= re_len - 3, 393 | SLRE_INVALID_METACHARACTER); 394 | FAIL_IF(re[i + 1] == 'x' && !(isxdigit(re[i + 2]) && 395 | isxdigit(re[i + 3])), SLRE_INVALID_METACHARACTER); 396 | } else { 397 | FAIL_IF(!is_metacharacter((const unsigned char *) re + i + 1), 398 | SLRE_INVALID_METACHARACTER); 399 | } 400 | } else if (re[i] == '(') { 401 | FAIL_IF(info->num_brackets >= (int) ARRAY_SIZE(info->brackets), 402 | SLRE_TOO_MANY_BRACKETS); 403 | depth++; /* Order is important here. Depth increments first. */ 404 | info->brackets[info->num_brackets].ptr = re + i + 1; 405 | info->brackets[info->num_brackets].len = -1; 406 | info->num_brackets++; 407 | FAIL_IF(info->num_caps > 0 && info->num_brackets - 1 > info->num_caps, 408 | SLRE_CAPS_ARRAY_TOO_SMALL); 409 | } else if (re[i] == ')') { 410 | int ind = info->brackets[info->num_brackets - 1].len == -1 ? 411 | info->num_brackets - 1 : depth; 412 | info->brackets[ind].len = (int) (&re[i] - info->brackets[ind].ptr); 413 | SLRE_DBG(("SETTING BRACKET %d [%.*s]\n", 414 | ind, info->brackets[ind].len, info->brackets[ind].ptr)); 415 | depth--; 416 | FAIL_IF(depth < 0, SLRE_UNBALANCED_BRACKETS); 417 | FAIL_IF(i > 0 && re[i - 1] == '(', SLRE_NO_MATCH); 418 | } 419 | } 420 | 421 | FAIL_IF(depth != 0, SLRE_UNBALANCED_BRACKETS); 422 | setup_branch_points(info); 423 | 424 | return baz(s, s_len, info); 425 | } 426 | 427 | int slre_match(const char *regexp, const char *s, int s_len, 428 | struct slre_cap *caps, int num_caps, int flags) { 429 | struct regex_info info; 430 | 431 | /* Initialize info structure */ 432 | info.flags = flags; 433 | info.num_brackets = info.num_branches = 0; 434 | info.num_caps = num_caps; 435 | info.caps = caps; 436 | 437 | SLRE_DBG(("========================> [%s] [%.*s]\n", regexp, s_len, s)); 438 | return foo(regexp, (int) strlen(regexp), s, s_len, &info); 439 | } 440 | -------------------------------------------------------------------------------- /netmonsys/slre.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2013 Sergey Lyubka 3 | * Copyright (c) 2013 Cesanta Software Limited 4 | * All rights reserved 5 | * 6 | * This library is dual-licensed: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 as 8 | * published by the Free Software Foundation. For the terms of this 9 | * license, see . 10 | * 11 | * You are free to use this library under the terms of the GNU General 12 | * Public License, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the GNU General Public License for more details. 15 | * 16 | * Alternatively, you can license this library under a commercial 17 | * license, as set out in . 18 | */ 19 | 20 | /* 21 | * This is a regular expression library that implements a subset of Perl RE. 22 | * Please refer to README.md for a detailed reference. 23 | */ 24 | 25 | #ifndef CS_SLRE_SLRE_H_ 26 | #define CS_SLRE_SLRE_H_ 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | struct slre_cap { 33 | const char *ptr; 34 | int len; 35 | }; 36 | 37 | 38 | int slre_match(const char *regexp, const char *buf, int buf_len, 39 | struct slre_cap *caps, int num_caps, int flags); 40 | 41 | /* Possible flags for slre_match() */ 42 | enum { SLRE_IGNORE_CASE = 1 }; 43 | 44 | 45 | /* slre_match() failure codes */ 46 | #define SLRE_NO_MATCH -1 47 | #define SLRE_UNEXPECTED_QUANTIFIER -2 48 | #define SLRE_UNBALANCED_BRACKETS -3 49 | #define SLRE_INTERNAL_ERROR -4 50 | #define SLRE_INVALID_CHARACTER_SET -5 51 | #define SLRE_INVALID_METACHARACTER -6 52 | #define SLRE_CAPS_ARRAY_TOO_SMALL -7 53 | #define SLRE_TOO_MANY_BRANCHES -8 54 | #define SLRE_TOO_MANY_BRACKETS -9 55 | 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | 60 | #endif /* CS_SLRE_SLRE_H_ */ 61 | -------------------------------------------------------------------------------- /netmonsys/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define NDIS60 1 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | -------------------------------------------------------------------------------- /工程说明.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZhanLang/netmonsys/0cb57dc3c9ed8381d2158630d06cd28b99516549/工程说明.txt --------------------------------------------------------------------------------