mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	Replace GPL licensed C/C++ samples
This commit is contained in:
		
							
								
								
									
										1178
									
								
								samples/C++/PackageInfoParser.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1178
									
								
								samples/C++/PackageInfoParser.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										123
									
								
								samples/C++/crypter.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								samples/C++/crypter.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | |||||||
|  | // Copyright (c) 2009-2012 The Bitcoin Developers | ||||||
|  | // Distributed under the MIT/X11 software license, see the accompanying | ||||||
|  | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||||
|  |  | ||||||
|  | // Source - https://github.com/Bradfrogger/Marvelous/blob/master/src/crypter.cpp | ||||||
|  |  | ||||||
|  | #include <openssl/aes.h> | ||||||
|  | #include <openssl/evp.h> | ||||||
|  | #include <vector> | ||||||
|  | #include <string> | ||||||
|  | #ifdef WIN32 | ||||||
|  | #include <windows.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "crypter.h" | ||||||
|  |  | ||||||
|  | bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod) | ||||||
|  | { | ||||||
|  |     if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE) | ||||||
|  |         return false; | ||||||
|  |  | ||||||
|  |     int i = 0; | ||||||
|  |     if (nDerivationMethod == 0) | ||||||
|  |         i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0], | ||||||
|  |                           (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV); | ||||||
|  |  | ||||||
|  |     if (i != (int)WALLET_CRYPTO_KEY_SIZE) | ||||||
|  |     { | ||||||
|  |         OPENSSL_cleanse(chKey, sizeof(chKey)); | ||||||
|  |         OPENSSL_cleanse(chIV, sizeof(chIV)); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fKeySet = true; | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV) | ||||||
|  | { | ||||||
|  |     if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE) | ||||||
|  |         return false; | ||||||
|  |  | ||||||
|  |     memcpy(&chKey[0], &chNewKey[0], sizeof chKey); | ||||||
|  |     memcpy(&chIV[0], &chNewIV[0], sizeof chIV); | ||||||
|  |  | ||||||
|  |     fKeySet = true; | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) | ||||||
|  | { | ||||||
|  |     if (!fKeySet) | ||||||
|  |         return false; | ||||||
|  |  | ||||||
|  |     // max ciphertext len for a n bytes of plaintext is | ||||||
|  |     // n + AES_BLOCK_SIZE - 1 bytes | ||||||
|  |     int nLen = vchPlaintext.size(); | ||||||
|  |     int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0; | ||||||
|  |     vchCiphertext = std::vector<unsigned char> (nCLen); | ||||||
|  |  | ||||||
|  |     EVP_CIPHER_CTX ctx; | ||||||
|  |  | ||||||
|  |     bool fOk = true; | ||||||
|  |  | ||||||
|  |     EVP_CIPHER_CTX_init(&ctx); | ||||||
|  |     if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV); | ||||||
|  |     if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen); | ||||||
|  |     if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0])+nCLen, &nFLen); | ||||||
|  |     EVP_CIPHER_CTX_cleanup(&ctx); | ||||||
|  |  | ||||||
|  |     if (!fOk) return false; | ||||||
|  |  | ||||||
|  |     vchCiphertext.resize(nCLen + nFLen); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) | ||||||
|  | { | ||||||
|  |     if (!fKeySet) | ||||||
|  |         return false; | ||||||
|  |  | ||||||
|  |     // plaintext will always be equal to or lesser than length of ciphertext | ||||||
|  |     int nLen = vchCiphertext.size(); | ||||||
|  |     int nPLen = nLen, nFLen = 0; | ||||||
|  |  | ||||||
|  |     vchPlaintext = CKeyingMaterial(nPLen); | ||||||
|  |  | ||||||
|  |     EVP_CIPHER_CTX ctx; | ||||||
|  |  | ||||||
|  |     bool fOk = true; | ||||||
|  |  | ||||||
|  |     EVP_CIPHER_CTX_init(&ctx); | ||||||
|  |     if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV); | ||||||
|  |     if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen); | ||||||
|  |     if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0])+nPLen, &nFLen); | ||||||
|  |     EVP_CIPHER_CTX_cleanup(&ctx); | ||||||
|  |  | ||||||
|  |     if (!fOk) return false; | ||||||
|  |  | ||||||
|  |     vchPlaintext.resize(nPLen + nFLen); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext) | ||||||
|  | { | ||||||
|  |     CCrypter cKeyCrypter; | ||||||
|  |     std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE); | ||||||
|  |     memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE); | ||||||
|  |     if(!cKeyCrypter.SetKey(vMasterKey, chIV)) | ||||||
|  |         return false; | ||||||
|  |     return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext) | ||||||
|  | { | ||||||
|  |     CCrypter cKeyCrypter; | ||||||
|  |     std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE); | ||||||
|  |     memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE); | ||||||
|  |     if(!cKeyCrypter.SetKey(vMasterKey, chIV)) | ||||||
|  |         return false; | ||||||
|  |     return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext)); | ||||||
|  | } | ||||||
							
								
								
									
										109
									
								
								samples/C++/graphics.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								samples/C++/graphics.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | |||||||
|  | // License - https://github.com/TurtleP/Flask/blob/master/LICENSE | ||||||
|  |  | ||||||
|  | #include <shared.h> | ||||||
|  |  | ||||||
|  | int currentR = 0xFF; | ||||||
|  | int currentG = 0xFF; | ||||||
|  | int currentB = 0xFF; | ||||||
|  | int currentA = 0xFF; | ||||||
|  |  | ||||||
|  | int currentScreen = GFX_BOTTOM; | ||||||
|  |  | ||||||
|  | float transX = 0; | ||||||
|  | float transY = 0; | ||||||
|  | bool isPushed = false; | ||||||
|  |  | ||||||
|  | u32 getCurrentColor()  | ||||||
|  | { | ||||||
|  | 	return RGBA8(currentR, currentG, currentB, currentA); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void setColor(int r, int g, int b) | ||||||
|  | { | ||||||
|  | 	currentR = r; | ||||||
|  | 	currentG = g; | ||||||
|  | 	currentB = b; | ||||||
|  | 	currentA = currentA; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void setColor(int r, int g, int b, int a) | ||||||
|  | { | ||||||
|  | 	currentR = r; | ||||||
|  | 	currentG = g; | ||||||
|  | 	currentB = b; | ||||||
|  | 	currentA = a; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void setScreen(int screen) | ||||||
|  | { | ||||||
|  | 	currentScreen = screen; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int getCurrentScreen() | ||||||
|  | { | ||||||
|  | 	return currentScreen; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void screenShot() //for showing stuff being done | ||||||
|  | { | ||||||
|  | 	FILE * topScreen = fopen("sdmc:/framebuffer_top.rgb", "w+"); | ||||||
|  |  | ||||||
|  | 	fwrite(gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 288000, 1, topScreen); | ||||||
|  |  | ||||||
|  | 	fclose(topScreen); | ||||||
|  |  | ||||||
|  | 	FILE * bottomScreen = fopen("sdmc:/framebuffer_bottom.rgb", "w+");; | ||||||
|  |  | ||||||
|  | 	fwrite(gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), 230400, 1, bottomScreen); | ||||||
|  |  | ||||||
|  | 	fclose(bottomScreen); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void translateCoords(float * x, float * y) { | ||||||
|  | 	if (isPushed)  | ||||||
|  | 	{ | ||||||
|  | 		*x += transX; | ||||||
|  | 		*y += transY; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void translate(float dx, float dy) | ||||||
|  | { | ||||||
|  | 	if (sf2d_get_current_screen() == getCurrentScreen())  | ||||||
|  | 	{ | ||||||
|  | 		transX = transX + dx; | ||||||
|  | 		transY = transY + dy; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void push() | ||||||
|  | { | ||||||
|  | 	if (sf2d_get_current_screen() == getCurrentScreen())  | ||||||
|  | 	{ | ||||||
|  | 		isPushed = true; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void pop() | ||||||
|  | { | ||||||
|  | 	if (sf2d_get_current_screen() == getCurrentScreen())  | ||||||
|  | 	{ | ||||||
|  | 		transX = 0; | ||||||
|  | 		transY = 0; | ||||||
|  | 		isPushed = false; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void setScissor(u32 x, u32 y, u32 width, u32 height) | ||||||
|  | { | ||||||
|  | 	if (sf2d_get_current_screen() == getCurrentScreen())  | ||||||
|  | 	{ | ||||||
|  | 		GPU_SCISSORMODE mode = GPU_SCISSOR_NORMAL; | ||||||
|  |  | ||||||
|  | 		if (!x && !y && !width && !height) { | ||||||
|  | 			mode = GPU_SCISSOR_DISABLE; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		sf2d_set_scissor_test(mode, x, y, width, height); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										920
									
								
								samples/C++/json_reader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										920
									
								
								samples/C++/json_reader.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,920 @@ | |||||||
|  | // Copyright 2007-2010 Baptiste Lepilleur | ||||||
|  | // Distributed under MIT license, or public domain if desired and | ||||||
|  | // recognized in your jurisdiction. | ||||||
|  | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining | ||||||
|  | a copy of this software and associated documentation files (the | ||||||
|  | "Software"), to deal in the Software without restriction, including | ||||||
|  | without limitation the rights to use, copy, modify, merge, publish, | ||||||
|  | distribute, sublicense, and/or sell copies of the Software, and to | ||||||
|  | permit persons to whom the Software is furnished to do so, subject to | ||||||
|  | the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be | ||||||
|  | included in all copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||||
|  | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||||
|  | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||||
|  | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||||||
|  | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||||||
|  | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||||||
|  | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | // Source - https://github.com/Ij888/ApacheCordovaRecipes/blob/6e8a2c1d9de7302f74bc3dbac54a021f0499bbb3/jqmsandbox/plugins/cordova-plugin-globalization/src/blackberry10/native/public/json_reader.cpp | ||||||
|  |  | ||||||
|  | #include <json/reader.h> | ||||||
|  | #include <json/value.h> | ||||||
|  | #include <utility> | ||||||
|  | #include <cstdio> | ||||||
|  | #include <cassert> | ||||||
|  | #include <cstring> | ||||||
|  | #include <iostream> | ||||||
|  | #include <stdexcept> | ||||||
|  |  | ||||||
|  | #if _MSC_VER >= 1400 // VC++ 8.0 | ||||||
|  | #pragma warning( disable : 4996 )   // disable warning about strdup being deprecated. | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | namespace Json { | ||||||
|  |  | ||||||
|  | // QNX is strict about declaring C symbols in the std namespace. | ||||||
|  | #ifdef __QNXNTO__ | ||||||
|  | using std::memcpy; | ||||||
|  | using std::sprintf; | ||||||
|  | using std::sscanf; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | // Implementation of class Features | ||||||
|  | // //////////////////////////////// | ||||||
|  |  | ||||||
|  | Features::Features() | ||||||
|  |    : allowComments_( true ) | ||||||
|  |    , strictRoot_( false ) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Features  | ||||||
|  | Features::all() | ||||||
|  | { | ||||||
|  |    return Features(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Features  | ||||||
|  | Features::strictMode() | ||||||
|  | { | ||||||
|  |    Features features; | ||||||
|  |    features.allowComments_ = false; | ||||||
|  |    features.strictRoot_ = true; | ||||||
|  |    return features; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Implementation of class Reader | ||||||
|  | // //////////////////////////////// | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static inline bool  | ||||||
|  | in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) | ||||||
|  | { | ||||||
|  |    return c == c1  ||  c == c2  ||  c == c3  ||  c == c4; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static inline bool  | ||||||
|  | in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) | ||||||
|  | { | ||||||
|  |    return c == c1  ||  c == c2  ||  c == c3  ||  c == c4  ||  c == c5; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static bool  | ||||||
|  | containsNewLine( Reader::Location begin,  | ||||||
|  |                  Reader::Location end ) | ||||||
|  | { | ||||||
|  |    for ( ;begin < end; ++begin ) | ||||||
|  |       if ( *begin == '\n'  ||  *begin == '\r' ) | ||||||
|  |          return true; | ||||||
|  |    return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static std::string codePointToUTF8(unsigned int cp) | ||||||
|  | { | ||||||
|  |    std::string result; | ||||||
|  |     | ||||||
|  |    // based on description from http://en.wikipedia.org/wiki/UTF-8 | ||||||
|  |  | ||||||
|  |    if (cp <= 0x7f)  | ||||||
|  |    { | ||||||
|  |       result.resize(1); | ||||||
|  |       result[0] = static_cast<char>(cp); | ||||||
|  |    }  | ||||||
|  |    else if (cp <= 0x7FF)  | ||||||
|  |    { | ||||||
|  |       result.resize(2); | ||||||
|  |       result[1] = static_cast<char>(0x80 | (0x3f & cp)); | ||||||
|  |       result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6))); | ||||||
|  |    }  | ||||||
|  |    else if (cp <= 0xFFFF)  | ||||||
|  |    { | ||||||
|  |       result.resize(3); | ||||||
|  |       result[2] = static_cast<char>(0x80 | (0x3f & cp)); | ||||||
|  |       result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6))); | ||||||
|  |       result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12))); | ||||||
|  |    } | ||||||
|  |    else if (cp <= 0x10FFFF)  | ||||||
|  |    { | ||||||
|  |       result.resize(4); | ||||||
|  |       result[3] = static_cast<char>(0x80 | (0x3f & cp)); | ||||||
|  |       result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); | ||||||
|  |       result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12))); | ||||||
|  |       result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18))); | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Class Reader | ||||||
|  | // ////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | Reader::Reader() | ||||||
|  |    : features_( Features::all() ) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Reader::Reader( const Features &features ) | ||||||
|  |    : features_( features ) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | Reader::parse( const std::string &document,  | ||||||
|  |                Value &root, | ||||||
|  |                bool collectComments ) | ||||||
|  | { | ||||||
|  |    document_ = document; | ||||||
|  |    const char *begin = document_.c_str(); | ||||||
|  |    const char *end = begin + document_.length(); | ||||||
|  |    return parse( begin, end, root, collectComments ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | Reader::parse( std::istream& sin, | ||||||
|  |                Value &root, | ||||||
|  |                bool collectComments ) | ||||||
|  | { | ||||||
|  |    //std::istream_iterator<char> begin(sin); | ||||||
|  |    //std::istream_iterator<char> end; | ||||||
|  |    // Those would allow streamed input from a file, if parse() were a | ||||||
|  |    // template function. | ||||||
|  |  | ||||||
|  |    // Since std::string is reference-counted, this at least does not | ||||||
|  |    // create an extra copy. | ||||||
|  |    std::string doc; | ||||||
|  |    std::getline(sin, doc, (char)EOF); | ||||||
|  |    return parse( doc, root, collectComments ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::parse( const char *beginDoc, const char *endDoc,  | ||||||
|  |                Value &root, | ||||||
|  |                bool collectComments ) | ||||||
|  | { | ||||||
|  |    if ( !features_.allowComments_ ) | ||||||
|  |    { | ||||||
|  |       collectComments = false; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    begin_ = beginDoc; | ||||||
|  |    end_ = endDoc; | ||||||
|  |    collectComments_ = collectComments; | ||||||
|  |    current_ = begin_; | ||||||
|  |    lastValueEnd_ = 0; | ||||||
|  |    lastValue_ = 0; | ||||||
|  |    commentsBefore_ = ""; | ||||||
|  |    errors_.clear(); | ||||||
|  |    while ( !nodes_.empty() ) | ||||||
|  |       nodes_.pop(); | ||||||
|  |    nodes_.push( &root ); | ||||||
|  |     | ||||||
|  |    bool successful = readValue(); | ||||||
|  |    Token token; | ||||||
|  |    skipCommentTokens( token ); | ||||||
|  |    if ( collectComments_  &&  !commentsBefore_.empty() ) | ||||||
|  |       root.setComment( commentsBefore_, commentAfter ); | ||||||
|  |    if ( features_.strictRoot_ ) | ||||||
|  |    { | ||||||
|  |       if ( !root.isArray()  &&  !root.isObject() ) | ||||||
|  |       { | ||||||
|  |          // Set error location to start of doc, ideally should be first token found in doc | ||||||
|  |          token.type_ = tokenError; | ||||||
|  |          token.start_ = beginDoc; | ||||||
|  |          token.end_ = endDoc; | ||||||
|  |          addError( "A valid JSON document must be either an array or an object value.", | ||||||
|  |                    token ); | ||||||
|  |          return false; | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  |    return successful; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | Reader::readValue() | ||||||
|  | { | ||||||
|  |    Token token; | ||||||
|  |    skipCommentTokens( token ); | ||||||
|  |    bool successful = true; | ||||||
|  |  | ||||||
|  |    if ( collectComments_  &&  !commentsBefore_.empty() ) | ||||||
|  |    { | ||||||
|  |       currentValue().setComment( commentsBefore_, commentBefore ); | ||||||
|  |       commentsBefore_ = ""; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |    switch ( token.type_ ) | ||||||
|  |    { | ||||||
|  |    case tokenObjectBegin: | ||||||
|  |       successful = readObject( token ); | ||||||
|  |       break; | ||||||
|  |    case tokenArrayBegin: | ||||||
|  |       successful = readArray( token ); | ||||||
|  |       break; | ||||||
|  |    case tokenNumber: | ||||||
|  |       successful = decodeNumber( token ); | ||||||
|  |       break; | ||||||
|  |    case tokenString: | ||||||
|  |       successful = decodeString( token ); | ||||||
|  |       break; | ||||||
|  |    case tokenTrue: | ||||||
|  |       currentValue() = true; | ||||||
|  |       break; | ||||||
|  |    case tokenFalse: | ||||||
|  |       currentValue() = false; | ||||||
|  |       break; | ||||||
|  |    case tokenNull: | ||||||
|  |       currentValue() = Value(); | ||||||
|  |       break; | ||||||
|  |    default: | ||||||
|  |       return addError( "Syntax error: value, object or array expected.", token ); | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    if ( collectComments_ ) | ||||||
|  |    { | ||||||
|  |       lastValueEnd_ = current_; | ||||||
|  |       lastValue_ = ¤tValue(); | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    return successful; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | Reader::skipCommentTokens( Token &token ) | ||||||
|  | { | ||||||
|  |    if ( features_.allowComments_ ) | ||||||
|  |    { | ||||||
|  |       do | ||||||
|  |       { | ||||||
|  |          readToken( token ); | ||||||
|  |       } | ||||||
|  |       while ( token.type_ == tokenComment ); | ||||||
|  |    } | ||||||
|  |    else | ||||||
|  |    { | ||||||
|  |       readToken( token ); | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::expectToken( TokenType type, Token &token, const char *message ) | ||||||
|  | { | ||||||
|  |    readToken( token ); | ||||||
|  |    if ( token.type_ != type ) | ||||||
|  |       return addError( message, token ); | ||||||
|  |    return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::readToken( Token &token ) | ||||||
|  | { | ||||||
|  |    skipSpaces(); | ||||||
|  |    token.start_ = current_; | ||||||
|  |    Char c = getNextChar(); | ||||||
|  |    bool ok = true; | ||||||
|  |    switch ( c ) | ||||||
|  |    { | ||||||
|  |    case '{': | ||||||
|  |       token.type_ = tokenObjectBegin; | ||||||
|  |       break; | ||||||
|  |    case '}': | ||||||
|  |       token.type_ = tokenObjectEnd; | ||||||
|  |       break; | ||||||
|  |    case '[': | ||||||
|  |       token.type_ = tokenArrayBegin; | ||||||
|  |       break; | ||||||
|  |    case ']': | ||||||
|  |       token.type_ = tokenArrayEnd; | ||||||
|  |       break; | ||||||
|  |    case '"': | ||||||
|  |       token.type_ = tokenString; | ||||||
|  |       ok = readString(); | ||||||
|  |       break; | ||||||
|  |    case '/': | ||||||
|  |       token.type_ = tokenComment; | ||||||
|  |       ok = readComment(); | ||||||
|  |       break; | ||||||
|  |    case '0': | ||||||
|  |    case '1': | ||||||
|  |    case '2': | ||||||
|  |    case '3': | ||||||
|  |    case '4': | ||||||
|  |    case '5': | ||||||
|  |    case '6': | ||||||
|  |    case '7': | ||||||
|  |    case '8': | ||||||
|  |    case '9': | ||||||
|  |    case '-': | ||||||
|  |       token.type_ = tokenNumber; | ||||||
|  |       readNumber(); | ||||||
|  |       break; | ||||||
|  |    case 't': | ||||||
|  |       token.type_ = tokenTrue; | ||||||
|  |       ok = match( "rue", 3 ); | ||||||
|  |       break; | ||||||
|  |    case 'f': | ||||||
|  |       token.type_ = tokenFalse; | ||||||
|  |       ok = match( "alse", 4 ); | ||||||
|  |       break; | ||||||
|  |    case 'n': | ||||||
|  |       token.type_ = tokenNull; | ||||||
|  |       ok = match( "ull", 3 ); | ||||||
|  |       break; | ||||||
|  |    case ',': | ||||||
|  |       token.type_ = tokenArraySeparator; | ||||||
|  |       break; | ||||||
|  |    case ':': | ||||||
|  |       token.type_ = tokenMemberSeparator; | ||||||
|  |       break; | ||||||
|  |    case 0: | ||||||
|  |       token.type_ = tokenEndOfStream; | ||||||
|  |       break; | ||||||
|  |    default: | ||||||
|  |       ok = false; | ||||||
|  |       break; | ||||||
|  |    } | ||||||
|  |    if ( !ok ) | ||||||
|  |       token.type_ = tokenError; | ||||||
|  |    token.end_ = current_; | ||||||
|  |    return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | Reader::skipSpaces() | ||||||
|  | { | ||||||
|  |    while ( current_ != end_ ) | ||||||
|  |    { | ||||||
|  |       Char c = *current_; | ||||||
|  |       if ( c == ' '  ||  c == '\t'  ||  c == '\r'  ||  c == '\n' ) | ||||||
|  |          ++current_; | ||||||
|  |       else | ||||||
|  |          break; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::match( Location pattern,  | ||||||
|  |                int patternLength ) | ||||||
|  | { | ||||||
|  |    if ( end_ - current_ < patternLength ) | ||||||
|  |       return false; | ||||||
|  |    int index = patternLength; | ||||||
|  |    while ( index-- ) | ||||||
|  |       if ( current_[index] != pattern[index] ) | ||||||
|  |          return false; | ||||||
|  |    current_ += patternLength; | ||||||
|  |    return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | Reader::readComment() | ||||||
|  | { | ||||||
|  |    Location commentBegin = current_ - 1; | ||||||
|  |    Char c = getNextChar(); | ||||||
|  |    bool successful = false; | ||||||
|  |    if ( c == '*' ) | ||||||
|  |       successful = readCStyleComment(); | ||||||
|  |    else if ( c == '/' ) | ||||||
|  |       successful = readCppStyleComment(); | ||||||
|  |    if ( !successful ) | ||||||
|  |       return false; | ||||||
|  |  | ||||||
|  |    if ( collectComments_ ) | ||||||
|  |    { | ||||||
|  |       CommentPlacement placement = commentBefore; | ||||||
|  |       if ( lastValueEnd_  &&  !containsNewLine( lastValueEnd_, commentBegin ) ) | ||||||
|  |       { | ||||||
|  |          if ( c != '*'  ||  !containsNewLine( commentBegin, current_ ) ) | ||||||
|  |             placement = commentAfterOnSameLine; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       addComment( commentBegin, current_, placement ); | ||||||
|  |    } | ||||||
|  |    return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | Reader::addComment( Location begin,  | ||||||
|  |                     Location end,  | ||||||
|  |                     CommentPlacement placement ) | ||||||
|  | { | ||||||
|  |    assert( collectComments_ ); | ||||||
|  |    if ( placement == commentAfterOnSameLine ) | ||||||
|  |    { | ||||||
|  |       assert( lastValue_ != 0 ); | ||||||
|  |       lastValue_->setComment( std::string( begin, end ), placement ); | ||||||
|  |    } | ||||||
|  |    else | ||||||
|  |    { | ||||||
|  |       if ( !commentsBefore_.empty() ) | ||||||
|  |          commentsBefore_ += "\n"; | ||||||
|  |       commentsBefore_ += std::string( begin, end ); | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::readCStyleComment() | ||||||
|  | { | ||||||
|  |    while ( current_ != end_ ) | ||||||
|  |    { | ||||||
|  |       Char c = getNextChar(); | ||||||
|  |       if ( c == '*'  &&  *current_ == '/' ) | ||||||
|  |          break; | ||||||
|  |    } | ||||||
|  |    return getNextChar() == '/'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::readCppStyleComment() | ||||||
|  | { | ||||||
|  |    while ( current_ != end_ ) | ||||||
|  |    { | ||||||
|  |       Char c = getNextChar(); | ||||||
|  |       if (  c == '\r'  ||  c == '\n' ) | ||||||
|  |          break; | ||||||
|  |    } | ||||||
|  |    return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | Reader::readNumber() | ||||||
|  | { | ||||||
|  |    while ( current_ != end_ ) | ||||||
|  |    { | ||||||
|  |       if ( !(*current_ >= '0'  &&  *current_ <= '9')  && | ||||||
|  |            !in( *current_, '.', 'e', 'E', '+', '-' ) ) | ||||||
|  |          break; | ||||||
|  |       ++current_; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | Reader::readString() | ||||||
|  | { | ||||||
|  |    Char c = 0; | ||||||
|  |    while ( current_ != end_ ) | ||||||
|  |    { | ||||||
|  |       c = getNextChar(); | ||||||
|  |       if ( c == '\\' ) | ||||||
|  |          getNextChar(); | ||||||
|  |       else if ( c == '"' ) | ||||||
|  |          break; | ||||||
|  |    } | ||||||
|  |    return c == '"'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::readObject( Token &tokenStart ) | ||||||
|  | { | ||||||
|  |    Token tokenName; | ||||||
|  |    std::string name; | ||||||
|  |    currentValue() = Value( objectValue ); | ||||||
|  |    while ( readToken( tokenName ) ) | ||||||
|  |    { | ||||||
|  |       bool initialTokenOk = true; | ||||||
|  |       while ( tokenName.type_ == tokenComment  &&  initialTokenOk ) | ||||||
|  |          initialTokenOk = readToken( tokenName ); | ||||||
|  |       if  ( !initialTokenOk ) | ||||||
|  |          break; | ||||||
|  |       if ( tokenName.type_ == tokenObjectEnd  &&  name.empty() )  // empty object | ||||||
|  |          return true; | ||||||
|  |       if ( tokenName.type_ != tokenString ) | ||||||
|  |          break; | ||||||
|  |        | ||||||
|  |       name = ""; | ||||||
|  |       if ( !decodeString( tokenName, name ) ) | ||||||
|  |          return recoverFromError( tokenObjectEnd ); | ||||||
|  |  | ||||||
|  |       Token colon; | ||||||
|  |       if ( !readToken( colon ) ||  colon.type_ != tokenMemberSeparator ) | ||||||
|  |       { | ||||||
|  |          return addErrorAndRecover( "Missing ':' after object member name",  | ||||||
|  |                                     colon,  | ||||||
|  |                                     tokenObjectEnd ); | ||||||
|  |       } | ||||||
|  |       Value &value = currentValue()[ name ]; | ||||||
|  |       nodes_.push( &value ); | ||||||
|  |       bool ok = readValue(); | ||||||
|  |       nodes_.pop(); | ||||||
|  |       if ( !ok ) // error already set | ||||||
|  |          return recoverFromError( tokenObjectEnd ); | ||||||
|  |  | ||||||
|  |       Token comma; | ||||||
|  |       if ( !readToken( comma ) | ||||||
|  |             ||  ( comma.type_ != tokenObjectEnd  &&   | ||||||
|  |                   comma.type_ != tokenArraySeparator && | ||||||
|  | 		  comma.type_ != tokenComment ) ) | ||||||
|  |       { | ||||||
|  |          return addErrorAndRecover( "Missing ',' or '}' in object declaration",  | ||||||
|  |                                     comma,  | ||||||
|  |                                     tokenObjectEnd ); | ||||||
|  |       } | ||||||
|  |       bool finalizeTokenOk = true; | ||||||
|  |       while ( comma.type_ == tokenComment && | ||||||
|  |               finalizeTokenOk ) | ||||||
|  |          finalizeTokenOk = readToken( comma ); | ||||||
|  |       if ( comma.type_ == tokenObjectEnd ) | ||||||
|  |          return true; | ||||||
|  |    } | ||||||
|  |    return addErrorAndRecover( "Missing '}' or object member name",  | ||||||
|  |                               tokenName,  | ||||||
|  |                               tokenObjectEnd ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::readArray( Token &tokenStart ) | ||||||
|  | { | ||||||
|  |    currentValue() = Value( arrayValue ); | ||||||
|  |    skipSpaces(); | ||||||
|  |    if ( *current_ == ']' ) // empty array | ||||||
|  |    { | ||||||
|  |       Token endArray; | ||||||
|  |       readToken( endArray ); | ||||||
|  |       return true; | ||||||
|  |    } | ||||||
|  |    int index = 0; | ||||||
|  |    while ( true ) | ||||||
|  |    { | ||||||
|  |       Value &value = currentValue()[ index++ ]; | ||||||
|  |       nodes_.push( &value ); | ||||||
|  |       bool ok = readValue(); | ||||||
|  |       nodes_.pop(); | ||||||
|  |       if ( !ok ) // error already set | ||||||
|  |          return recoverFromError( tokenArrayEnd ); | ||||||
|  |  | ||||||
|  |       Token token; | ||||||
|  |       // Accept Comment after last item in the array. | ||||||
|  |       ok = readToken( token ); | ||||||
|  |       while ( token.type_ == tokenComment  &&  ok ) | ||||||
|  |       { | ||||||
|  |          ok = readToken( token ); | ||||||
|  |       } | ||||||
|  |       bool badTokenType = ( token.type_ == tokenArraySeparator  &&   | ||||||
|  |                             token.type_ == tokenArrayEnd ); | ||||||
|  |       if ( !ok  ||  badTokenType ) | ||||||
|  |       { | ||||||
|  |          return addErrorAndRecover( "Missing ',' or ']' in array declaration",  | ||||||
|  |                                     token,  | ||||||
|  |                                     tokenArrayEnd ); | ||||||
|  |       } | ||||||
|  |       if ( token.type_ == tokenArrayEnd ) | ||||||
|  |          break; | ||||||
|  |    } | ||||||
|  |    return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::decodeNumber( Token &token ) | ||||||
|  | { | ||||||
|  |    bool isDouble = false; | ||||||
|  |    for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) | ||||||
|  |    { | ||||||
|  |       isDouble = isDouble   | ||||||
|  |                  ||  in( *inspect, '.', 'e', 'E', '+' )   | ||||||
|  |                  ||  ( *inspect == '-'  &&  inspect != token.start_ ); | ||||||
|  |    } | ||||||
|  |    if ( isDouble ) | ||||||
|  |       return decodeDouble( token ); | ||||||
|  |    Location current = token.start_; | ||||||
|  |    bool isNegative = *current == '-'; | ||||||
|  |    if ( isNegative ) | ||||||
|  |       ++current; | ||||||
|  |    Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt)  | ||||||
|  |                                        : Value::maxUInt) / 10; | ||||||
|  |    Value::UInt value = 0; | ||||||
|  |    while ( current < token.end_ ) | ||||||
|  |    { | ||||||
|  |       Char c = *current++; | ||||||
|  |       if ( c < '0'  ||  c > '9' ) | ||||||
|  |          return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); | ||||||
|  |       if ( value >= threshold ) | ||||||
|  |          return decodeDouble( token ); | ||||||
|  |       value = value * 10 + Value::UInt(c - '0'); | ||||||
|  |    } | ||||||
|  |    if ( isNegative ) | ||||||
|  |       currentValue() = -Value::Int( value ); | ||||||
|  |    else if ( value <= Value::UInt(Value::maxInt) ) | ||||||
|  |       currentValue() = Value::Int( value ); | ||||||
|  |    else | ||||||
|  |       currentValue() = value; | ||||||
|  |    return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::decodeDouble( Token &token ) | ||||||
|  | { | ||||||
|  |    double value = 0; | ||||||
|  |    const int bufferSize = 32; | ||||||
|  |    int count; | ||||||
|  |    int length = int(token.end_ - token.start_); | ||||||
|  |    if ( length <= bufferSize ) | ||||||
|  |    { | ||||||
|  |       Char buffer[bufferSize]; | ||||||
|  |       memcpy( buffer, token.start_, length ); | ||||||
|  |       buffer[length] = 0; | ||||||
|  |       count = sscanf( buffer, "%lf", &value ); | ||||||
|  |    } | ||||||
|  |    else | ||||||
|  |    { | ||||||
|  |       std::string buffer( token.start_, token.end_ ); | ||||||
|  |       count = sscanf( buffer.c_str(), "%lf", &value ); | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    if ( count != 1 ) | ||||||
|  |       return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); | ||||||
|  |    currentValue() = value; | ||||||
|  |    return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::decodeString( Token &token ) | ||||||
|  | { | ||||||
|  |    std::string decoded; | ||||||
|  |    if ( !decodeString( token, decoded ) ) | ||||||
|  |       return false; | ||||||
|  |    currentValue() = decoded; | ||||||
|  |    return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::decodeString( Token &token, std::string &decoded ) | ||||||
|  | { | ||||||
|  |    decoded.reserve( token.end_ - token.start_ - 2 ); | ||||||
|  |    Location current = token.start_ + 1; // skip '"' | ||||||
|  |    Location end = token.end_ - 1;      // do not include '"' | ||||||
|  |    while ( current != end ) | ||||||
|  |    { | ||||||
|  |       Char c = *current++; | ||||||
|  |       if ( c == '"' ) | ||||||
|  |          break; | ||||||
|  |       else if ( c == '\\' ) | ||||||
|  |       { | ||||||
|  |          if ( current == end ) | ||||||
|  |             return addError( "Empty escape sequence in string", token, current ); | ||||||
|  |          Char escape = *current++; | ||||||
|  |          switch ( escape ) | ||||||
|  |          { | ||||||
|  |          case '"': decoded += '"'; break; | ||||||
|  |          case '/': decoded += '/'; break; | ||||||
|  |          case '\\': decoded += '\\'; break; | ||||||
|  |          case 'b': decoded += '\b'; break; | ||||||
|  |          case 'f': decoded += '\f'; break; | ||||||
|  |          case 'n': decoded += '\n'; break; | ||||||
|  |          case 'r': decoded += '\r'; break; | ||||||
|  |          case 't': decoded += '\t'; break; | ||||||
|  |          case 'u': | ||||||
|  |             { | ||||||
|  |                unsigned int unicode; | ||||||
|  |                if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) | ||||||
|  |                   return false; | ||||||
|  |                decoded += codePointToUTF8(unicode); | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |          default: | ||||||
|  |             return addError( "Bad escape sequence in string", token, current ); | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |       else | ||||||
|  |       { | ||||||
|  |          decoded += c; | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  |    return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | Reader::decodeUnicodeCodePoint( Token &token,  | ||||||
|  |                                      Location ¤t,  | ||||||
|  |                                      Location end,  | ||||||
|  |                                      unsigned int &unicode ) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |    if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) | ||||||
|  |       return false; | ||||||
|  |    if (unicode >= 0xD800 && unicode <= 0xDBFF) | ||||||
|  |    { | ||||||
|  |       // surrogate pairs | ||||||
|  |       if (end - current < 6) | ||||||
|  |          return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); | ||||||
|  |       unsigned int surrogatePair; | ||||||
|  |       if (*(current++) == '\\' && *(current++)== 'u') | ||||||
|  |       { | ||||||
|  |          if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) | ||||||
|  |          { | ||||||
|  |             unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); | ||||||
|  |          }  | ||||||
|  |          else | ||||||
|  |             return false; | ||||||
|  |       }  | ||||||
|  |       else | ||||||
|  |          return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); | ||||||
|  |    } | ||||||
|  |    return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::decodeUnicodeEscapeSequence( Token &token,  | ||||||
|  |                                      Location ¤t,  | ||||||
|  |                                      Location end,  | ||||||
|  |                                      unsigned int &unicode ) | ||||||
|  | { | ||||||
|  |    if ( end - current < 4 ) | ||||||
|  |       return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); | ||||||
|  |    unicode = 0; | ||||||
|  |    for ( int index =0; index < 4; ++index ) | ||||||
|  |    { | ||||||
|  |       Char c = *current++; | ||||||
|  |       unicode *= 16; | ||||||
|  |       if ( c >= '0'  &&  c <= '9' ) | ||||||
|  |          unicode += c - '0'; | ||||||
|  |       else if ( c >= 'a'  &&  c <= 'f' ) | ||||||
|  |          unicode += c - 'a' + 10; | ||||||
|  |       else if ( c >= 'A'  &&  c <= 'F' ) | ||||||
|  |          unicode += c - 'A' + 10; | ||||||
|  |       else | ||||||
|  |          return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); | ||||||
|  |    } | ||||||
|  |    return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::addError( const std::string &message,  | ||||||
|  |                   Token &token, | ||||||
|  |                   Location extra ) | ||||||
|  | { | ||||||
|  |    ErrorInfo info; | ||||||
|  |    info.token_ = token; | ||||||
|  |    info.message_ = message; | ||||||
|  |    info.extra_ = extra; | ||||||
|  |    errors_.push_back( info ); | ||||||
|  |    return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::recoverFromError( TokenType skipUntilToken ) | ||||||
|  | { | ||||||
|  |    int errorCount = int(errors_.size()); | ||||||
|  |    Token skip; | ||||||
|  |    while ( true ) | ||||||
|  |    { | ||||||
|  |       if ( !readToken(skip) ) | ||||||
|  |          errors_.resize( errorCount ); // discard errors caused by recovery | ||||||
|  |       if ( skip.type_ == skipUntilToken  ||  skip.type_ == tokenEndOfStream ) | ||||||
|  |          break; | ||||||
|  |    } | ||||||
|  |    errors_.resize( errorCount ); | ||||||
|  |    return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | Reader::addErrorAndRecover( const std::string &message,  | ||||||
|  |                             Token &token, | ||||||
|  |                             TokenType skipUntilToken ) | ||||||
|  | { | ||||||
|  |    addError( message, token ); | ||||||
|  |    return recoverFromError( skipUntilToken ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Value & | ||||||
|  | Reader::currentValue() | ||||||
|  | { | ||||||
|  |    return *(nodes_.top()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Reader::Char  | ||||||
|  | Reader::getNextChar() | ||||||
|  | { | ||||||
|  |    if ( current_ == end_ ) | ||||||
|  |       return 0; | ||||||
|  |    return *current_++; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | Reader::getLocationLineAndColumn( Location location, | ||||||
|  |                                   int &line, | ||||||
|  |                                   int &column ) const | ||||||
|  | { | ||||||
|  |    Location current = begin_; | ||||||
|  |    Location lastLineStart = current; | ||||||
|  |    line = 0; | ||||||
|  |    while ( current < location  &&  current != end_ ) | ||||||
|  |    { | ||||||
|  |       Char c = *current++; | ||||||
|  |       if ( c == '\r' ) | ||||||
|  |       { | ||||||
|  |          if ( *current == '\n' ) | ||||||
|  |             ++current; | ||||||
|  |          lastLineStart = current; | ||||||
|  |          ++line; | ||||||
|  |       } | ||||||
|  |       else if ( c == '\n' ) | ||||||
|  |       { | ||||||
|  |          lastLineStart = current; | ||||||
|  |          ++line; | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  |    // column & line start at 1 | ||||||
|  |    column = int(location - lastLineStart) + 1; | ||||||
|  |    ++line; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | std::string | ||||||
|  | Reader::getLocationLineAndColumn( Location location ) const | ||||||
|  | { | ||||||
|  |    int line, column; | ||||||
|  |    getLocationLineAndColumn( location, line, column ); | ||||||
|  |    char buffer[18+16+16+1]; | ||||||
|  |    sprintf( buffer, "Line %d, Column %d", line, column ); | ||||||
|  |    return buffer; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | std::string  | ||||||
|  | Reader::getFormatedErrorMessages() const | ||||||
|  | { | ||||||
|  |    std::string formattedMessage; | ||||||
|  |    for ( Errors::const_iterator itError = errors_.begin(); | ||||||
|  |          itError != errors_.end(); | ||||||
|  |          ++itError ) | ||||||
|  |    { | ||||||
|  |       const ErrorInfo &error = *itError; | ||||||
|  |       formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; | ||||||
|  |       formattedMessage += "  " + error.message_ + "\n"; | ||||||
|  |       if ( error.extra_ ) | ||||||
|  |          formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; | ||||||
|  |    } | ||||||
|  |    return formattedMessage; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | std::istream& operator>>( std::istream &sin, Value &root ) | ||||||
|  | { | ||||||
|  |     Json::Reader reader; | ||||||
|  |     bool ok = reader.parse(sin, root, true); | ||||||
|  |     //JSON_ASSERT( ok ); | ||||||
|  |     if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages()); | ||||||
|  |     return sin; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } // namespace Json | ||||||
							
								
								
									
										857
									
								
								samples/C++/json_writer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										857
									
								
								samples/C++/json_writer.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,857 @@ | |||||||
|  | // Copyright 2007-2010 Baptiste Lepilleur | ||||||
|  | // Distributed under MIT license, or public domain if desired and | ||||||
|  | // recognized in your jurisdiction. | ||||||
|  | // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining | ||||||
|  | a copy of this software and associated documentation files (the | ||||||
|  | "Software"), to deal in the Software without restriction, including | ||||||
|  | without limitation the rights to use, copy, modify, merge, publish, | ||||||
|  | distribute, sublicense, and/or sell copies of the Software, and to | ||||||
|  | permit persons to whom the Software is furnished to do so, subject to | ||||||
|  | the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be | ||||||
|  | included in all copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||||
|  | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||||
|  | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||||
|  | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||||||
|  | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||||||
|  | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||||||
|  | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | // Source - https://github.com/Ij888/ApacheCordovaRecipes/blob/6e8a2c1d9de7302f74bc3dbac54a021f0499bbb3/jqmsandbox/plugins/cordova-plugin-globalization/src/blackberry10/native/public/json_writer.cpp | ||||||
|  |  | ||||||
|  | #include <json/writer.h> | ||||||
|  | #include <utility> | ||||||
|  | #include <assert.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <iostream> | ||||||
|  | #include <sstream> | ||||||
|  | #include <iomanip> | ||||||
|  |  | ||||||
|  | #if _MSC_VER >= 1400 // VC++ 8.0 | ||||||
|  | #pragma warning( disable : 4996 )   // disable warning about strdup being deprecated. | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | namespace Json { | ||||||
|  |  | ||||||
|  | static bool isControlCharacter(char ch) | ||||||
|  | { | ||||||
|  |    return ch > 0 && ch <= 0x1F; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static bool containsControlCharacter( const char* str ) | ||||||
|  | { | ||||||
|  |    while ( *str )  | ||||||
|  |    { | ||||||
|  |       if ( isControlCharacter( *(str++) ) ) | ||||||
|  |          return true; | ||||||
|  |    } | ||||||
|  |    return false; | ||||||
|  | } | ||||||
|  | static void uintToString( unsigned int value,  | ||||||
|  |                           char *¤t ) | ||||||
|  | { | ||||||
|  |    *--current = 0; | ||||||
|  |    do | ||||||
|  |    { | ||||||
|  |       *--current = (value % 10) + '0'; | ||||||
|  |       value /= 10; | ||||||
|  |    } | ||||||
|  |    while ( value != 0 ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string valueToString( Int value ) | ||||||
|  | { | ||||||
|  |    char buffer[32]; | ||||||
|  |    char *current = buffer + sizeof(buffer); | ||||||
|  |    bool isNegative = value < 0; | ||||||
|  |    if ( isNegative ) | ||||||
|  |       value = -value; | ||||||
|  |    uintToString( UInt(value), current ); | ||||||
|  |    if ( isNegative ) | ||||||
|  |       *--current = '-'; | ||||||
|  |    assert( current >= buffer ); | ||||||
|  |    return current; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | std::string valueToString( UInt value ) | ||||||
|  | { | ||||||
|  |    char buffer[32]; | ||||||
|  |    char *current = buffer + sizeof(buffer); | ||||||
|  |    uintToString( value, current ); | ||||||
|  |    assert( current >= buffer ); | ||||||
|  |    return current; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string valueToString( double value ) | ||||||
|  | { | ||||||
|  |    char buffer[32]; | ||||||
|  | #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning.  | ||||||
|  |    sprintf_s(buffer, sizeof(buffer), "%#.16g", value);  | ||||||
|  | #else	 | ||||||
|  |    sprintf(buffer, "%#.16g", value);  | ||||||
|  | #endif | ||||||
|  |    char* ch = buffer + strlen(buffer) - 1; | ||||||
|  |    if (*ch != '0') return buffer; // nothing to truncate, so save time | ||||||
|  |    while(ch > buffer && *ch == '0'){ | ||||||
|  |      --ch; | ||||||
|  |    } | ||||||
|  |    char* last_nonzero = ch; | ||||||
|  |    while(ch >= buffer){ | ||||||
|  |      switch(*ch){ | ||||||
|  |      case '0': | ||||||
|  |      case '1': | ||||||
|  |      case '2': | ||||||
|  |      case '3': | ||||||
|  |      case '4': | ||||||
|  |      case '5': | ||||||
|  |      case '6': | ||||||
|  |      case '7': | ||||||
|  |      case '8': | ||||||
|  |      case '9': | ||||||
|  |        --ch; | ||||||
|  |        continue; | ||||||
|  |      case '.': | ||||||
|  |        // Truncate zeroes to save bytes in output, but keep one. | ||||||
|  |        *(last_nonzero+2) = '\0'; | ||||||
|  |        return buffer; | ||||||
|  |      default: | ||||||
|  |        return buffer; | ||||||
|  |      } | ||||||
|  |    } | ||||||
|  |    return buffer; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | std::string valueToString( bool value ) | ||||||
|  | { | ||||||
|  |    return value ? "true" : "false"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string valueToQuotedString( const char *value ) | ||||||
|  | { | ||||||
|  |    // Not sure how to handle unicode... | ||||||
|  |    if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) | ||||||
|  |       return std::string("\"") + value + "\""; | ||||||
|  |    // We have to walk value and escape any special characters. | ||||||
|  |    // Appending to std::string is not efficient, but this should be rare. | ||||||
|  |    // (Note: forward slashes are *not* rare, but I am not escaping them.) | ||||||
|  |    unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL | ||||||
|  |    std::string result; | ||||||
|  |    result.reserve(maxsize); // to avoid lots of mallocs | ||||||
|  |    result += "\""; | ||||||
|  |    for (const char* c=value; *c != 0; ++c) | ||||||
|  |    { | ||||||
|  |       switch(*c) | ||||||
|  |       { | ||||||
|  |          case '\"': | ||||||
|  |             result += "\\\""; | ||||||
|  |             break; | ||||||
|  |          case '\\': | ||||||
|  |             result += "\\\\"; | ||||||
|  |             break; | ||||||
|  |          case '\b': | ||||||
|  |             result += "\\b"; | ||||||
|  |             break; | ||||||
|  |          case '\f': | ||||||
|  |             result += "\\f"; | ||||||
|  |             break; | ||||||
|  |          case '\n': | ||||||
|  |             result += "\\n"; | ||||||
|  |             break; | ||||||
|  |          case '\r': | ||||||
|  |             result += "\\r"; | ||||||
|  |             break; | ||||||
|  |          case '\t': | ||||||
|  |             result += "\\t"; | ||||||
|  |             break; | ||||||
|  |          //case '/': | ||||||
|  |             // Even though \/ is considered a legal escape in JSON, a bare | ||||||
|  |             // slash is also legal, so I see no reason to escape it. | ||||||
|  |             // (I hope I am not misunderstanding something. | ||||||
|  |             // blep notes: actually escaping \/ may be useful in javascript to avoid </  | ||||||
|  |             // sequence. | ||||||
|  |             // Should add a flag to allow this compatibility mode and prevent this  | ||||||
|  |             // sequence from occurring. | ||||||
|  |          default: | ||||||
|  |             if ( isControlCharacter( *c ) ) | ||||||
|  |             { | ||||||
|  |                std::ostringstream oss; | ||||||
|  |                oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c); | ||||||
|  |                result += oss.str(); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                result += *c; | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  |    result += "\""; | ||||||
|  |    return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Class Writer | ||||||
|  | // ////////////////////////////////////////////////////////////////// | ||||||
|  | Writer::~Writer() | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Class FastWriter | ||||||
|  | // ////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | FastWriter::FastWriter() | ||||||
|  |    : yamlCompatiblityEnabled_( false ) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | FastWriter::enableYAMLCompatibility() | ||||||
|  | { | ||||||
|  |    yamlCompatiblityEnabled_ = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | std::string  | ||||||
|  | FastWriter::write( const Value &root ) | ||||||
|  | { | ||||||
|  |    document_ = ""; | ||||||
|  |    writeValue( root ); | ||||||
|  |    document_ += "\n"; | ||||||
|  |    return document_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | FastWriter::writeValue( const Value &value ) | ||||||
|  | { | ||||||
|  |    switch ( value.type() ) | ||||||
|  |    { | ||||||
|  |    case nullValue: | ||||||
|  |       document_ += "null"; | ||||||
|  |       break; | ||||||
|  |    case intValue: | ||||||
|  |       document_ += valueToString( value.asInt() ); | ||||||
|  |       break; | ||||||
|  |    case uintValue: | ||||||
|  |       document_ += valueToString( value.asUInt() ); | ||||||
|  |       break; | ||||||
|  |    case realValue: | ||||||
|  |       document_ += valueToString( value.asDouble() ); | ||||||
|  |       break; | ||||||
|  |    case stringValue: | ||||||
|  |       document_ += valueToQuotedString( value.asCString() ); | ||||||
|  |       break; | ||||||
|  |    case booleanValue: | ||||||
|  |       document_ += valueToString( value.asBool() ); | ||||||
|  |       break; | ||||||
|  |    case arrayValue: | ||||||
|  |       { | ||||||
|  |          document_ += "["; | ||||||
|  |          int size = value.size(); | ||||||
|  |          for ( int index =0; index < size; ++index ) | ||||||
|  |          { | ||||||
|  |             if ( index > 0 ) | ||||||
|  |                document_ += ","; | ||||||
|  |             writeValue( value[index] ); | ||||||
|  |          } | ||||||
|  |          document_ += "]"; | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  |    case objectValue: | ||||||
|  |       { | ||||||
|  |          Value::Members members( value.getMemberNames() ); | ||||||
|  |          document_ += "{"; | ||||||
|  |          for ( Value::Members::iterator it = members.begin();  | ||||||
|  |                it != members.end();  | ||||||
|  |                ++it ) | ||||||
|  |          { | ||||||
|  |             const std::string &name = *it; | ||||||
|  |             if ( it != members.begin() ) | ||||||
|  |                document_ += ","; | ||||||
|  |             document_ += valueToQuotedString( name.c_str() ); | ||||||
|  |             document_ += yamlCompatiblityEnabled_ ? ": "  | ||||||
|  |                                                   : ":"; | ||||||
|  |             writeValue( value[name] ); | ||||||
|  |          } | ||||||
|  |          document_ += "}"; | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Class StyledWriter | ||||||
|  | // ////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | StyledWriter::StyledWriter() | ||||||
|  |    : rightMargin_( 74 ) | ||||||
|  |    , indentSize_( 3 ) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | std::string  | ||||||
|  | StyledWriter::write( const Value &root ) | ||||||
|  | { | ||||||
|  |    document_ = ""; | ||||||
|  |    addChildValues_ = false; | ||||||
|  |    indentString_ = ""; | ||||||
|  |    writeCommentBeforeValue( root ); | ||||||
|  |    writeValue( root ); | ||||||
|  |    writeCommentAfterValueOnSameLine( root ); | ||||||
|  |    document_ += "\n"; | ||||||
|  |    return document_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledWriter::writeValue( const Value &value ) | ||||||
|  | { | ||||||
|  |    switch ( value.type() ) | ||||||
|  |    { | ||||||
|  |    case nullValue: | ||||||
|  |       pushValue( "null" ); | ||||||
|  |       break; | ||||||
|  |    case intValue: | ||||||
|  |       pushValue( valueToString( value.asInt() ) ); | ||||||
|  |       break; | ||||||
|  |    case uintValue: | ||||||
|  |       pushValue( valueToString( value.asUInt() ) ); | ||||||
|  |       break; | ||||||
|  |    case realValue: | ||||||
|  |       pushValue( valueToString( value.asDouble() ) ); | ||||||
|  |       break; | ||||||
|  |    case stringValue: | ||||||
|  |       pushValue( valueToQuotedString( value.asCString() ) ); | ||||||
|  |       break; | ||||||
|  |    case booleanValue: | ||||||
|  |       pushValue( valueToString( value.asBool() ) ); | ||||||
|  |       break; | ||||||
|  |    case arrayValue: | ||||||
|  |       writeArrayValue( value); | ||||||
|  |       break; | ||||||
|  |    case objectValue: | ||||||
|  |       { | ||||||
|  |          Value::Members members( value.getMemberNames() ); | ||||||
|  |          if ( members.empty() ) | ||||||
|  |             pushValue( "{}" ); | ||||||
|  |          else | ||||||
|  |          { | ||||||
|  |             writeWithIndent( "{" ); | ||||||
|  |             indent(); | ||||||
|  |             Value::Members::iterator it = members.begin(); | ||||||
|  |             while ( true ) | ||||||
|  |             { | ||||||
|  |                const std::string &name = *it; | ||||||
|  |                const Value &childValue = value[name]; | ||||||
|  |                writeCommentBeforeValue( childValue ); | ||||||
|  |                writeWithIndent( valueToQuotedString( name.c_str() ) ); | ||||||
|  |                document_ += " : "; | ||||||
|  |                writeValue( childValue ); | ||||||
|  |                if ( ++it == members.end() ) | ||||||
|  |                { | ||||||
|  |                   writeCommentAfterValueOnSameLine( childValue ); | ||||||
|  |                   break; | ||||||
|  |                } | ||||||
|  |                document_ += ","; | ||||||
|  |                writeCommentAfterValueOnSameLine( childValue ); | ||||||
|  |             } | ||||||
|  |             unindent(); | ||||||
|  |             writeWithIndent( "}" ); | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledWriter::writeArrayValue( const Value &value ) | ||||||
|  | { | ||||||
|  |    unsigned size = value.size(); | ||||||
|  |    if ( size == 0 ) | ||||||
|  |       pushValue( "[]" ); | ||||||
|  |    else | ||||||
|  |    { | ||||||
|  |       bool isArrayMultiLine = isMultineArray( value ); | ||||||
|  |       if ( isArrayMultiLine ) | ||||||
|  |       { | ||||||
|  |          writeWithIndent( "[" ); | ||||||
|  |          indent(); | ||||||
|  |          bool hasChildValue = !childValues_.empty(); | ||||||
|  |          unsigned index =0; | ||||||
|  |          while ( true ) | ||||||
|  |          { | ||||||
|  |             const Value &childValue = value[index]; | ||||||
|  |             writeCommentBeforeValue( childValue ); | ||||||
|  |             if ( hasChildValue ) | ||||||
|  |                writeWithIndent( childValues_[index] ); | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                writeIndent(); | ||||||
|  |                writeValue( childValue ); | ||||||
|  |             } | ||||||
|  |             if ( ++index == size ) | ||||||
|  |             { | ||||||
|  |                writeCommentAfterValueOnSameLine( childValue ); | ||||||
|  |                break; | ||||||
|  |             } | ||||||
|  |             document_ += ","; | ||||||
|  |             writeCommentAfterValueOnSameLine( childValue ); | ||||||
|  |          } | ||||||
|  |          unindent(); | ||||||
|  |          writeWithIndent( "]" ); | ||||||
|  |       } | ||||||
|  |       else // output on a single line | ||||||
|  |       { | ||||||
|  |          assert( childValues_.size() == size ); | ||||||
|  |          document_ += "[ "; | ||||||
|  |          for ( unsigned index =0; index < size; ++index ) | ||||||
|  |          { | ||||||
|  |             if ( index > 0 ) | ||||||
|  |                document_ += ", "; | ||||||
|  |             document_ += childValues_[index]; | ||||||
|  |          } | ||||||
|  |          document_ += " ]"; | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | StyledWriter::isMultineArray( const Value &value ) | ||||||
|  | { | ||||||
|  |    int size = value.size(); | ||||||
|  |    bool isMultiLine = size*3 >= rightMargin_ ; | ||||||
|  |    childValues_.clear(); | ||||||
|  |    for ( int index =0; index < size  &&  !isMultiLine; ++index ) | ||||||
|  |    { | ||||||
|  |       const Value &childValue = value[index]; | ||||||
|  |       isMultiLine = isMultiLine  || | ||||||
|  |                      ( (childValue.isArray()  ||  childValue.isObject())  &&   | ||||||
|  |                         childValue.size() > 0 ); | ||||||
|  |    } | ||||||
|  |    if ( !isMultiLine ) // check if line length > max line length | ||||||
|  |    { | ||||||
|  |       childValues_.reserve( size ); | ||||||
|  |       addChildValues_ = true; | ||||||
|  |       int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' | ||||||
|  |       for ( int index =0; index < size  &&  !isMultiLine; ++index ) | ||||||
|  |       { | ||||||
|  |          writeValue( value[index] ); | ||||||
|  |          lineLength += int( childValues_[index].length() ); | ||||||
|  |          isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] ); | ||||||
|  |       } | ||||||
|  |       addChildValues_ = false; | ||||||
|  |       isMultiLine = isMultiLine  ||  lineLength >= rightMargin_; | ||||||
|  |    } | ||||||
|  |    return isMultiLine; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledWriter::pushValue( const std::string &value ) | ||||||
|  | { | ||||||
|  |    if ( addChildValues_ ) | ||||||
|  |       childValues_.push_back( value ); | ||||||
|  |    else | ||||||
|  |       document_ += value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledWriter::writeIndent() | ||||||
|  | { | ||||||
|  |    if ( !document_.empty() ) | ||||||
|  |    { | ||||||
|  |       char last = document_[document_.length()-1]; | ||||||
|  |       if ( last == ' ' )     // already indented | ||||||
|  |          return; | ||||||
|  |       if ( last != '\n' )    // Comments may add new-line | ||||||
|  |          document_ += '\n'; | ||||||
|  |    } | ||||||
|  |    document_ += indentString_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledWriter::writeWithIndent( const std::string &value ) | ||||||
|  | { | ||||||
|  |    writeIndent(); | ||||||
|  |    document_ += value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledWriter::indent() | ||||||
|  | { | ||||||
|  |    indentString_ += std::string( indentSize_, ' ' ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledWriter::unindent() | ||||||
|  | { | ||||||
|  |    assert( int(indentString_.size()) >= indentSize_ ); | ||||||
|  |    indentString_.resize( indentString_.size() - indentSize_ ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledWriter::writeCommentBeforeValue( const Value &root ) | ||||||
|  | { | ||||||
|  |    if ( !root.hasComment( commentBefore ) ) | ||||||
|  |       return; | ||||||
|  |    document_ += normalizeEOL( root.getComment( commentBefore ) ); | ||||||
|  |    document_ += "\n"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) | ||||||
|  | { | ||||||
|  |    if ( root.hasComment( commentAfterOnSameLine ) ) | ||||||
|  |       document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); | ||||||
|  |  | ||||||
|  |    if ( root.hasComment( commentAfter ) ) | ||||||
|  |    { | ||||||
|  |       document_ += "\n"; | ||||||
|  |       document_ += normalizeEOL( root.getComment( commentAfter ) ); | ||||||
|  |       document_ += "\n"; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | StyledWriter::hasCommentForValue( const Value &value ) | ||||||
|  | { | ||||||
|  |    return value.hasComment( commentBefore ) | ||||||
|  |           ||  value.hasComment( commentAfterOnSameLine ) | ||||||
|  |           ||  value.hasComment( commentAfter ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | std::string  | ||||||
|  | StyledWriter::normalizeEOL( const std::string &text ) | ||||||
|  | { | ||||||
|  |    std::string normalized; | ||||||
|  |    normalized.reserve( text.length() ); | ||||||
|  |    const char *begin = text.c_str(); | ||||||
|  |    const char *end = begin + text.length(); | ||||||
|  |    const char *current = begin; | ||||||
|  |    while ( current != end ) | ||||||
|  |    { | ||||||
|  |       char c = *current++; | ||||||
|  |       if ( c == '\r' ) // mac or dos EOL | ||||||
|  |       { | ||||||
|  |          if ( *current == '\n' ) // convert dos EOL | ||||||
|  |             ++current; | ||||||
|  |          normalized += '\n'; | ||||||
|  |       } | ||||||
|  |       else // handle unix EOL & other char | ||||||
|  |          normalized += c; | ||||||
|  |    } | ||||||
|  |    return normalized; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Class StyledStreamWriter | ||||||
|  | // ////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|  | StyledStreamWriter::StyledStreamWriter( std::string indentation ) | ||||||
|  |    : document_(NULL) | ||||||
|  |    , rightMargin_( 74 ) | ||||||
|  |    , indentation_( indentation ) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void | ||||||
|  | StyledStreamWriter::write( std::ostream &out, const Value &root ) | ||||||
|  | { | ||||||
|  |    document_ = &out; | ||||||
|  |    addChildValues_ = false; | ||||||
|  |    indentString_ = ""; | ||||||
|  |    writeCommentBeforeValue( root ); | ||||||
|  |    writeValue( root ); | ||||||
|  |    writeCommentAfterValueOnSameLine( root ); | ||||||
|  |    *document_ << "\n"; | ||||||
|  |    document_ = NULL; // Forget the stream, for safety. | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledStreamWriter::writeValue( const Value &value ) | ||||||
|  | { | ||||||
|  |    switch ( value.type() ) | ||||||
|  |    { | ||||||
|  |    case nullValue: | ||||||
|  |       pushValue( "null" ); | ||||||
|  |       break; | ||||||
|  |    case intValue: | ||||||
|  |       pushValue( valueToString( value.asInt() ) ); | ||||||
|  |       break; | ||||||
|  |    case uintValue: | ||||||
|  |       pushValue( valueToString( value.asUInt() ) ); | ||||||
|  |       break; | ||||||
|  |    case realValue: | ||||||
|  |       pushValue( valueToString( value.asDouble() ) ); | ||||||
|  |       break; | ||||||
|  |    case stringValue: | ||||||
|  |       pushValue( valueToQuotedString( value.asCString() ) ); | ||||||
|  |       break; | ||||||
|  |    case booleanValue: | ||||||
|  |       pushValue( valueToString( value.asBool() ) ); | ||||||
|  |       break; | ||||||
|  |    case arrayValue: | ||||||
|  |       writeArrayValue( value); | ||||||
|  |       break; | ||||||
|  |    case objectValue: | ||||||
|  |       { | ||||||
|  |          Value::Members members( value.getMemberNames() ); | ||||||
|  |          if ( members.empty() ) | ||||||
|  |             pushValue( "{}" ); | ||||||
|  |          else | ||||||
|  |          { | ||||||
|  |             writeWithIndent( "{" ); | ||||||
|  |             indent(); | ||||||
|  |             Value::Members::iterator it = members.begin(); | ||||||
|  |             while ( true ) | ||||||
|  |             { | ||||||
|  |                const std::string &name = *it; | ||||||
|  |                const Value &childValue = value[name]; | ||||||
|  |                writeCommentBeforeValue( childValue ); | ||||||
|  |                writeWithIndent( valueToQuotedString( name.c_str() ) ); | ||||||
|  |                *document_ << " : "; | ||||||
|  |                writeValue( childValue ); | ||||||
|  |                if ( ++it == members.end() ) | ||||||
|  |                { | ||||||
|  |                   writeCommentAfterValueOnSameLine( childValue ); | ||||||
|  |                   break; | ||||||
|  |                } | ||||||
|  |                *document_ << ","; | ||||||
|  |                writeCommentAfterValueOnSameLine( childValue ); | ||||||
|  |             } | ||||||
|  |             unindent(); | ||||||
|  |             writeWithIndent( "}" ); | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledStreamWriter::writeArrayValue( const Value &value ) | ||||||
|  | { | ||||||
|  |    unsigned size = value.size(); | ||||||
|  |    if ( size == 0 ) | ||||||
|  |       pushValue( "[]" ); | ||||||
|  |    else | ||||||
|  |    { | ||||||
|  |       bool isArrayMultiLine = isMultineArray( value ); | ||||||
|  |       if ( isArrayMultiLine ) | ||||||
|  |       { | ||||||
|  |          writeWithIndent( "[" ); | ||||||
|  |          indent(); | ||||||
|  |          bool hasChildValue = !childValues_.empty(); | ||||||
|  |          unsigned index =0; | ||||||
|  |          while ( true ) | ||||||
|  |          { | ||||||
|  |             const Value &childValue = value[index]; | ||||||
|  |             writeCommentBeforeValue( childValue ); | ||||||
|  |             if ( hasChildValue ) | ||||||
|  |                writeWithIndent( childValues_[index] ); | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  | 	       writeIndent(); | ||||||
|  |                writeValue( childValue ); | ||||||
|  |             } | ||||||
|  |             if ( ++index == size ) | ||||||
|  |             { | ||||||
|  |                writeCommentAfterValueOnSameLine( childValue ); | ||||||
|  |                break; | ||||||
|  |             } | ||||||
|  |             *document_ << ","; | ||||||
|  |             writeCommentAfterValueOnSameLine( childValue ); | ||||||
|  |          } | ||||||
|  |          unindent(); | ||||||
|  |          writeWithIndent( "]" ); | ||||||
|  |       } | ||||||
|  |       else // output on a single line | ||||||
|  |       { | ||||||
|  |          assert( childValues_.size() == size ); | ||||||
|  |          *document_ << "[ "; | ||||||
|  |          for ( unsigned index =0; index < size; ++index ) | ||||||
|  |          { | ||||||
|  |             if ( index > 0 ) | ||||||
|  |                *document_ << ", "; | ||||||
|  |             *document_ << childValues_[index]; | ||||||
|  |          } | ||||||
|  |          *document_ << " ]"; | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | StyledStreamWriter::isMultineArray( const Value &value ) | ||||||
|  | { | ||||||
|  |    int size = value.size(); | ||||||
|  |    bool isMultiLine = size*3 >= rightMargin_ ; | ||||||
|  |    childValues_.clear(); | ||||||
|  |    for ( int index =0; index < size  &&  !isMultiLine; ++index ) | ||||||
|  |    { | ||||||
|  |       const Value &childValue = value[index]; | ||||||
|  |       isMultiLine = isMultiLine  || | ||||||
|  |                      ( (childValue.isArray()  ||  childValue.isObject())  &&   | ||||||
|  |                         childValue.size() > 0 ); | ||||||
|  |    } | ||||||
|  |    if ( !isMultiLine ) // check if line length > max line length | ||||||
|  |    { | ||||||
|  |       childValues_.reserve( size ); | ||||||
|  |       addChildValues_ = true; | ||||||
|  |       int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' | ||||||
|  |       for ( int index =0; index < size  &&  !isMultiLine; ++index ) | ||||||
|  |       { | ||||||
|  |          writeValue( value[index] ); | ||||||
|  |          lineLength += int( childValues_[index].length() ); | ||||||
|  |          isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] ); | ||||||
|  |       } | ||||||
|  |       addChildValues_ = false; | ||||||
|  |       isMultiLine = isMultiLine  ||  lineLength >= rightMargin_; | ||||||
|  |    } | ||||||
|  |    return isMultiLine; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledStreamWriter::pushValue( const std::string &value ) | ||||||
|  | { | ||||||
|  |    if ( addChildValues_ ) | ||||||
|  |       childValues_.push_back( value ); | ||||||
|  |    else | ||||||
|  |       *document_ << value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledStreamWriter::writeIndent() | ||||||
|  | { | ||||||
|  |   /* | ||||||
|  |     Some comments in this method would have been nice. ;-) | ||||||
|  |  | ||||||
|  |    if ( !document_.empty() ) | ||||||
|  |    { | ||||||
|  |       char last = document_[document_.length()-1]; | ||||||
|  |       if ( last == ' ' )     // already indented | ||||||
|  |          return; | ||||||
|  |       if ( last != '\n' )    // Comments may add new-line | ||||||
|  |          *document_ << '\n'; | ||||||
|  |    } | ||||||
|  |   */ | ||||||
|  |    *document_ << '\n' << indentString_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledStreamWriter::writeWithIndent( const std::string &value ) | ||||||
|  | { | ||||||
|  |    writeIndent(); | ||||||
|  |    *document_ << value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledStreamWriter::indent() | ||||||
|  | { | ||||||
|  |    indentString_ += indentation_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledStreamWriter::unindent() | ||||||
|  | { | ||||||
|  |    assert( indentString_.size() >= indentation_.size() ); | ||||||
|  |    indentString_.resize( indentString_.size() - indentation_.size() ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledStreamWriter::writeCommentBeforeValue( const Value &root ) | ||||||
|  | { | ||||||
|  |    if ( !root.hasComment( commentBefore ) ) | ||||||
|  |       return; | ||||||
|  |    *document_ << normalizeEOL( root.getComment( commentBefore ) ); | ||||||
|  |    *document_ << "\n"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void  | ||||||
|  | StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) | ||||||
|  | { | ||||||
|  |    if ( root.hasComment( commentAfterOnSameLine ) ) | ||||||
|  |       *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); | ||||||
|  |  | ||||||
|  |    if ( root.hasComment( commentAfter ) ) | ||||||
|  |    { | ||||||
|  |       *document_ << "\n"; | ||||||
|  |       *document_ << normalizeEOL( root.getComment( commentAfter ) ); | ||||||
|  |       *document_ << "\n"; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool  | ||||||
|  | StyledStreamWriter::hasCommentForValue( const Value &value ) | ||||||
|  | { | ||||||
|  |    return value.hasComment( commentBefore ) | ||||||
|  |           ||  value.hasComment( commentAfterOnSameLine ) | ||||||
|  |           ||  value.hasComment( commentAfter ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | std::string  | ||||||
|  | StyledStreamWriter::normalizeEOL( const std::string &text ) | ||||||
|  | { | ||||||
|  |    std::string normalized; | ||||||
|  |    normalized.reserve( text.length() ); | ||||||
|  |    const char *begin = text.c_str(); | ||||||
|  |    const char *end = begin + text.length(); | ||||||
|  |    const char *current = begin; | ||||||
|  |    while ( current != end ) | ||||||
|  |    { | ||||||
|  |       char c = *current++; | ||||||
|  |       if ( c == '\r' ) // mac or dos EOL | ||||||
|  |       { | ||||||
|  |          if ( *current == '\n' ) // convert dos EOL | ||||||
|  |             ++current; | ||||||
|  |          normalized += '\n'; | ||||||
|  |       } | ||||||
|  |       else // handle unix EOL & other char | ||||||
|  |          normalized += c; | ||||||
|  |    } | ||||||
|  |    return normalized; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | std::ostream& operator<<( std::ostream &sout, const Value &root ) | ||||||
|  | { | ||||||
|  |    Json::StyledStreamWriter writer; | ||||||
|  |    writer.write(sout, root); | ||||||
|  |    return sout; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } // namespace Json | ||||||
| @@ -1,415 +0,0 @@ | |||||||
| // This defines the interface to the QsciCommand class. |  | ||||||
| // |  | ||||||
| // Copyright (c) 2011 Riverbank Computing Limited <info@riverbankcomputing.com> |  | ||||||
| //  |  | ||||||
| // This file is part of QScintilla. |  | ||||||
| //  |  | ||||||
| // This file may be used under the terms of the GNU General Public |  | ||||||
| // License versions 2.0 or 3.0 as published by the Free Software |  | ||||||
| // Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 |  | ||||||
| // included in the packaging of this file.  Alternatively you may (at |  | ||||||
| // your option) use any later version of the GNU General Public |  | ||||||
| // License if such license has been publicly approved by Riverbank |  | ||||||
| // Computing Limited (or its successors, if any) and the KDE Free Qt |  | ||||||
| // Foundation. In addition, as a special exception, Riverbank gives you |  | ||||||
| // certain additional rights. These rights are described in the Riverbank |  | ||||||
| // GPL Exception version 1.1, which can be found in the file |  | ||||||
| // GPL_EXCEPTION.txt in this package. |  | ||||||
| //  |  | ||||||
| // If you are unsure which license is appropriate for your use, please |  | ||||||
| // contact the sales department at sales@riverbankcomputing.com. |  | ||||||
| //  |  | ||||||
| // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE |  | ||||||
| // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifndef QSCICOMMAND_H |  | ||||||
| #define QSCICOMMAND_H |  | ||||||
|  |  | ||||||
| #ifdef __APPLE__ |  | ||||||
| extern "C++" { |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #include <qstring.h> |  | ||||||
|  |  | ||||||
| #include <Qsci/qsciglobal.h> |  | ||||||
| #include <Qsci/qsciscintillabase.h> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class QsciScintilla; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| //! \brief The QsciCommand class represents an internal editor command that may |  | ||||||
| //! have one or two keys bound to it. |  | ||||||
| //! |  | ||||||
| //! Methods are provided to change the keys bound to the command and to remove |  | ||||||
| //! a key binding.  Each command has a user friendly description of the command |  | ||||||
| //! for use in key mapping dialogs. |  | ||||||
| class QSCINTILLA_EXPORT QsciCommand |  | ||||||
| { |  | ||||||
| public: |  | ||||||
|     //! This enum defines the different commands that can be assigned to a key. |  | ||||||
|     enum Command { |  | ||||||
|         //! Move down one line. |  | ||||||
|         LineDown = QsciScintillaBase::SCI_LINEDOWN, |  | ||||||
|  |  | ||||||
|         //! Extend the selection down one line. |  | ||||||
|         LineDownExtend = QsciScintillaBase::SCI_LINEDOWNEXTEND, |  | ||||||
|  |  | ||||||
|         //! Extend the rectangular selection down one line. |  | ||||||
|         LineDownRectExtend = QsciScintillaBase::SCI_LINEDOWNRECTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Scroll the view down one line. |  | ||||||
|         LineScrollDown = QsciScintillaBase::SCI_LINESCROLLDOWN, |  | ||||||
|  |  | ||||||
|         //! Move up one line. |  | ||||||
|         LineUp = QsciScintillaBase::SCI_LINEUP, |  | ||||||
|  |  | ||||||
|         //! Extend the selection up one line. |  | ||||||
|         LineUpExtend = QsciScintillaBase::SCI_LINEUPEXTEND, |  | ||||||
|  |  | ||||||
|         //! Extend the rectangular selection up one line. |  | ||||||
|         LineUpRectExtend = QsciScintillaBase::SCI_LINEUPRECTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Scroll the view up one line. |  | ||||||
|         LineScrollUp = QsciScintillaBase::SCI_LINESCROLLUP, |  | ||||||
|  |  | ||||||
|         //! Scroll to the start of the document. |  | ||||||
|         ScrollToStart = QsciScintillaBase::SCI_SCROLLTOSTART, |  | ||||||
|  |  | ||||||
|         //! Scroll to the end of the document. |  | ||||||
|         ScrollToEnd = QsciScintillaBase::SCI_SCROLLTOEND, |  | ||||||
|  |  | ||||||
|         //! Scroll vertically to centre the current line. |  | ||||||
|         VerticalCentreCaret = QsciScintillaBase::SCI_VERTICALCENTRECARET, |  | ||||||
|  |  | ||||||
|         //! Move down one paragraph. |  | ||||||
|         ParaDown = QsciScintillaBase::SCI_PARADOWN, |  | ||||||
|  |  | ||||||
|         //! Extend the selection down one paragraph. |  | ||||||
|         ParaDownExtend = QsciScintillaBase::SCI_PARADOWNEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move up one paragraph. |  | ||||||
|         ParaUp = QsciScintillaBase::SCI_PARAUP, |  | ||||||
|  |  | ||||||
|         //! Extend the selection up one paragraph. |  | ||||||
|         ParaUpExtend = QsciScintillaBase::SCI_PARAUPEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move left one character. |  | ||||||
|         CharLeft = QsciScintillaBase::SCI_CHARLEFT, |  | ||||||
|  |  | ||||||
|         //! Extend the selection left one character. |  | ||||||
|         CharLeftExtend = QsciScintillaBase::SCI_CHARLEFTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Extend the rectangular selection left one character. |  | ||||||
|         CharLeftRectExtend = QsciScintillaBase::SCI_CHARLEFTRECTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move right one character. |  | ||||||
|         CharRight = QsciScintillaBase::SCI_CHARRIGHT, |  | ||||||
|  |  | ||||||
|         //! Extend the selection right one character. |  | ||||||
|         CharRightExtend = QsciScintillaBase::SCI_CHARRIGHTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Extend the rectangular selection right one character. |  | ||||||
|         CharRightRectExtend = QsciScintillaBase::SCI_CHARRIGHTRECTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move left one word. |  | ||||||
|         WordLeft = QsciScintillaBase::SCI_WORDLEFT, |  | ||||||
|  |  | ||||||
|         //! Extend the selection left one word. |  | ||||||
|         WordLeftExtend = QsciScintillaBase::SCI_WORDLEFTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move right one word. |  | ||||||
|         WordRight = QsciScintillaBase::SCI_WORDRIGHT, |  | ||||||
|  |  | ||||||
|         //! Extend the selection right one word. |  | ||||||
|         WordRightExtend = QsciScintillaBase::SCI_WORDRIGHTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move to the end of the previous word. |  | ||||||
|         WordLeftEnd = QsciScintillaBase::SCI_WORDLEFTEND, |  | ||||||
|  |  | ||||||
|         //! Extend the selection to the end of the previous word. |  | ||||||
|         WordLeftEndExtend = QsciScintillaBase::SCI_WORDLEFTENDEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move to the end of the next word. |  | ||||||
|         WordRightEnd = QsciScintillaBase::SCI_WORDRIGHTEND, |  | ||||||
|  |  | ||||||
|         //! Extend the selection to the end of the next word. |  | ||||||
|         WordRightEndExtend = QsciScintillaBase::SCI_WORDRIGHTENDEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move left one word part. |  | ||||||
|         WordPartLeft = QsciScintillaBase::SCI_WORDPARTLEFT, |  | ||||||
|  |  | ||||||
|         //! Extend the selection left one word part. |  | ||||||
|         WordPartLeftExtend = QsciScintillaBase::SCI_WORDPARTLEFTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move right one word part. |  | ||||||
|         WordPartRight = QsciScintillaBase::SCI_WORDPARTRIGHT, |  | ||||||
|  |  | ||||||
|         //! Extend the selection right one word part. |  | ||||||
|         WordPartRightExtend = QsciScintillaBase::SCI_WORDPARTRIGHTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move to the start of the document line. |  | ||||||
|         Home = QsciScintillaBase::SCI_HOME, |  | ||||||
|  |  | ||||||
|         //! Extend the selection to the start of the document line. |  | ||||||
|         HomeExtend = QsciScintillaBase::SCI_HOMEEXTEND, |  | ||||||
|  |  | ||||||
|         //! Extend the rectangular selection to the start of the document line. |  | ||||||
|         HomeRectExtend = QsciScintillaBase::SCI_HOMERECTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move to the start of the displayed line. |  | ||||||
|         HomeDisplay = QsciScintillaBase::SCI_HOMEDISPLAY, |  | ||||||
|  |  | ||||||
|         //! Extend the selection to the start of the displayed line. |  | ||||||
|         HomeDisplayExtend = QsciScintillaBase::SCI_HOMEDISPLAYEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move to the start of the displayed or document line. |  | ||||||
|         HomeWrap = QsciScintillaBase::SCI_HOMEWRAP, |  | ||||||
|  |  | ||||||
|         //! Extend the selection to the start of the displayed or document |  | ||||||
|         //! line. |  | ||||||
|         HomeWrapExtend = QsciScintillaBase::SCI_HOMEWRAPEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move to the first visible character in the document line. |  | ||||||
|         VCHome = QsciScintillaBase::SCI_VCHOME, |  | ||||||
|  |  | ||||||
|         //! Extend the selection to the first visible character in the document |  | ||||||
|         //! line. |  | ||||||
|         VCHomeExtend = QsciScintillaBase::SCI_VCHOMEEXTEND, |  | ||||||
|  |  | ||||||
|         //! Extend the rectangular selection to the first visible character in |  | ||||||
|         //! the document line. |  | ||||||
|         VCHomeRectExtend = QsciScintillaBase::SCI_VCHOMERECTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move to the first visible character of the displayed or document |  | ||||||
|         //! line. |  | ||||||
|         VCHomeWrap = QsciScintillaBase::SCI_VCHOMEWRAP, |  | ||||||
|  |  | ||||||
|         //! Extend the selection to the first visible character of the |  | ||||||
|         //! displayed or document line. |  | ||||||
|         VCHomeWrapExtend = QsciScintillaBase::SCI_VCHOMEWRAPEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move to the end of the document line. |  | ||||||
|         LineEnd = QsciScintillaBase::SCI_LINEEND, |  | ||||||
|  |  | ||||||
|         //! Extend the selection to the end of the document line. |  | ||||||
|         LineEndExtend = QsciScintillaBase::SCI_LINEENDEXTEND, |  | ||||||
|  |  | ||||||
|         //! Extend the rectangular selection to the end of the document line. |  | ||||||
|         LineEndRectExtend = QsciScintillaBase::SCI_LINEENDRECTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move to the end of the displayed line. |  | ||||||
|         LineEndDisplay = QsciScintillaBase::SCI_LINEENDDISPLAY, |  | ||||||
|  |  | ||||||
|         //! Extend the selection to the end of the displayed line. |  | ||||||
|         LineEndDisplayExtend = QsciScintillaBase::SCI_LINEENDDISPLAYEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move to the end of the displayed or document line. |  | ||||||
|         LineEndWrap = QsciScintillaBase::SCI_LINEENDWRAP, |  | ||||||
|  |  | ||||||
|         //! Extend the selection to the end of the displayed or document line. |  | ||||||
|         LineEndWrapExtend = QsciScintillaBase::SCI_LINEENDWRAPEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move to the start of the document. |  | ||||||
|         DocumentStart = QsciScintillaBase::SCI_DOCUMENTSTART, |  | ||||||
|  |  | ||||||
|         //! Extend the selection to the start of the document. |  | ||||||
|         DocumentStartExtend = QsciScintillaBase::SCI_DOCUMENTSTARTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move to the end of the document. |  | ||||||
|         DocumentEnd = QsciScintillaBase::SCI_DOCUMENTEND, |  | ||||||
|  |  | ||||||
|         //! Extend the selection to the end of the document. |  | ||||||
|         DocumentEndExtend = QsciScintillaBase::SCI_DOCUMENTENDEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move up one page. |  | ||||||
|         PageUp = QsciScintillaBase::SCI_PAGEUP, |  | ||||||
|  |  | ||||||
|         //! Extend the selection up one page. |  | ||||||
|         PageUpExtend = QsciScintillaBase::SCI_PAGEUPEXTEND, |  | ||||||
|  |  | ||||||
|         //! Extend the rectangular selection up one page. |  | ||||||
|         PageUpRectExtend = QsciScintillaBase::SCI_PAGEUPRECTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Move down one page. |  | ||||||
|         PageDown = QsciScintillaBase::SCI_PAGEDOWN, |  | ||||||
|  |  | ||||||
|         //! Extend the selection down one page. |  | ||||||
|         PageDownExtend = QsciScintillaBase::SCI_PAGEDOWNEXTEND, |  | ||||||
|  |  | ||||||
|         //! Extend the rectangular selection down one page. |  | ||||||
|         PageDownRectExtend = QsciScintillaBase::SCI_PAGEDOWNRECTEXTEND, |  | ||||||
|  |  | ||||||
|         //! Stuttered move up one page. |  | ||||||
|         StutteredPageUp = QsciScintillaBase::SCI_STUTTEREDPAGEUP, |  | ||||||
|  |  | ||||||
|         //! Stuttered extend the selection up one page. |  | ||||||
|         StutteredPageUpExtend = QsciScintillaBase::SCI_STUTTEREDPAGEUPEXTEND, |  | ||||||
|  |  | ||||||
|         //! Stuttered move down one page. |  | ||||||
|         StutteredPageDown = QsciScintillaBase::SCI_STUTTEREDPAGEDOWN, |  | ||||||
|  |  | ||||||
|         //! Stuttered extend the selection down one page. |  | ||||||
|         StutteredPageDownExtend = QsciScintillaBase::SCI_STUTTEREDPAGEDOWNEXTEND, |  | ||||||
|  |  | ||||||
|         //! Delete the current character. |  | ||||||
|         Delete = QsciScintillaBase::SCI_CLEAR, |  | ||||||
|  |  | ||||||
|         //! Delete the previous character. |  | ||||||
|         DeleteBack = QsciScintillaBase::SCI_DELETEBACK, |  | ||||||
|  |  | ||||||
|         //! Delete the previous character if not at start of line. |  | ||||||
|         DeleteBackNotLine = QsciScintillaBase::SCI_DELETEBACKNOTLINE, |  | ||||||
|  |  | ||||||
|         //! Delete the word to the left. |  | ||||||
|         DeleteWordLeft = QsciScintillaBase::SCI_DELWORDLEFT, |  | ||||||
|  |  | ||||||
|         //! Delete the word to the right. |  | ||||||
|         DeleteWordRight = QsciScintillaBase::SCI_DELWORDRIGHT, |  | ||||||
|  |  | ||||||
|         //! Delete right to the end of the next word. |  | ||||||
|         DeleteWordRightEnd = QsciScintillaBase::SCI_DELWORDRIGHTEND, |  | ||||||
|  |  | ||||||
|         //! Delete the line to the left. |  | ||||||
|         DeleteLineLeft = QsciScintillaBase::SCI_DELLINELEFT, |  | ||||||
|  |  | ||||||
|         //! Delete the line to the right. |  | ||||||
|         DeleteLineRight = QsciScintillaBase::SCI_DELLINERIGHT, |  | ||||||
|  |  | ||||||
|         //! Delete the current line. |  | ||||||
|         LineDelete = QsciScintillaBase::SCI_LINEDELETE, |  | ||||||
|  |  | ||||||
|         //! Cut the current line to the clipboard. |  | ||||||
|         LineCut = QsciScintillaBase::SCI_LINECUT, |  | ||||||
|  |  | ||||||
|         //! Copy the current line to the clipboard. |  | ||||||
|         LineCopy = QsciScintillaBase::SCI_LINECOPY, |  | ||||||
|  |  | ||||||
|         //! Transpose the current and previous lines. |  | ||||||
|         LineTranspose = QsciScintillaBase::SCI_LINETRANSPOSE, |  | ||||||
|  |  | ||||||
|         //! Duplicate the current line. |  | ||||||
|         LineDuplicate = QsciScintillaBase::SCI_LINEDUPLICATE, |  | ||||||
|  |  | ||||||
|         //! Select the whole document. |  | ||||||
|         SelectAll = QsciScintillaBase::SCI_SELECTALL, |  | ||||||
|  |  | ||||||
|         //! Move the selected lines up one line. |  | ||||||
|         MoveSelectedLinesUp = QsciScintillaBase::SCI_MOVESELECTEDLINESUP, |  | ||||||
|  |  | ||||||
|         //! Move the selected lines down one line. |  | ||||||
|         MoveSelectedLinesDown = QsciScintillaBase::SCI_MOVESELECTEDLINESDOWN, |  | ||||||
|  |  | ||||||
|         //! Duplicate the selection. |  | ||||||
|         SelectionDuplicate = QsciScintillaBase::SCI_SELECTIONDUPLICATE, |  | ||||||
|  |  | ||||||
|         //! Convert the selection to lower case. |  | ||||||
|         SelectionLowerCase = QsciScintillaBase::SCI_LOWERCASE, |  | ||||||
|  |  | ||||||
|         //! Convert the selection to upper case. |  | ||||||
|         SelectionUpperCase = QsciScintillaBase::SCI_UPPERCASE, |  | ||||||
|  |  | ||||||
|         //! Cut the selection to the clipboard. |  | ||||||
|         SelectionCut = QsciScintillaBase::SCI_CUT, |  | ||||||
|  |  | ||||||
|         //! Copy the selection to the clipboard. |  | ||||||
|         SelectionCopy = QsciScintillaBase::SCI_COPY, |  | ||||||
|  |  | ||||||
|         //! Paste from the clipboard. |  | ||||||
|         Paste = QsciScintillaBase::SCI_PASTE, |  | ||||||
|  |  | ||||||
|         //! Toggle insert/overtype. |  | ||||||
|         EditToggleOvertype = QsciScintillaBase::SCI_EDITTOGGLEOVERTYPE, |  | ||||||
|  |  | ||||||
|         //! Insert a platform dependent newline. |  | ||||||
|         Newline = QsciScintillaBase::SCI_NEWLINE, |  | ||||||
|  |  | ||||||
|         //! Insert a formfeed. |  | ||||||
|         Formfeed = QsciScintillaBase::SCI_FORMFEED, |  | ||||||
|  |  | ||||||
|         //! Indent one level. |  | ||||||
|         Tab = QsciScintillaBase::SCI_TAB, |  | ||||||
|  |  | ||||||
|         //! De-indent one level. |  | ||||||
|         Backtab = QsciScintillaBase::SCI_BACKTAB, |  | ||||||
|  |  | ||||||
|         //! Cancel any current operation. |  | ||||||
|         Cancel = QsciScintillaBase::SCI_CANCEL, |  | ||||||
|  |  | ||||||
|         //! Undo the last command. |  | ||||||
|         Undo = QsciScintillaBase::SCI_UNDO, |  | ||||||
|  |  | ||||||
|         //! Redo the last command. |  | ||||||
|         Redo = QsciScintillaBase::SCI_REDO, |  | ||||||
|  |  | ||||||
|         //! Zoom in. |  | ||||||
|         ZoomIn = QsciScintillaBase::SCI_ZOOMIN, |  | ||||||
|  |  | ||||||
|         //! Zoom out. |  | ||||||
|         ZoomOut = QsciScintillaBase::SCI_ZOOMOUT, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     //! Return the command that will be executed by this instance. |  | ||||||
|     Command command() const {return scicmd;} |  | ||||||
|  |  | ||||||
|     //! Execute the command. |  | ||||||
|     void execute(); |  | ||||||
|  |  | ||||||
|     //! Binds the key \a key to the command.  If \a key is 0 then the key |  | ||||||
|     //! binding is removed.  If \a key is invalid then the key binding is |  | ||||||
|     //! unchanged.  Valid keys are any visible or control character or any |  | ||||||
|     //! of \c Key_Down, \c Key_Up, \c Key_Left, \c Key_Right, \c Key_Home, |  | ||||||
|     //! \c Key_End, \c Key_PageUp, \c Key_PageDown, \c Key_Delete, |  | ||||||
|     //! \c Key_Insert, \c Key_Escape, \c Key_Backspace, \c Key_Tab and |  | ||||||
|     //! \c Key_Return.  Keys may be modified with any combination of \c SHIFT, |  | ||||||
|     //! \c CTRL, \c ALT and \c META. |  | ||||||
|     //! |  | ||||||
|     //! \sa key(), setAlternateKey(), validKey() |  | ||||||
|     void setKey(int key); |  | ||||||
|  |  | ||||||
|     //! Binds the alternate key \a altkey to the command.  If \a key is 0 |  | ||||||
|     //! then the alternate key binding is removed. |  | ||||||
|     //! |  | ||||||
|     //! \sa alternateKey(), setKey(), validKey() |  | ||||||
|     void setAlternateKey(int altkey); |  | ||||||
|  |  | ||||||
|     //! The key that is currently bound to the command is returned. |  | ||||||
|     //! |  | ||||||
|     //! \sa setKey(), alternateKey() |  | ||||||
|     int key() const {return qkey;} |  | ||||||
|  |  | ||||||
|     //! The alternate key that is currently bound to the command is |  | ||||||
|     //! returned. |  | ||||||
|     //! |  | ||||||
|     //! \sa setAlternateKey(), key() |  | ||||||
|     int alternateKey() const {return qaltkey;} |  | ||||||
|  |  | ||||||
|     //! If the key \a key is valid then true is returned. |  | ||||||
|     static bool validKey(int key); |  | ||||||
|  |  | ||||||
|     //! The user friendly description of the command is returned. |  | ||||||
|     QString description() const; |  | ||||||
|  |  | ||||||
| private: |  | ||||||
|     friend class QsciCommandSet; |  | ||||||
|  |  | ||||||
|     QsciCommand(QsciScintilla *qs, Command cmd, int key, int altkey, |  | ||||||
|             const char *desc); |  | ||||||
|  |  | ||||||
|     void bindKey(int key,int &qk,int &scik); |  | ||||||
|  |  | ||||||
|     QsciScintilla *qsCmd; |  | ||||||
|     Command scicmd; |  | ||||||
|     int qkey, scikey, qaltkey, scialtkey; |  | ||||||
|     const char *descCmd; |  | ||||||
|  |  | ||||||
|     QsciCommand(const QsciCommand &); |  | ||||||
|     QsciCommand &operator=(const QsciCommand &); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| #ifdef __APPLE__ |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,116 +0,0 @@ | |||||||
| // This module defines interface to the QsciPrinter class. |  | ||||||
| // |  | ||||||
| // Copyright (c) 2011 Riverbank Computing Limited <info@riverbankcomputing.com> |  | ||||||
| //  |  | ||||||
| // This file is part of QScintilla. |  | ||||||
| //  |  | ||||||
| // This file may be used under the terms of the GNU General Public |  | ||||||
| // License versions 2.0 or 3.0 as published by the Free Software |  | ||||||
| // Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 |  | ||||||
| // included in the packaging of this file.  Alternatively you may (at |  | ||||||
| // your option) use any later version of the GNU General Public |  | ||||||
| // License if such license has been publicly approved by Riverbank |  | ||||||
| // Computing Limited (or its successors, if any) and the KDE Free Qt |  | ||||||
| // Foundation. In addition, as a special exception, Riverbank gives you |  | ||||||
| // certain additional rights. These rights are described in the Riverbank |  | ||||||
| // GPL Exception version 1.1, which can be found in the file |  | ||||||
| // GPL_EXCEPTION.txt in this package. |  | ||||||
| //  |  | ||||||
| // If you are unsure which license is appropriate for your use, please |  | ||||||
| // contact the sales department at sales@riverbankcomputing.com. |  | ||||||
| //  |  | ||||||
| // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE |  | ||||||
| // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifndef QSCIPRINTER_H |  | ||||||
| #define QSCIPRINTER_H |  | ||||||
|  |  | ||||||
| #ifdef __APPLE__ |  | ||||||
| extern "C++" { |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #include <qprinter.h> |  | ||||||
|  |  | ||||||
| #include <Qsci/qsciglobal.h> |  | ||||||
| #include <Qsci/qsciscintilla.h> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| QT_BEGIN_NAMESPACE |  | ||||||
| class QRect; |  | ||||||
| class QPainter; |  | ||||||
| QT_END_NAMESPACE |  | ||||||
|  |  | ||||||
| class QsciScintillaBase; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| //! \brief The QsciPrinter class is a sub-class of the Qt QPrinter class that |  | ||||||
| //! is able to print the text of a Scintilla document. |  | ||||||
| //! |  | ||||||
| //! The class can be further sub-classed to alter to layout of the text, adding |  | ||||||
| //! headers and footers for example. |  | ||||||
| class QSCINTILLA_EXPORT QsciPrinter : public QPrinter |  | ||||||
| { |  | ||||||
| public: |  | ||||||
|     //! Constructs a printer paint device with mode \a mode. |  | ||||||
|     QsciPrinter(PrinterMode mode = ScreenResolution); |  | ||||||
|  |  | ||||||
|     //! Destroys the QsciPrinter instance. |  | ||||||
|     virtual ~QsciPrinter(); |  | ||||||
|  |  | ||||||
|     //! Format a page, by adding headers and footers for example, before the |  | ||||||
|     //! document text is drawn on it.  \a painter is the painter to be used to |  | ||||||
|     //! add customised text and graphics.  \a drawing is true if the page is |  | ||||||
|     //! actually being drawn rather than being sized.  \a painter drawing |  | ||||||
|     //! methods must only be called when \a drawing is true.  \a area is the |  | ||||||
|     //! area of the page that will be used to draw the text.  This should be |  | ||||||
|     //! modified if it is necessary to reserve space for any customised text or |  | ||||||
|     //! graphics.  By default the area is relative to the printable area of the |  | ||||||
|     //! page.  Use QPrinter::setFullPage() because calling printRange() if you |  | ||||||
|     //! want to try and print over the whole page.  \a pagenr is the number of |  | ||||||
|     //! the page.  The first page is numbered 1. |  | ||||||
|     virtual void formatPage(QPainter &painter, bool drawing, QRect &area, |  | ||||||
|             int pagenr); |  | ||||||
|  |  | ||||||
|     //! Return the number of points to add to each font when printing. |  | ||||||
|     //! |  | ||||||
|     //! \sa setMagnification() |  | ||||||
|     int magnification() const {return mag;} |  | ||||||
|  |  | ||||||
|     //! Sets the number of points to add to each font when printing to \a |  | ||||||
|     //! magnification. |  | ||||||
|     //! |  | ||||||
|     //! \sa magnification() |  | ||||||
|     virtual void setMagnification(int magnification); |  | ||||||
|  |  | ||||||
|     //! Print a range of lines from the Scintilla instance \a qsb.  \a from is |  | ||||||
|     //! the first line to print and a negative value signifies the first line |  | ||||||
|     //! of text.  \a to is the last line to print and a negative value |  | ||||||
|     //! signifies the last line of text.  true is returned if there was no |  | ||||||
|     //! error. |  | ||||||
|     virtual int printRange(QsciScintillaBase *qsb, int from = -1, int to = -1); |  | ||||||
|  |  | ||||||
|     //! Return the line wrap mode used when printing.  The default is |  | ||||||
|     //! QsciScintilla::WrapWord. |  | ||||||
|     //! |  | ||||||
|     //! \sa setWrapMode() |  | ||||||
|     QsciScintilla::WrapMode wrapMode() const {return wrap;} |  | ||||||
|  |  | ||||||
|     //! Sets the line wrap mode used when printing to \a wmode. |  | ||||||
|     //! |  | ||||||
|     //! \sa wrapMode() |  | ||||||
|     virtual void setWrapMode(QsciScintilla::WrapMode wmode); |  | ||||||
|  |  | ||||||
| private: |  | ||||||
|     int mag; |  | ||||||
|     QsciScintilla::WrapMode wrap; |  | ||||||
|  |  | ||||||
|     QsciPrinter(const QsciPrinter &); |  | ||||||
|     QsciPrinter &operator=(const QsciPrinter &); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| #ifdef __APPLE__ |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,116 +0,0 @@ | |||||||
| // This module defines interface to the QsciPrinter class. |  | ||||||
| // |  | ||||||
| // Copyright (c) 2011 Riverbank Computing Limited <info@riverbankcomputing.com> |  | ||||||
| //  |  | ||||||
| // This file is part of QScintilla. |  | ||||||
| //  |  | ||||||
| // This file may be used under the terms of the GNU General Public |  | ||||||
| // License versions 2.0 or 3.0 as published by the Free Software |  | ||||||
| // Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3 |  | ||||||
| // included in the packaging of this file.  Alternatively you may (at |  | ||||||
| // your option) use any later version of the GNU General Public |  | ||||||
| // License if such license has been publicly approved by Riverbank |  | ||||||
| // Computing Limited (or its successors, if any) and the KDE Free Qt |  | ||||||
| // Foundation. In addition, as a special exception, Riverbank gives you |  | ||||||
| // certain additional rights. These rights are described in the Riverbank |  | ||||||
| // GPL Exception version 1.1, which can be found in the file |  | ||||||
| // GPL_EXCEPTION.txt in this package. |  | ||||||
| //  |  | ||||||
| // If you are unsure which license is appropriate for your use, please |  | ||||||
| // contact the sales department at sales@riverbankcomputing.com. |  | ||||||
| //  |  | ||||||
| // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE |  | ||||||
| // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifndef QSCIPRINTER_H |  | ||||||
| #define QSCIPRINTER_H |  | ||||||
|  |  | ||||||
| #ifdef __APPLE__ |  | ||||||
| extern "C++" { |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #include <qprinter.h> |  | ||||||
|  |  | ||||||
| #include <Qsci/qsciglobal.h> |  | ||||||
| #include <Qsci/qsciscintilla.h> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| QT_BEGIN_NAMESPACE |  | ||||||
| class QRect; |  | ||||||
| class QPainter; |  | ||||||
| QT_END_NAMESPACE |  | ||||||
|  |  | ||||||
| class QsciScintillaBase; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| //! \brief The QsciPrinter class is a sub-class of the Qt QPrinter class that |  | ||||||
| //! is able to print the text of a Scintilla document. |  | ||||||
| //! |  | ||||||
| //! The class can be further sub-classed to alter to layout of the text, adding |  | ||||||
| //! headers and footers for example. |  | ||||||
| class QSCINTILLA_EXPORT QsciPrinter : public QPrinter |  | ||||||
| { |  | ||||||
| public: |  | ||||||
|     //! Constructs a printer paint device with mode \a mode. |  | ||||||
|     QsciPrinter(PrinterMode mode = ScreenResolution); |  | ||||||
|  |  | ||||||
|     //! Destroys the QsciPrinter instance. |  | ||||||
|     virtual ~QsciPrinter(); |  | ||||||
|  |  | ||||||
|     //! Format a page, by adding headers and footers for example, before the |  | ||||||
|     //! document text is drawn on it.  \a painter is the painter to be used to |  | ||||||
|     //! add customised text and graphics.  \a drawing is true if the page is |  | ||||||
|     //! actually being drawn rather than being sized.  \a painter drawing |  | ||||||
|     //! methods must only be called when \a drawing is true.  \a area is the |  | ||||||
|     //! area of the page that will be used to draw the text.  This should be |  | ||||||
|     //! modified if it is necessary to reserve space for any customised text or |  | ||||||
|     //! graphics.  By default the area is relative to the printable area of the |  | ||||||
|     //! page.  Use QPrinter::setFullPage() because calling printRange() if you |  | ||||||
|     //! want to try and print over the whole page.  \a pagenr is the number of |  | ||||||
|     //! the page.  The first page is numbered 1. |  | ||||||
|     virtual void formatPage(QPainter &painter, bool drawing, QRect &area, |  | ||||||
|             int pagenr); |  | ||||||
|  |  | ||||||
|     //! Return the number of points to add to each font when printing. |  | ||||||
|     //! |  | ||||||
|     //! \sa setMagnification() |  | ||||||
|     int magnification() const {return mag;} |  | ||||||
|  |  | ||||||
|     //! Sets the number of points to add to each font when printing to \a |  | ||||||
|     //! magnification. |  | ||||||
|     //! |  | ||||||
|     //! \sa magnification() |  | ||||||
|     virtual void setMagnification(int magnification); |  | ||||||
|  |  | ||||||
|     //! Print a range of lines from the Scintilla instance \a qsb.  \a from is |  | ||||||
|     //! the first line to print and a negative value signifies the first line |  | ||||||
|     //! of text.  \a to is the last line to print and a negative value |  | ||||||
|     //! signifies the last line of text.  true is returned if there was no |  | ||||||
|     //! error. |  | ||||||
|     virtual int printRange(QsciScintillaBase *qsb, int from = -1, int to = -1); |  | ||||||
|  |  | ||||||
|     //! Return the line wrap mode used when printing.  The default is |  | ||||||
|     //! QsciScintilla::WrapWord. |  | ||||||
|     //! |  | ||||||
|     //! \sa setWrapMode() |  | ||||||
|     QsciScintilla::WrapMode wrapMode() const {return wrap;} |  | ||||||
|  |  | ||||||
|     //! Sets the line wrap mode used when printing to \a wmode. |  | ||||||
|     //! |  | ||||||
|     //! \sa wrapMode() |  | ||||||
|     virtual void setWrapMode(QsciScintilla::WrapMode wmode); |  | ||||||
|  |  | ||||||
| private: |  | ||||||
|     int mag; |  | ||||||
|     QsciScintilla::WrapMode wrap; |  | ||||||
|  |  | ||||||
|     QsciPrinter(const QsciPrinter &); |  | ||||||
|     QsciPrinter &operator=(const QsciPrinter &); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| #ifdef __APPLE__ |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
							
								
								
									
										557
									
								
								samples/C++/srs_app_ingest.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										557
									
								
								samples/C++/srs_app_ingest.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,557 @@ | |||||||
|  | /* | ||||||
|  | The MIT License (MIT) | ||||||
|  |  | ||||||
|  | Copyright (c) 2013-2015 SRS(ossrs) | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||||
|  | this software and associated documentation files (the "Software"), to deal in | ||||||
|  | the Software without restriction, including without limitation the rights to | ||||||
|  | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||||
|  | the Software, and to permit persons to whom the Software is furnished to do so, | ||||||
|  | subject to the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be included in all | ||||||
|  | copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||||
|  | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||||
|  | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||||
|  | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||||
|  | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | // Source - https://github.com/REN-I/srs/blob/3aae7854702a37955bce706fcd8122b02ac07f53/trunk/src/app/srs_app_ingest.cpp | ||||||
|  |  | ||||||
|  | #include <srs_app_ingest.hpp> | ||||||
|  |  | ||||||
|  | #ifdef SRS_AUTO_INGEST | ||||||
|  |  | ||||||
|  | #include <stdlib.h> | ||||||
|  | using namespace std; | ||||||
|  |  | ||||||
|  | #include <srs_kernel_error.hpp> | ||||||
|  | #include <srs_app_config.hpp> | ||||||
|  | #include <srs_kernel_log.hpp> | ||||||
|  | #include <srs_app_ffmpeg.hpp> | ||||||
|  | #include <srs_app_pithy_print.hpp> | ||||||
|  | #include <srs_kernel_utility.hpp> | ||||||
|  | #include <srs_app_utility.hpp> | ||||||
|  |  | ||||||
|  | // when error, ingester sleep for a while and retry. | ||||||
|  | // ingest never sleep a long time, for we must start the stream ASAP. | ||||||
|  | #define SRS_AUTO_INGESTER_SLEEP_US (int64_t)(3*1000*1000LL) | ||||||
|  |  | ||||||
|  | SrsIngesterFFMPEG::SrsIngesterFFMPEG() | ||||||
|  | { | ||||||
|  |     ffmpeg = NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SrsIngesterFFMPEG::~SrsIngesterFFMPEG() | ||||||
|  | { | ||||||
|  |     srs_freep(ffmpeg); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngesterFFMPEG::initialize(SrsFFMPEG* ff, string v, string i) | ||||||
|  | { | ||||||
|  |     int ret = ERROR_SUCCESS; | ||||||
|  |      | ||||||
|  |     ffmpeg = ff; | ||||||
|  |     vhost = v; | ||||||
|  |     id = i; | ||||||
|  |     starttime = srs_get_system_time_ms(); | ||||||
|  |      | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | string SrsIngesterFFMPEG::uri() | ||||||
|  | { | ||||||
|  |     return vhost + "/" + id; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngesterFFMPEG::alive() | ||||||
|  | { | ||||||
|  |     return (int)(srs_get_system_time_ms() - starttime); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool SrsIngesterFFMPEG::equals(string v) | ||||||
|  | { | ||||||
|  |     return vhost == v; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool SrsIngesterFFMPEG::equals(string v, string i) | ||||||
|  | { | ||||||
|  |     return vhost == v && id == i; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngesterFFMPEG::start() | ||||||
|  | { | ||||||
|  |     return ffmpeg->start(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SrsIngesterFFMPEG::stop() | ||||||
|  | { | ||||||
|  |     ffmpeg->stop(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngesterFFMPEG::cycle() | ||||||
|  | { | ||||||
|  |     return ffmpeg->cycle(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SrsIngesterFFMPEG::fast_stop() | ||||||
|  | { | ||||||
|  |     ffmpeg->fast_stop(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SrsIngester::SrsIngester() | ||||||
|  | { | ||||||
|  |     _srs_config->subscribe(this); | ||||||
|  |      | ||||||
|  |     pthread = new SrsReusableThread("ingest", this, SRS_AUTO_INGESTER_SLEEP_US); | ||||||
|  |     pprint = SrsPithyPrint::create_ingester(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SrsIngester::~SrsIngester() | ||||||
|  | { | ||||||
|  |     _srs_config->unsubscribe(this); | ||||||
|  |      | ||||||
|  |     srs_freep(pthread); | ||||||
|  |     clear_engines(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngester::start() | ||||||
|  | { | ||||||
|  |     int ret = ERROR_SUCCESS; | ||||||
|  |      | ||||||
|  |     if ((ret = parse()) != ERROR_SUCCESS) { | ||||||
|  |         clear_engines(); | ||||||
|  |         ret = ERROR_SUCCESS; | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // even no ingesters, we must also start it, | ||||||
|  |     // for the reload may add more ingesters. | ||||||
|  |      | ||||||
|  |     // start thread to run all encoding engines. | ||||||
|  |     if ((ret = pthread->start()) != ERROR_SUCCESS) { | ||||||
|  |         srs_error("st_thread_create failed. ret=%d", ret); | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |     srs_trace("ingest thread cid=%d, current_cid=%d", pthread->cid(), _srs_context->get_id()); | ||||||
|  |      | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngester::parse_ingesters(SrsConfDirective* vhost) | ||||||
|  | { | ||||||
|  |     int ret = ERROR_SUCCESS; | ||||||
|  |      | ||||||
|  |     std::vector<SrsConfDirective*> ingesters = _srs_config->get_ingesters(vhost->arg0()); | ||||||
|  |      | ||||||
|  |     // create engine | ||||||
|  |     for (int i = 0; i < (int)ingesters.size(); i++) { | ||||||
|  |         SrsConfDirective* ingest = ingesters[i]; | ||||||
|  |         if ((ret = parse_engines(vhost, ingest)) != ERROR_SUCCESS) { | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngester::parse_engines(SrsConfDirective* vhost, SrsConfDirective* ingest) | ||||||
|  | { | ||||||
|  |     int ret = ERROR_SUCCESS; | ||||||
|  |  | ||||||
|  |     if (!_srs_config->get_ingest_enabled(ingest)) { | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     std::string ffmpeg_bin = _srs_config->get_ingest_ffmpeg(ingest); | ||||||
|  |     if (ffmpeg_bin.empty()) { | ||||||
|  |         ret = ERROR_ENCODER_PARSE; | ||||||
|  |         srs_trace("empty ffmpeg ret=%d", ret); | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // get all engines. | ||||||
|  |     std::vector<SrsConfDirective*> engines = _srs_config->get_transcode_engines(ingest); | ||||||
|  |      | ||||||
|  |     // create ingesters without engines. | ||||||
|  |     if (engines.empty()) { | ||||||
|  |         SrsFFMPEG* ffmpeg = new SrsFFMPEG(ffmpeg_bin); | ||||||
|  |         if ((ret = initialize_ffmpeg(ffmpeg, vhost, ingest, NULL)) != ERROR_SUCCESS) { | ||||||
|  |             srs_freep(ffmpeg); | ||||||
|  |             if (ret != ERROR_ENCODER_LOOP) { | ||||||
|  |                 srs_error("invalid ingest engine. ret=%d", ret); | ||||||
|  |             } | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         SrsIngesterFFMPEG* ingester = new SrsIngesterFFMPEG(); | ||||||
|  |         if ((ret = ingester->initialize(ffmpeg, vhost->arg0(), ingest->arg0())) != ERROR_SUCCESS) { | ||||||
|  |             srs_freep(ingester); | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         ingesters.push_back(ingester); | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // create ingesters with engine | ||||||
|  |     for (int i = 0; i < (int)engines.size(); i++) { | ||||||
|  |         SrsConfDirective* engine = engines[i]; | ||||||
|  |         SrsFFMPEG* ffmpeg = new SrsFFMPEG(ffmpeg_bin); | ||||||
|  |         if ((ret = initialize_ffmpeg(ffmpeg, vhost, ingest, engine)) != ERROR_SUCCESS) { | ||||||
|  |             srs_freep(ffmpeg); | ||||||
|  |             if (ret != ERROR_ENCODER_LOOP) { | ||||||
|  |                 srs_error("invalid ingest engine: %s %s, ret=%d",  | ||||||
|  |                     ingest->arg0().c_str(), engine->arg0().c_str(), ret); | ||||||
|  |             } | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         SrsIngesterFFMPEG* ingester = new SrsIngesterFFMPEG(); | ||||||
|  |         if ((ret = ingester->initialize(ffmpeg, vhost->arg0(), ingest->arg0())) != ERROR_SUCCESS) { | ||||||
|  |             srs_freep(ingester); | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         ingesters.push_back(ingester); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SrsIngester::dispose() | ||||||
|  | { | ||||||
|  |     // first, use fast stop to notice all FFMPEG to quit gracefully. | ||||||
|  |     std::vector<SrsIngesterFFMPEG*>::iterator it; | ||||||
|  |     for (it = ingesters.begin(); it != ingesters.end(); ++it) { | ||||||
|  |         SrsIngesterFFMPEG* ingester = *it; | ||||||
|  |         ingester->fast_stop(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (!ingesters.empty()) { | ||||||
|  |         srs_trace("fast stop all ingesters ok."); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // then, use stop to wait FFMPEG quit one by one and send SIGKILL if needed. | ||||||
|  |     stop(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SrsIngester::stop() | ||||||
|  | { | ||||||
|  |     pthread->stop(); | ||||||
|  |     clear_engines(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngester::cycle() | ||||||
|  | { | ||||||
|  |     int ret = ERROR_SUCCESS; | ||||||
|  |      | ||||||
|  |     std::vector<SrsIngesterFFMPEG*>::iterator it; | ||||||
|  |     for (it = ingesters.begin(); it != ingesters.end(); ++it) { | ||||||
|  |         SrsIngesterFFMPEG* ingester = *it; | ||||||
|  |          | ||||||
|  |         // start all ffmpegs. | ||||||
|  |         if ((ret = ingester->start()) != ERROR_SUCCESS) { | ||||||
|  |             srs_error("ingest ffmpeg start failed. ret=%d", ret); | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // check ffmpeg status. | ||||||
|  |         if ((ret = ingester->cycle()) != ERROR_SUCCESS) { | ||||||
|  |             srs_error("ingest ffmpeg cycle failed. ret=%d", ret); | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // pithy print | ||||||
|  |     show_ingest_log_message(); | ||||||
|  |      | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SrsIngester::on_thread_stop() | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SrsIngester::clear_engines() | ||||||
|  | { | ||||||
|  |     std::vector<SrsIngesterFFMPEG*>::iterator it; | ||||||
|  |      | ||||||
|  |     for (it = ingesters.begin(); it != ingesters.end(); ++it) { | ||||||
|  |         SrsIngesterFFMPEG* ingester = *it; | ||||||
|  |         srs_freep(ingester); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ingesters.clear(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngester::parse() | ||||||
|  | { | ||||||
|  |     int ret = ERROR_SUCCESS; | ||||||
|  |      | ||||||
|  |     // parse ingesters | ||||||
|  |     std::vector<SrsConfDirective*> vhosts; | ||||||
|  |     _srs_config->get_vhosts(vhosts); | ||||||
|  |      | ||||||
|  |     for (int i = 0; i < (int)vhosts.size(); i++) { | ||||||
|  |         SrsConfDirective* vhost = vhosts[i]; | ||||||
|  |         if ((ret = parse_ingesters(vhost)) != ERROR_SUCCESS) { | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngester::initialize_ffmpeg(SrsFFMPEG* ffmpeg, SrsConfDirective* vhost, SrsConfDirective* ingest, SrsConfDirective* engine) | ||||||
|  | { | ||||||
|  |     int ret = ERROR_SUCCESS; | ||||||
|  |      | ||||||
|  |     std::string port; | ||||||
|  |     if (true) { | ||||||
|  |         std::vector<std::string> ip_ports = _srs_config->get_listens(); | ||||||
|  |         srs_assert(ip_ports.size() > 0); | ||||||
|  |          | ||||||
|  |         std::string ep = ip_ports[0]; | ||||||
|  |         std::string ip; | ||||||
|  |         srs_parse_endpoint(ep, ip, port); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     std::string output = _srs_config->get_engine_output(engine); | ||||||
|  |     // output stream, to other/self server | ||||||
|  |     // ie. rtmp://localhost:1935/live/livestream_sd | ||||||
|  |     output = srs_string_replace(output, "[vhost]", vhost->arg0()); | ||||||
|  |     output = srs_string_replace(output, "[port]", port); | ||||||
|  |     if (output.empty()) { | ||||||
|  |         ret = ERROR_ENCODER_NO_OUTPUT; | ||||||
|  |         srs_trace("empty output url, ingest=%s. ret=%d", ingest->arg0().c_str(), ret); | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // find the app and stream in rtmp url | ||||||
|  |     std::string url = output; | ||||||
|  |     std::string app, stream; | ||||||
|  |     size_t pos = std::string::npos; | ||||||
|  |     if ((pos = url.rfind("/")) != std::string::npos) { | ||||||
|  |         stream = url.substr(pos + 1); | ||||||
|  |         url = url.substr(0, pos); | ||||||
|  |     } | ||||||
|  |     if ((pos = url.rfind("/")) != std::string::npos) { | ||||||
|  |         app = url.substr(pos + 1); | ||||||
|  |         url = url.substr(0, pos); | ||||||
|  |     } | ||||||
|  |     if ((pos = app.rfind("?")) != std::string::npos) { | ||||||
|  |         app = app.substr(0, pos); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     std::string log_file = SRS_CONSTS_NULL_FILE; // disabled | ||||||
|  |     // write ffmpeg info to log file. | ||||||
|  |     if (_srs_config->get_ffmpeg_log_enabled()) { | ||||||
|  |         log_file = _srs_config->get_ffmpeg_log_dir(); | ||||||
|  |         log_file += "/"; | ||||||
|  |         log_file += "ffmpeg-ingest"; | ||||||
|  |         log_file += "-"; | ||||||
|  |         log_file += vhost->arg0(); | ||||||
|  |         log_file += "-"; | ||||||
|  |         log_file += app; | ||||||
|  |         log_file += "-"; | ||||||
|  |         log_file += stream; | ||||||
|  |         log_file += ".log"; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // input | ||||||
|  |     std::string input_type = _srs_config->get_ingest_input_type(ingest); | ||||||
|  |     if (input_type.empty()) { | ||||||
|  |         ret = ERROR_ENCODER_NO_INPUT; | ||||||
|  |         srs_trace("empty intput type, ingest=%s. ret=%d", ingest->arg0().c_str(), ret); | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (srs_config_ingest_is_file(input_type)) { | ||||||
|  |         std::string input_url = _srs_config->get_ingest_input_url(ingest); | ||||||
|  |         if (input_url.empty()) { | ||||||
|  |             ret = ERROR_ENCODER_NO_INPUT; | ||||||
|  |             srs_trace("empty intput url, ingest=%s. ret=%d", ingest->arg0().c_str(), ret); | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // for file, set re. | ||||||
|  |         ffmpeg->set_iparams("-re"); | ||||||
|  |      | ||||||
|  |         if ((ret = ffmpeg->initialize(input_url, output, log_file)) != ERROR_SUCCESS) { | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |     } else if (srs_config_ingest_is_stream(input_type)) { | ||||||
|  |         std::string input_url = _srs_config->get_ingest_input_url(ingest); | ||||||
|  |         if (input_url.empty()) { | ||||||
|  |             ret = ERROR_ENCODER_NO_INPUT; | ||||||
|  |             srs_trace("empty intput url, ingest=%s. ret=%d", ingest->arg0().c_str(), ret); | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // for stream, no re. | ||||||
|  |         ffmpeg->set_iparams(""); | ||||||
|  |      | ||||||
|  |         if ((ret = ffmpeg->initialize(input_url, output, log_file)) != ERROR_SUCCESS) { | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         ret = ERROR_ENCODER_INPUT_TYPE; | ||||||
|  |         srs_error("invalid ingest=%s type=%s, ret=%d",  | ||||||
|  |             ingest->arg0().c_str(), input_type.c_str(), ret); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // set output format to flv for RTMP | ||||||
|  |     ffmpeg->set_oformat("flv"); | ||||||
|  |      | ||||||
|  |     std::string vcodec = _srs_config->get_engine_vcodec(engine); | ||||||
|  |     std::string acodec = _srs_config->get_engine_acodec(engine); | ||||||
|  |     // whatever the engine config, use copy as default. | ||||||
|  |     bool engine_disabled = !engine || !_srs_config->get_engine_enabled(engine); | ||||||
|  |     if (engine_disabled || vcodec.empty() || acodec.empty()) { | ||||||
|  |         if ((ret = ffmpeg->initialize_copy()) != ERROR_SUCCESS) { | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         if ((ret = ffmpeg->initialize_transcode(engine)) != ERROR_SUCCESS) { | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     srs_trace("parse success, ingest=%s, vhost=%s",  | ||||||
|  |         ingest->arg0().c_str(), vhost->arg0().c_str()); | ||||||
|  |      | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SrsIngester::show_ingest_log_message() | ||||||
|  | { | ||||||
|  |     pprint->elapse(); | ||||||
|  |  | ||||||
|  |     if ((int)ingesters.size() <= 0) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // random choose one ingester to report. | ||||||
|  |     int index = rand() % (int)ingesters.size(); | ||||||
|  |     SrsIngesterFFMPEG* ingester = ingesters.at(index); | ||||||
|  |      | ||||||
|  |     // reportable | ||||||
|  |     if (pprint->can_print()) { | ||||||
|  |         srs_trace("-> "SRS_CONSTS_LOG_INGESTER" time=%"PRId64", ingesters=%d, #%d(alive=%ds, %s)", | ||||||
|  |             pprint->age(), (int)ingesters.size(), index, ingester->alive() / 1000, ingester->uri().c_str()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngester::on_reload_vhost_added(string vhost) | ||||||
|  | { | ||||||
|  |     int ret = ERROR_SUCCESS; | ||||||
|  |      | ||||||
|  |     SrsConfDirective* _vhost = _srs_config->get_vhost(vhost); | ||||||
|  |     if ((ret = parse_ingesters(_vhost)) != ERROR_SUCCESS) { | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     srs_trace("reload add vhost ingesters, vhost=%s", vhost.c_str()); | ||||||
|  |  | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngester::on_reload_vhost_removed(string vhost) | ||||||
|  | { | ||||||
|  |     int ret = ERROR_SUCCESS; | ||||||
|  |      | ||||||
|  |     std::vector<SrsIngesterFFMPEG*>::iterator it; | ||||||
|  |      | ||||||
|  |     for (it = ingesters.begin(); it != ingesters.end();) { | ||||||
|  |         SrsIngesterFFMPEG* ingester = *it; | ||||||
|  |          | ||||||
|  |         if (!ingester->equals(vhost)) { | ||||||
|  |             ++it; | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // stop the ffmpeg and free it. | ||||||
|  |         ingester->stop(); | ||||||
|  |          | ||||||
|  |         srs_trace("reload stop ingester, vhost=%s, id=%s", vhost.c_str(), ingester->uri().c_str()); | ||||||
|  |              | ||||||
|  |         srs_freep(ingester); | ||||||
|  |          | ||||||
|  |         // remove the item from ingesters. | ||||||
|  |         it = ingesters.erase(it); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngester::on_reload_ingest_removed(string vhost, string ingest_id) | ||||||
|  | { | ||||||
|  |     int ret = ERROR_SUCCESS; | ||||||
|  |      | ||||||
|  |     std::vector<SrsIngesterFFMPEG*>::iterator it; | ||||||
|  |      | ||||||
|  |     for (it = ingesters.begin(); it != ingesters.end();) { | ||||||
|  |         SrsIngesterFFMPEG* ingester = *it; | ||||||
|  |          | ||||||
|  |         if (!ingester->equals(vhost, ingest_id)) { | ||||||
|  |             ++it; | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // stop the ffmpeg and free it. | ||||||
|  |         ingester->stop(); | ||||||
|  |          | ||||||
|  |         srs_trace("reload stop ingester, vhost=%s, id=%s", vhost.c_str(), ingester->uri().c_str()); | ||||||
|  |              | ||||||
|  |         srs_freep(ingester); | ||||||
|  |          | ||||||
|  |         // remove the item from ingesters. | ||||||
|  |         it = ingesters.erase(it); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngester::on_reload_ingest_added(string vhost, string ingest_id) | ||||||
|  | { | ||||||
|  |     int ret = ERROR_SUCCESS; | ||||||
|  |      | ||||||
|  |     SrsConfDirective* _vhost = _srs_config->get_vhost(vhost); | ||||||
|  |     SrsConfDirective* _ingester = _srs_config->get_ingest_by_id(vhost, ingest_id); | ||||||
|  |      | ||||||
|  |     if ((ret = parse_engines(_vhost, _ingester)) != ERROR_SUCCESS) { | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     srs_trace("reload add ingester, " | ||||||
|  |         "vhost=%s, id=%s", vhost.c_str(), ingest_id.c_str()); | ||||||
|  |      | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int SrsIngester::on_reload_ingest_updated(string vhost, string ingest_id) | ||||||
|  | { | ||||||
|  |     int ret = ERROR_SUCCESS; | ||||||
|  |  | ||||||
|  |     if ((ret = on_reload_ingest_removed(vhost, ingest_id)) != ERROR_SUCCESS) { | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if ((ret = on_reload_ingest_added(vhost, ingest_id)) != ERROR_SUCCESS) { | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     srs_trace("reload updated ingester, " | ||||||
|  |         "vhost=%s, id=%s", vhost.c_str(), ingest_id.c_str()); | ||||||
|  |      | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user