diff --git a/ansiParser.hpp b/ansiParser.hpp new file mode 100644 index 0000000..fb5fd69 --- /dev/null +++ b/ansiParser.hpp @@ -0,0 +1,201 @@ +#ifndef __ANSI_H /* An extra safeguard to prevent this header from */ +#define __ANSI_H /* being included twice in the same source file */ + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#ifdef TARGET_OS_MAC +#include +#elif _WIN32 +#include +#else +#include +#endif + +#include +#include +#include + +class AnsiParser +{ +public: + + static AnsiParser* Instance() + { + if(globalInstance == 0) + { + globalInstance = new AnsiParser(); + } + return globalInstance; + } + + // Release And Clear the Singleton + static void ReleaseInstance() + { + if(globalInstance != 0) + { + delete globalInstance; + globalInstance = 0; + } + return; + } + + // Holds Screen Buffer Structure + // We want each character as a string for multi-byte UTF8 characters. + struct myScreen + { + myScreen(); + myScreen(std::string sequence, SDL_Color fg, SDL_Color bg); + std::string characterSequence; + SDL_Color foreground; + SDL_Color background; + }; + + // Screen Array. + myScreen sequenceBuffer; + std::vector screenBuffer; + + // Function for populating the Screen Buffer + void setScreenBuffer(std::string mySequence); + void scrollScreenBuffer(); + void clearScreenBufferRange(int start, int end); + void clearScreenBuffer(); + void getScreenBufferText(); + void bufferToClipboard(int startx, int starty, int numChar, int numRows); + + const char ESC = '\x1b'; + // This needs to be passed from TheTerminal instance eventually + const int TERM_HEIGHT = 25; // Temp + const int TERM_WIDTH = 80; // Temp + +#define NUM_LINES 25 // change to 50 for 80x50 ANSI's +#define MAX_PARAMS 10 + + // Control Sequence Terminators +#define CURSOR_UP 'A' +#define CURSOR_DOWN 'B' +#define CURSOR_FORWARD 'C' +#define CURSOR_BACKWARD 'D' +#define CURSOR_NEXT_LINE 'E' // XTERM +#define CURSOR_PREV_LIVE 'F' // XTERM +#define CURSOR_X_POSITION 'G' // XTERM +#define CURSOR_POSITION 'H' + +#define ERASE_DISPLAY 'J' // 2J +#define ERASE_TO_EOL 'K' + +#define DELETE_CHARACTER 'P' // Erase Character(2) + +#define REPEAT_CHARACTER 'b' // Repeat preceding character +#define LINE_POS_ABSOLUTE 'd' // Line Position Absolute [row] (default = [1,column]) (VPA). +#define CURSOR_POSITION_ALT 'f' // equivalent to 'H' +#define SET_MODE 'h' // Line Wraparound ?7h +#define SCROLL_REGION 'r' // ESC[#;#r +#define SAVE_CURSOR_POS 's' +#define RESTORE_CURSOR_POS 'u' +#define RESET_MODE 'l' +#define SET_GRAPHICS_MODE 'm' +#define ANSI_DETECTION 'n' // ESC[6n +#define SET_KEYBOARD_STRINGS 'p' + + /* Extra Notes. + ESC [ 7 ; col h Enables line wrapping at column position. If col (1-based) + * is absent, wrap at column 80. + ESC [ 7 l Disables line wrapping. Lines wraps at the end of screen buffer. + ESC [ 25 h Show text cursor. + ESC [ 25 l Hide text cursor. + */ + + int x_position; + int y_position; + + // Handles Character Repeats. + unsigned char preceedingSequence; + + // Text attributes + enum + { + // Attributes + ALL_ATTRIBUTES_OFF = 0, + BOLD_ON = 1, + UNDERSCORE = 4, + BLINK_ON = 5, + REVERSE_VIDEO_ON = 7, + CONCEALED_ON = 8, + + // Foreground colors + FG_BLACK = 30, + FG_RED = 31, + FG_GREEN = 32, + FG_YELLOW = 33, + FG_BLUE = 34, + FG_MAGENTA = 35, + FG_CYAN = 36, + FG_WHITE = 37, + + // Background colors + BG_BLACK = 40, + BG_RED = 41, + BG_GREEN = 42, + BG_YELLOW = 43, + BG_BLUE = 44, + BG_MAGENTA = 45, + BG_CYAN = 46, + BG_WHITE = 47 + }; + // Reset Static Variables values for the class + void reset(); + // Parses Straight Text input with no control sequences + void textInput(std::string buffer); + // Parses Control sequences passed in vector. (sequenceParser) + void sequenceCursorAndDisplay(); + void sequenceGraphicsModeDisplay(); + void sequenceResetAndResponses(); + void sequenceInput(std::vector sequenceParameters); + + bool isCursorActive() + { + return isCursorShown; + } + void setCursorActive(bool active) + { + isCursorShown = active; + } + +private: + + std::vector parameters; + std::string current_color; + std::string textBuffer; + + int max_x_position; + int characters_per_line; + int position; + int saved_cursor_x; + int saved_cursor_y; + int saved_attribute; + int saved_prev_attr; + int color_attribute; + int prev_color_attribute; + + bool line_wrapped; + bool cleared_the_screen; + bool isCursorShown; + + SDL_Color savedForegroundColor; + SDL_Color savedBackgroundColor; + + AnsiParser(); + ~AnsiParser(); + AnsiParser(const AnsiParser&); + AnsiParser& operator=(const AnsiParser&); + + static AnsiParser* globalInstance; +}; + +typedef AnsiParser TheAnsiParser; + +#endif diff --git a/inputHandler.hpp b/inputHandler.hpp new file mode 100644 index 0000000..4e19efb --- /dev/null +++ b/inputHandler.hpp @@ -0,0 +1,159 @@ +#ifndef __InputHandler__ +#define __InputHandler__ + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#ifdef TARGET_OS_MAC +#include +#elif _WIN32 +#include +#include +#else // LINUX +#include +#endif + +#include + +# define CTRLA 0x01 +# define CTRLB 0x02 +# define CTRLC 0x03 +# define CTRLD 0x04 +# define CTRLE 0x05 +# define CTRLF 0x06 +# define CTRLG 0x07 +# define CTRLH 0x08 +# define CTRLI 0x09 +# define CTRLJ 0x0a +# define CTRLK 0x0b +# define CTRLL 0x0c +# define CTRLM 0x0d +# define CTRLN 0x0e +# define CTRLO 0x0f +# define CTRLP 0x10 +# define CTRLQ 0x11 +# define CTRLR 0x12 +# define CTRLS 0x13 +# define CTRLT 0x14 +# define CTRLU 0x15 +# define CTRLV 0x16 +# define CTRLW 0x17 +# define CTRLX 0x18 +# define CTRLY 0x19 +# define CTRLZ 0x1a + +class InputHandler +{ +public: + static InputHandler* Instance() + { + if(globalInstance == 0) + { + globalInstance = new InputHandler(); + } + return globalInstance; + } + + // Release And Clear the Singleton + static void ReleaseInstance() + { + if(globalInstance != 0) + { + delete globalInstance; + globalInstance = 0; + } + return; + } + + // keyboard events, True if Data Available. + bool update(); + void reset() + { + inputSequence.erase(); + } + + std::string getInputSequence() const + { + return inputSequence; + } + bool isGlobalShutdown() const + { + return globalShutdown; + } + + bool isMouseSelection() const + { + return isMouseSelected; + } + + // mouse events + int getMouseSourceXPosition() const + { + return mouseSourceXPosition; + } + int getMouseSourceYPosition() const + { + return mouseSourceYPosition; + } + +private: + + void setInputSequence(std::string sequence) + { + inputSequence = sequence; + } + + bool globalShutdown; + bool isWindowMode; + int fullScreenWindowSize; + bool isMouseSelected; + int mouseSourceXPosition; + int mouseSourceYPosition; + int mouseReleaseXPosition; + int mouseReleaseYPosition; + + std::string inputSequence; // Keyboard Input + std::string inputText; // Copy/Paste Input + + InputHandler(); + ~InputHandler(); + InputHandler(const InputHandler&); + InputHandler& operator=(const InputHandler&); + + // singleton + static InputHandler* globalInstance; + + const unsigned char CTRLKEYTABLE[26] = + { + CTRLA, CTRLB, CTRLC, CTRLD, CTRLE, + CTRLF, CTRLG, CTRLH, CTRLI, CTRLJ, + CTRLK, CTRLL, CTRLM, CTRLN, CTRLO, + CTRLP, CTRLQ, CTRLR, CTRLS, CTRLT, + CTRLU, CTRLV, CTRLW, CTRLX, CTRLY, + CTRLZ + }; + + // First Break Up into Seperate Functions, + // Later Map Enum and and setup commands for the following. + void handleWindowEvents(SDL_Event &event); + bool handleTextInputEvent(SDL_Event &event); + void handleMouseButtonUpEvent(SDL_Event &event); + void handleMouseMotionEvent(SDL_Event &event); + bool handleMouseButtonDownEvent(SDL_Event &event); + bool handleShiftControlKeys(SDL_Event &event); + bool handleControlKeys(SDL_Event &event); + bool handleAlternateKeys(SDL_Event &event); + bool handleKeyPadAndFunctionKeys(SDL_Event &event); + bool handleANSIKeyMapFunctionKeys(SDL_Event &event); + bool handleVT100KeyMapFunctionKeys(SDL_Event &event); + bool handleLINUXKeyMapFunctionKeys(SDL_Event &event); + bool handleSCOKeyMapFunctionKeys(SDL_Event &event); + bool handleKeyDownEvents(SDL_Event &event); +}; +typedef InputHandler TheInputHandler; + + +#endif diff --git a/linkList.hpp b/linkList.hpp new file mode 100644 index 0000000..9002396 --- /dev/null +++ b/linkList.hpp @@ -0,0 +1,61 @@ +#ifndef __LINKLIST_H +#define __LINKLIST_H + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#include +#include + +using namespace std; + +typedef struct list_bar +{ + std::string ansiString1; + std::string ansiString2; + +} list_bar; + +typedef struct LineRec +{ + std::string data; + LineRec *nextNodeLink; + LineRec *previousNodeLink; + +} LineRec; + +typedef struct LinkList +{ + +public: + // Main List for Holding All Data + LineRec *headNode; + LineRec *currentNode; + LineRec *lastNode; + + // Passing Light bars between Interfaces + std::vector listing; + + int currentRow; + int topMargin; + int bottomMargin; + int totalLines; + int currnetLineNumber; + int currentPage; + int totalPages; + int rowsPerPage; + int currentSelection; // Current Line in Box of Selection. + + LinkList(); + ~LinkList(); + + void getVectorList(std::vector listbar); + void clearVectorList(); + void drawVectorList(unsigned long page, unsigned long list); + +} LinkList; + +# endif diff --git a/loaderParams.hpp b/loaderParams.hpp new file mode 100644 index 0000000..881492c --- /dev/null +++ b/loaderParams.hpp @@ -0,0 +1,61 @@ +#ifndef __LOADER_PARAMS__ +#define __LOADER_PARAMS__ + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#include + +class LoaderParams +{ +public: + + LoaderParams(int swidth, int sheight, int wwidth, int wheight, std::string textureID, int callbackID = 0) : + surfaceWidth(swidth), + surfaceHeight(sheight), + windowWidth(swidth), + windowHeight(sheight), + callbackID(callbackID), + textureID(textureID) + {} + + int getSurfaceWidth() const + { + return surfaceWidth; + } + int getSurfaceHeight() const + { + return surfaceHeight; + } + int getWindowWidth() const + { + return windowWidth; + } + int getWindowHeight() const + { + return windowHeight; + } + std::string getTextureID() const + { + return textureID; + } + int getCallbackID() const + { + return callbackID; + } + +private: + + int surfaceWidth; + int surfaceHeight; + int windowWidth; + int windowHeight; + int callbackID; + std::string textureID; + +}; + +#endif diff --git a/mainMenuState.hpp b/mainMenuState.hpp new file mode 100644 index 0000000..dc24f9a --- /dev/null +++ b/mainMenuState.hpp @@ -0,0 +1,101 @@ +#ifndef __MAINMENU_STATE__ +#define __MAINMENU_STATE__ + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#include +#include +#include "menuState.h" +#include "linkList.h" +#include "menuFunction.h" + +typedef struct MainMenuState_INI +{ + char INI_PATH[255]; + char INI_NAME[255]; + int TOP_MARGIN; + int BOTTOM_MARGIN; + std::string PAGE_NUMBER; + std::string PAGE_TOTAL; + std::string MORE_MESSAGE_ON; + std::string MORE_MESSAGE_TEXT_ON; + std::string MORE_MESSAGE_OFF; + std::string MORE_MESSAGE_TEXT_OFF; + std::string TEXT_COLOR; + std::string TEXT_COLOR_HILIGHT; + std::string MAX_SYSTEMS; + std::string FONT_SET; + // Theme + std::string ANSI_FILE; + std::string ANSI_HELP_FILE; + std::string THEME_NAME; + std::string MENU_PROMPT_TEXT; + // Message Read .ini File + bool ddirectory_exists(); + void ddirectory_create(); + void ddirectory_chkpar(std::string &data); + void ddirectory_check(std::string cfgdata); + bool ddirectory_parse(int idx=0); + +} MainMenuState_INI; + +/* + * This Class Holds a connection to the MenuState -> SocketState -> Term + * This is where we will initiate either Telnet or SSH + */ +class MainMenuState : public MenuState, MainMenuState_INI +{ +public: + + virtual ~MainMenuState() + { std::cout << "Shutting Down MainMenuState" << std::endl;} + virtual void update(); + virtual bool onEnter(); + virtual bool onExit(); + virtual std::string getStateID() const + { + return menuID; + } + +private: + + virtual void setCallbacks(const std::vector& callbacks); + // call back functions for menu items + static void menuToTelnet(); + static void menuToSSH(); + + std::string inputSequence; + static const std::string menuID; + + // Class Types for use + LinkList _linkList; + MenuFunction _menuFunction; + + // int numberOfCommands; // Number of Commands in Loaded Menu + // int systemActive; // System Exit + + // Dialing Directory + unsigned long LIGHTBAR_POSITION; + int directoryTopMargin; + int directoryBottomMargin; + + std::vector systemConnection; + std::vector buildDialList(); + + void readinAnsi(std::string FileName, std::string &buff); + void parseHeader(std::string FileName); + bool changeTheme(int idx); + void setupList(); + + bool readDialDirectory(); + void createDialDirectory(); + void writeDialDirectory(); + int startDialDirectory(); + +}; + +#endif diff --git a/menuFunction.hpp b/menuFunction.hpp new file mode 100644 index 0000000..377b593 --- /dev/null +++ b/menuFunction.hpp @@ -0,0 +1,128 @@ +#ifndef MenuFunction_H +#define MenuFunction_H + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#include + +typedef struct MenuRecord +{ + std::string MenuName; // menu name + std::string Directive; // normal menu text file + std::string MenuPrompt; // menu prompt + bool Lightbar; // Light-bar Menu? + +} MenuRecord; + +typedef struct CommandRecord +{ + std::string LDesc; // command description + std::string SDesc; // command string + std::string CKeys; // command execution keys + std::string CmdKeys; // command keys + std::string MString; // command data + bool LBarCmd; // Is This a Light-bar Cmd + std::string HiString; // Highlighted + std::string LoString; // Un-highlighted + uint16_t Xcoord; // Light-bar X coordinate + uint16_t Ycoord; // Light-bar Y coordinate + +} CommandRecord; + + +class MenuFunction +{ +protected: + + MenuRecord *menuRecord; + CommandRecord *commandRecord; + int numCommands; // Number of Commands in Loaded Menu + bool isSystemActive; // System Exit + +public: + + char MENUPATH[255]; + + std::string _curmenu; // Current Menu + std::string _premenu; // Previous Menu + std::string _gosub; // GoSub Menu. + + // Menu Light-bar Variables + short xPosition; // Holds X coordinate + short yPosition; // Holds Y coordinate + short numLightbarCommand; // Holds Light-bar # of choices + short choice; // Holds Current Light-bar # + + short *commandIndex; + short *commandIndexLightbar; + + unsigned long cntEscCmds; + + int sequence, secondSequence; + bool isEscapeSequence; // Is Input key Escaped char, or Normal Key + char outBuff[1024]; // Holds Formatted Light-bar Data + std::string output; // Buffer for writing all light-bars at the same time + + int commandsExecuted; // Test's for hot keys commands executed, if non pass through loop + int firstCommandsExecuted; // If we executed all FIRSTCMD and nothing is left then return + + int currentSystem; // Light-bar Starting Position for Interfaces. + // This needs access from ie Title Scan Class. + + MenuFunction(); + ~MenuFunction(); + + // Below here are Menu Processing Functions + bool isLoadNewMenu; + + void dataParseHelper(std::string &temp); + // Command Data Functions + + void commandsParse(std::string cfgdata, int idx); + int commandsExist(std::string MenuName, int idx); + int commandsCount(std::string MenuName); + int commandsReadData(std::string MenuName, int idx); + + // Menu Data Functions + int menuParseData(std::string cfgdata); + int menuReadData(std::string MenuName); + + // Read in / Load Menu and Commands + void menuReadCommands(); + void menuReload(); + int menuExists(); + void menuStart(); + void menuClearObjects(); + + void menuLightBars(char *inPut); + void menuProcess(char *mString, uint32_t area=0); + + // Menu Command Processing + void menuDoCommands(CommandRecord *cmdr); + + // Menu System IO + // ---------------------------------------------------------------------- + static void rightSpacing(char *str, int space); + static void leftSpacing(char *str, int space); + static void maskInput(char *str); + static void inputField(char *text, int &len); + + + static int getKey(); + static void getLine(char *line, // Returns Input into Line + int length, // Max Input Length of String + char *leadoff = 0, // Data to Display in Default String {Optional} + int hid = false, // If input is Echoed as hidden {Optional} + char *chlist = 0); // Valid Input Char List {Optional} + + static void ansiForegroundColor(char *data, int fg); + static void ansiBackgroundColor(char *data, int bg); + static void sequenceToAnsi(char* szString, int buffer=true); + static void displayAnsiFile(std::string fileName); +}; + +# endif diff --git a/menuState.hpp b/menuState.hpp new file mode 100644 index 0000000..b8bcbd2 --- /dev/null +++ b/menuState.hpp @@ -0,0 +1,28 @@ +#ifndef __MENU_STATE__ +#define __MENU_STATE__ + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#include "termState.h" +#include "socketState.h" + +class MenuState : public TermState +{ +public: + + virtual ~MenuState() {} + +protected: + + typedef void(*Callback)(); + virtual void setCallbacks(const std::vector& callbacks) = 0; + + std::vector callbacks; +}; + + +#endif diff --git a/sequenceParser.hpp b/sequenceParser.hpp new file mode 100644 index 0000000..e8687ff --- /dev/null +++ b/sequenceParser.hpp @@ -0,0 +1,97 @@ +#ifndef SequenceParser_H +#define SequenceParser_H + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#include +#include + +class SequenceParser +{ +public: + + // Instantiate the Singleton + static SequenceParser* Instance() + { + if(globalInstance == 0) + { + globalInstance = new SequenceParser(); + return globalInstance; + } + return globalInstance; + } + + // Release And Clear the Singleton + static void ReleaseInstance() + { + if(globalInstance != 0) + { + delete globalInstance; + globalInstance = 0; + } + return; + } + // Parser String data for ESC Sequence. + void processSequence(std::string inputString); + +private: + + // Sequence Parser State + enum + { + SEQ_NORMAL = 0, // Normal Text Data + SEQ_START = 1, // Start of ESC Sequence + SEQ_PROCESSING = 2, // Processing for Complete Sequence + SEQ_DONE = 3, // ESC Sequence Completed OK. + SEQ_ERROR = 4 // Bad Sequence, Kill it! + }; + + int sequenceState; + unsigned + char sequence; + int parameter; + bool foundSequence; + bool foundParameters; + bool invalidSequence; + bool sequenceCompleted; + int sequenceLevel; + + void processLevel0(); + void processLevel1(); + void processLevel2(); + void validateSequence(); + + // Holds the intern data while we build the sequence, + // This is needed if inputString doesn't have a complete sequence + // Then we need to append so that the string will have the + // Original first half of the already parsed sequence. + std::string sequenceBuilder; + + //Holds the breakdown of the entire sequence + std::vector params; + + // This string contains normal data passed through the sequence + // Parser, At the end of a processing loop, this data is passed + // for writing to the screen. + std::string validOutputData; + std::string::size_type + escapePosition; + + static SequenceParser* globalInstance; + + SequenceParser(); + ~SequenceParser(); + + SequenceParser(const SequenceParser&); + SequenceParser& operator=(const SequenceParser&); + +}; + +//Setup the Class Type +typedef SequenceParser TheSequenceParser; + +#endif diff --git a/socketHandler.hpp b/socketHandler.hpp new file mode 100644 index 0000000..3823b1d --- /dev/null +++ b/socketHandler.hpp @@ -0,0 +1,90 @@ +#ifndef __SocketHandler__ +#define __SocketHandler__ + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#include +#include "socketState.h" + +#ifdef TARGET_OS_MAC +#include +#elif _WIN32 +#include +#include +#else // LINUX +#include +#endif + +class SocketHandler +{ +public: + + static SocketHandler* Instance() + { + if(globalInstance == 0) + { + globalInstance = new SocketHandler(); + } + + return globalInstance; + } + + // Release And Clear the Singleton + static void ReleaseInstance() + { + if(globalInstance != 0) + { + delete globalInstance; + globalInstance = 0; + } + return; + } + + // Socket Events, True if Data Available. + int send(unsigned char *buf, Uint32 len); + int recv(char *message); + int update(); + + bool initTelnet(std::string host, int port); + bool initSSH(std::string host, int port, std::string username, std::string password); + + std::string getSocketType() const + { + return socketType; + } + bool isActive() const + { + return active; + } + void setActive(int _active) + { + active = _active; + } + void reset(); + +private: + + // Handle Blinking Cursor + int cursorBlink; + bool startBlinking; + time_t ttime, ttime2; + + SocketState *socket; + bool active; + std::string socketType; + + SocketHandler(); + ~SocketHandler(); + SocketHandler(const SocketHandler&); + SocketHandler& operator=(const SocketHandler&); + + static SocketHandler* globalInstance; + +}; +typedef SocketHandler TheSocketHandler; + +#endif diff --git a/socketState.hpp b/socketState.hpp new file mode 100644 index 0000000..e0d59af --- /dev/null +++ b/socketState.hpp @@ -0,0 +1,177 @@ + +#ifndef __MY_SOCKET__H +#define __MY_SOCKET__H + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#include "terminal.h" + +#ifdef TARGET_OS_MAC +#include +#include +#elif _WIN32 +#include +#include +#else +#include +#include +#endif + +#include + +#include +#include + +/* + * Virtual Class Container for Common access to different + * Socket And connection types. + */ +class SocketState +{ +public: + + virtual ~SocketState() + { + std::cout << "Shutting Down SocketState" << std::endl; + } + virtual int sendSocket(unsigned char *message, Uint32 len) = 0; + virtual int recvSocket(char *message)= 0; + virtual int pollSocket() = 0; + virtual bool onEnter() = 0; + virtual bool onExit() = 0; +}; + +/* + * Class for TCP Telnet Sockets + */ +class SDL_Socket : public SocketState +{ +public: + + SDL_Socket(std::string _host, int _port) : + sock(nullptr), + set(nullptr) + { + host = _host; + port = _port; + } + + virtual ~SDL_Socket() + { + std::cout << "Shutting Down SDL_SocketState" << std::endl; + } + virtual int sendSocket(unsigned char *message, Uint32 len); + virtual int recvSocket(char *message); + virtual int pollSocket(); + virtual bool onEnter(); + virtual bool onExit(); + +private: + + std::string host; + int port; + TCPsocket sock; + SDLNet_SocketSet set; + +}; + +/* + * Class for TCP FTP Sockets + */ +class FTP_Socket : public SocketState +{ +public: + + FTP_Socket(std::string _host, int _port, std::string _user, std::string _pass) + : + controlSocket(nullptr), + listenSocket(nullptr), + dataSocket(nullptr), + set(nullptr) + { + host = _host; + port = _port; + userId = _user; + password = _pass; + } + + virtual ~FTP_Socket() + { + std::cout << "Shutting Down FTP SDL_SocketState" << std::endl; + } + virtual int sendSocket(unsigned char *message, Uint32 len); + virtual int recvSocket(char *message); + virtual int pollSocket(); + virtual bool onEnter(); + virtual bool onExit(); + +private: + + std::string host; + int port; + std::string userId; + std::string password; + + TCPsocket controlSocket; + TCPsocket listenSocket; + TCPsocket dataSocket; + SDLNet_SocketSet set; + +}; + +/* + * Class for TCP SSH Connections + */ +class SSH_Socket : public SocketState +{ +public: + + SSH_Socket(std::string _host, int _port, std::string _user, std::string _pass) + : + sshChannel(nullptr), + session(nullptr) + { + host = _host; + port = _port; + userId = _user; + password = _pass; + } + + virtual ~SSH_Socket() + { + std::cout << "Shutting Down SSH_SocketState" << std::endl; + } + virtual int sendSocket(unsigned char *message, Uint32 len); + virtual int recvSocket(char *message); + virtual int pollSocket(); + virtual bool onEnter(); + virtual bool onExit(); + + // Specific Functions for SSH + int verify_knownhost(); + int authenticate_console(); + int authenticate_kbdint(); + void error() + { + std::cout << "Authentication failed: " + << ssh_get_error(session) << std::endl; + } + + +private: + + ssh_channel sshChannel; + ssh_session session; + + std::string host; + int port; + std::string userId; + std::string password; + +}; + +#endif diff --git a/sshState.hpp b/sshState.hpp new file mode 100644 index 0000000..3aaf3bd --- /dev/null +++ b/sshState.hpp @@ -0,0 +1,57 @@ +#ifndef __SSH_STATE_H_ +#define __SSH_STATE_H_ + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#ifdef TARGET_OS_MAC +#include +#elif _WIN32 +#include +#else +#include +#endif + +// Temp +#define NUM_LINES 25 + +#include +#include "menuState.h" +//#include "termObject.h" +#include "socketState.h" + +/* + * Telnet Class handles Tel-opt Negotiation + * Parsing Socket Data and Sending Through to ANSI Parser. + */ +class SSHState : public MenuState +{ +public: + + virtual ~SSHState() + { std::cout << "Shutting Down SSHState" << std::endl; } + virtual void update(); + virtual bool onEnter(); + virtual bool onExit(); + + virtual std::string getStateID() const + { + return sshID; + } + +private: + + void handleSession(); + + // Virtual Classes. + static const std::string sshID; + virtual void setCallbacks(const std::vector& callbacks); + std::string inputSequence; + bool shutdown; + +}; + +#endif diff --git a/stateParser.hpp b/stateParser.hpp new file mode 100644 index 0000000..fb73be5 --- /dev/null +++ b/stateParser.hpp @@ -0,0 +1,31 @@ +#ifndef __State_Parser__ +#define __State_Parser__ + + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#include +#include +#include "tinyxml.h" + +class TermObject; + +class StateParser +{ +public: + + StateParser() {} + ~StateParser() {} + bool parseState(const char* stateFile, std::string stateID, std::vector *pObjects, std::vector *pTextureIDs); + +private: + + void parseObjects(TiXmlElement* pStateRoot, std::vector *pObjects); // Dialing Directory are the objects. + void parseTextures(TiXmlElement* pStateRoot, std::vector *pTextureIDs); // Change to Surfaces for Fonts. +}; + +#endif diff --git a/telnetState.hpp b/telnetState.hpp new file mode 100644 index 0000000..9a7a2e0 --- /dev/null +++ b/telnetState.hpp @@ -0,0 +1,397 @@ +#ifndef __TELNET_H_ +#define __TELNET_H_ + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#ifdef TARGET_OS_MAC +#include +#include +#elif _WIN32 +#include +#include +#else +#include +#include +#endif + +// Temp +#define NUM_LINES 25 + +//Definitions for the TELNET protocol. +#define IAC 255 // interpret as command: +#define DONT 254 // you are not to use option +#define DO 253 // please, you use option +#define WONT 252 // I won't use option +#define WILL 251 // I will use option +#define SB 250 // interpret as sub-negotiation +#define GA 249 // you may reverse the line +#define EL 248 // erase the current line +#define EC 247 // erase the current character +#define AYT 246 // are you there +#define AO 245 // abort output--but let prog finish +#define IP 244 // interrupt process--permanently +#define BREAK 243 // break +#define DM 242 // data mark--for connect. cleaning +#define NOP 241 // nop +#define SE 240 // end sub negotiation +#define EOR 239 // end of record (transparent mode) +#define ABORT 238 // Abort process +#define SUSP 237 // Suspend process +#define xEOF 236 // End of file: EOF is already used... +#define SYNCH 242 // for telfunc calls + +#ifdef TELCMDS +const char *telcmds[] = +{ + "EOF", "SUSP", "ABORT", "EOR", + "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", + "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0 +}; +#else +extern const char *telcmds[]; +#endif + +#define TELCMD_FIRST xEOF +#define TELCMD_LAST IAC +#define TELCMD_OK(x) ((unsigned int)(x) <= TELCMD_LAST && \ + (unsigned int)(x) >= TELCMD_FIRST) + +#define TELCMD(x) telcmds[(x)-TELCMD_FIRST] + +// telnet options +#define TELOPT_BINARY 0 // 8-bit data path +#define TELOPT_ECHO 1 // echo +#define TELOPT_RCP 2 // prepare to reconnect +#define TELOPT_SGA 3 // suppress go ahead +#define TELOPT_NAMS 4 // approximate message size +#define TELOPT_STATUS 5 // give status +#define TELOPT_TM 6 // timing mark +#define TELOPT_RCTE 7 // remote controlled transmission and echo +#define TELOPT_NAOL 8 // negotiate about output line width +#define TELOPT_NAOP 9 // negotiate about output page size +#define TELOPT_NAOCRD 10 // negotiate about CR disposition +#define TELOPT_NAOHTS 11 // negotiate about horizontal tab-stops +#define TELOPT_NAOHTD 12 // negotiate about horizontal tab disposition +#define TELOPT_NAOFFD 13 // negotiate about form-feed disposition +#define TELOPT_NAOVTS 14 // negotiate about vertical tab stops +#define TELOPT_NAOVTD 15 // negotiate about vertical tab disposition +#define TELOPT_NAOLFD 16 // negotiate about output LF disposition +#define TELOPT_XASCII 17 // extended ASCII character set +#define TELOPT_LOGOUT 18 // force log out +#define TELOPT_BM 19 // byte macro +#define TELOPT_DET 20 // data entry terminal +#define TELOPT_SUPDUP 21 // supdup protocol +#define TELOPT_SUPDUPOUTPUT 22 // supdup output +#define TELOPT_SNDLOC 23 // send location +#define TELOPT_TTYPE 24 // terminal type +#define TELOPT_EOR 25 // end or record +#define TELOPT_TUID 26 // TACACS user identification +#define TELOPT_OUTMRK 27 // output marking +#define TELOPT_TTYLOC 28 // terminal location number +#define TELOPT_3270REGIME 29 // 3270 regime +#define TELOPT_X3PAD 30 // X.3 PAD +#define TELOPT_NAWS 31 // window size +#define TELOPT_TSPEED 32 // terminal speed +#define TELOPT_LFLOW 33 // remote flow control +#define TELOPT_LINEMODE 34 // Line-mode option +#define TELOPT_XDISPLOC 35 // X Display Location +#define TELOPT_OLD_ENVIRON 36 // Old - Environment variables +#define TELOPT_AUTHENTICATION 37 // Authenticate +#define TELOPT_ENCRYPT 38 // Encryption option +#define TELOPT_NEW_ENVIRON 39 // New - Environment variables +#define TELOPT_TN3270E 40 // RFC2355 - TN3270 Enhancements +#define TELOPT_CHARSET 42 // RFC2066 - Charset +#define TELOPT_COMPORT 44 // RFC2217 - Com Port Control +#define TELOPT_KERMIT 47 // RFC2840 - Kermit +#define TELOPT_EXOPL 255 // extended-options-list + +// MUD WIP +#define TELOPT_MSDP 69 // used to send mud server data +#define TELOPT_MSSP 70 // used to send mud server information +#define TELOPT_MCCP_1 85 // MUD zlib stream compression Version 1 +#define TELOPT_MCCP_2 86 // MUD zlib stream compression Version 2 RFC1950. +#define TELOPT_MSP 90 // used to toggle Mud Sound Protocol +#define TELOPT_MXP 91 // used to toggle Mud Extension Protocol + +#define TELOPT_FIRST TELOPT_BINARY +#define TELOPT_LAST TELOPT_KERMIT + +#define TELOPT_OK(x) ((unsigned int)(x) <= TELOPT_LAST) +#define TELOPT(x) telopts[(x)-TELOPT_FIRST] + +#define NTELOPTS (1+TELOPT_LAST) + +#ifdef TELOPTS +const char *telopts[NTELOPTS+1] = +{ + "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", + "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", + "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", + "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", + "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", + "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", + "TACACS UID", "OUTPUT MARKING", "TTYLOC", + "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW", + "LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", + "ENCRYPT", "NEW-ENVIRON", "TN3270E", "CHARSET", "COM-PORT", + "KERMIT", + 0 +}; +#endif + +// sub-option qualifiers +#define TELQUAL_IS 0 // option is... +#define TELQUAL_SEND 1 // send option +#define TELQUAL_INFO 2 // ENVIRON: informational version of IS +#define TELQUAL_REPLY 2 // AUTHENTICATION: client version of IS +#define TELQUAL_NAME 3 // AUTHENTICATION: client version of IS + +#define LFLOW_OFF 0 // Disable remote flow control +#define LFLOW_ON 1 // Enable remote flow control +#define LFLOW_RESTART_ANY 2 // Restart output on any char +#define LFLOW_RESTART_XON 3 // Restart output only on XON + +// LINE-MODE sub-options +#define LM_MODE 1 +#define LM_FORWARDMASK 2 +#define LM_SLC 3 + +#define MODE_EDIT 0x01 +#define MODE_TRAPSIG 0x02 +#define MODE_ACK 0x04 +#define MODE_SOFT_TAB 0x08 +#define MODE_LIT_ECHO 0x10 + +#define MODE_MASK 0x1f + +// Not part of protocol, but needed to simplify things... +#define MODE_FLOW 0x0100 +#define MODE_ECHO 0x0200 +#define MODE_INBIN 0x0400 +#define MODE_OUTBIN 0x0800 +#define MODE_FORCE 0x1000 + +#define SLC_SYNCH 1 +#define SLC_BRK 2 +#define SLC_IP 3 +#define SLC_AO 4 +#define SLC_AYT 5 +#define SLC_EOR 6 +#define SLC_ABORT 7 +#define SLC_EOF 8 +#define SLC_SUSP 9 +#define SLC_EC 10 +#define SLC_EL 11 +#define SLC_EW 12 +#define SLC_RP 13 +#define SLC_LNEXT 14 +#define SLC_XON 15 +#define SLC_XOFF 16 +#define SLC_FORW1 17 +#define SLC_FORW2 18 +#define SLC_MCL 19 +#define SLC_MCR 20 +#define SLC_MCWL 21 +#define SLC_MCWR 22 +#define SLC_MCBOL 23 +#define SLC_MCEOL 24 +#define SLC_INSRT 25 +#define SLC_OVER 26 +#define SLC_ECR 27 +#define SLC_EWR 28 +#define SLC_EBOL 29 +#define SLC_EEOL 30 + +#define NSLC 30 + +// For backwards compatibility, we define SLC_NAMES to be the +// list of names if SLC_NAMES is not defined. + +#define SLC_NAMELIST "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \ + "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ + "LNEXT", "XON", "XOFF", "FORW1", "FORW2", \ + "MCL", "MCR", "MCWL", "MCWR", "MCBOL", \ + "MCEOL", "INSRT", "OVER", "ECR", "EWR", \ + "EBOL", "EEOL", \ + 0 + +#ifdef SLC_NAMES +char *slc_names[] = +{ + SLC_NAMELIST +}; +#else +extern char *slc_names[]; +#define SLC_NAMES SLC_NAMELIST +#endif + +#define SLC_NAME_OK(x) ((unsigned int)(x) <= NSLC) +#define SLC_NAME(x) slc_names[x] + +#define SLC_NOSUPPORT 0 +#define SLC_CANTCHANGE 1 +#define SLC_VARIABLE 2 +#define SLC_DEFAULT 3 +#define SLC_LEVELBITS 0x03 + +#define SLC_FUNC 0 +#define SLC_FLAGS 1 +#define SLC_VALUE 2 + +#define SLC_ACK 0x80 +#define SLC_FLUSHIN 0x40 +#define SLC_FLUSHOUT 0x20 + +#define OLD_ENV_VAR 1 +#define OLD_ENV_VALUE 0 +#define NEW_ENV_VAR 0 +#define NEW_ENV_VALUE 1 +#define ENV_ESC 2 +#define ENV_USERVAR 3 + +//AUTHENTICATION suboptions + + +//Who is authenticating who ... +#define AUTH_WHO_CLIENT 0 // Client authenticating server +#define AUTH_WHO_SERVER 1 // Server authenticating client +#define AUTH_WHO_MASK 1 + +// amount of authentication done + +#define AUTH_HOW_ONE_WAY 0 +#define AUTH_HOW_MUTUAL 2 +#define AUTH_HOW_MASK 2 + +// should we be encrypting? (not yet formally standardized) + +#define AUTH_ENCRYPT_OFF 0 +#define AUTH_ENCRYPT_ON 4 +#define AUTH_ENCRYPT_MASK 4 + +#define AUTHTYPE_NULL 0 +#define AUTHTYPE_KERBEROS_V4 1 +#define AUTHTYPE_KERBEROS_V5 2 +#define AUTHTYPE_SPX 3 +#define AUTHTYPE_MINK 4 +#define AUTHTYPE_SRA 6 +#define AUTHTYPE_CNT 7 + +#define AUTHTYPE_TEST 99 + +#ifdef AUTH_NAMES +const char *authtype_names[] = +{ + "NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", nullptr, "SRA", + 0 +}; +#else +extern const char *authtype_names[]; +#endif + +#define AUTHTYPE_NAME_OK(x) ((unsigned int)(x) < AUTHTYPE_CNT) +#define AUTHTYPE_NAME(x) authtype_names[x] + +// ENCRYPTION sub-options +#define ENCRYPT_IS 0 // I pick encryption type ... +#define ENCRYPT_SUPPORT 1 // I support encryption types ... +#define ENCRYPT_REPLY 2 // Initial setup response +#define ENCRYPT_START 3 // Am starting to send encrypted +#define ENCRYPT_END 4 // Am ending encrypted +#define ENCRYPT_REQSTART 5 // Request you start encrypting +#define ENCRYPT_REQEND 6 // Request you send encrypting +#define ENCRYPT_ENC_KEYID 7 +#define ENCRYPT_DEC_KEYID 8 +#define ENCRYPT_CNT 9 + +#define ENCTYPE_ANY 0 +#define ENCTYPE_DES_CFB64 1 +#define ENCTYPE_DES_OFB64 2 +#define ENCTYPE_CNT 3 + +#ifdef ENCRYPT_NAMES +const char *encrypt_names[] = +{ + "IS", "SUPPORT", "REPLY", "START", "END", + "REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID", + 0 +}; +const char *enctype_names[] = +{ + "ANY", "DES_CFB64", "DES_OFB64", + 0 +}; +#else +extern const char *encrypt_names[]; +extern const char *enctype_names[]; +#endif + +#define ENCRYPT_NAME_OK(x) ((unsigned int)(x) < ENCRYPT_CNT) +#define ENCRYPT_NAME(x) encrypt_names[x] + +#define ENCTYPE_NAME_OK(x) ((unsigned int)(x) < ENCTYPE_CNT) +#define ENCTYPE_NAME(x) enctype_names[x] + +#include +#include "menuState.h" +#include "socketState.h" + +/* + * Telnet Class handles Tel-opt Negotiation + * Parsing Socket Data and Sending Through to ANSI Parser. + */ + + +class TelnetState : public MenuState +{ +public: + + TelnetState(); + virtual ~TelnetState() + { std::cout << "Shutting Down TelnetState" << std::endl; } + virtual void update(); + virtual bool onEnter(); + virtual bool onExit(); + virtual std::string getStateID() const + { + return telnetID; + } + +private: + + void handleSession(); + + // Global Option State for Telnet Options Parsing. + int stage; + int cmd; + bool isSGA, isBIN, isECHO; + bool didSGA, didTERM, didNAWS, didBIN, didECHO; + unsigned char opt; + + // Telnet Protocol Functions. + unsigned + char telnetOptionAcknowledge(unsigned char cmd); + unsigned + char telnetOptionDeny(unsigned char cmd); + + void telnetOptionNawsReply(); + void telnetOptionTerminalTypeReply(); + void telnetSendIAC(unsigned char command, unsigned char option); + unsigned + char telnetOptionParse(unsigned char c); + + // Virtual Classes. + static const std::string telnetID; + + virtual void setCallbacks(const std::vector& callbacks); + + std::string inputSequence; + bool shutdown; + +}; + +#endif diff --git a/termObject.hpp b/termObject.hpp new file mode 100644 index 0000000..21992da --- /dev/null +++ b/termObject.hpp @@ -0,0 +1,80 @@ +#ifndef __TERM_OBJECT__ +#define __TERM_OBJECT__ + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#include "loaderParams.h" +#include +#include + +class TermObject +{ +public: + + // base class needs virtual destructor + virtual ~TermObject() {} + virtual void load(std::unique_ptr const &Params)=0; + virtual void draw()=0; + virtual void update()=0; + virtual void clean()=0; + + // get the type of the object + virtual std::string type() = 0; + + int getSurfaceWidth() + { + return surfaceWidth; + } + int getSurfaceHeight() + { + return surfaceHeight; + } + + int getWindowWidth() + { + return windowWidth; + } + int getWindowHeight() + { + return windowHeight; + } + + // is the object currently being updated? + bool updating() + { + return isUpdating; + } + + // set whether to update the object or not + void setUpdating(bool updating) + { + isUpdating = updating; + } + +protected: + + // constructor with default initialization list + TermObject() : surfaceWidth(0), + surfaceHeight(0), + windowWidth(0), + windowHeight(0), + isUpdating(false) + { } + + // size variables + int surfaceWidth; + int surfaceHeight; + int windowWidth; + int windowHeight; + + std::string textureID; + + // common Boolean variables + bool isUpdating; +}; + +#endif diff --git a/termObjectFactory.hpp b/termObjectFactory.hpp new file mode 100644 index 0000000..f31bc35 --- /dev/null +++ b/termObjectFactory.hpp @@ -0,0 +1,82 @@ +#ifndef __TERMOBJECT_Factory__ +#define __TERMOBJECT_Factory__ + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#include +#include +#include +#include "termObject.h" + +class BaseCreator +{ +public: + + virtual TermObject* createTermObject() const = 0; + virtual ~BaseCreator() {} +}; + +class TermObjectFactory +{ +public: + + static TermObjectFactory* Instance() + { + if(globalInstance == 0) + { + globalInstance = new TermObjectFactory(); + } + return globalInstance; + } + + // Release And Clear the Singleton + static void ReleaseInstance() + { + if(globalInstance != 0) + { + delete globalInstance; + globalInstance = 0; + } + return; + } + + bool registerType(std::string typeID, BaseCreator* globalCreator) + { + std::map::iterator it = creators.find(typeID); + // if the type is already registered, do nothing + if(it != creators.end()) + { + delete globalCreator; + } + creators[typeID] = globalCreator; + return true; + } + + TermObject* create(std::string typeID) + { + std::map::iterator it = creators.find(typeID); + if(it == creators.end()) + { + std::cout << "could not find type: " << typeID << "\n"; + return nullptr; + } + BaseCreator* globalCreator = (*it).second; + return globalCreator->createTermObject(); + } + +private: + + TermObjectFactory() {} + ~TermObjectFactory() {} + + std::map creators; + static TermObjectFactory* globalInstance; +}; + +typedef TermObjectFactory TheTermObjectFactory; + +#endif diff --git a/termState.hpp b/termState.hpp new file mode 100644 index 0000000..a39910b --- /dev/null +++ b/termState.hpp @@ -0,0 +1,33 @@ +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#ifndef __TERM_STATE__ +#define __TERM_STATE__ + +#include +#include + +class TermState +{ +public: + + virtual ~TermState() {} + virtual void update() = 0; + virtual bool onEnter() = 0; + virtual bool onExit() = 0; + virtual void resume() {} + virtual std::string getStateID() const = 0; + +protected: + + TermState() : isLoadingComplete(false), isActive(false) + { } + bool isLoadingComplete; + bool isActive; + +}; + +#endif diff --git a/termStateMachine.hpp b/termStateMachine.hpp new file mode 100644 index 0000000..f0e3e4a --- /dev/null +++ b/termStateMachine.hpp @@ -0,0 +1,31 @@ +#ifndef __TERM_StateMachine__ +#define __TERM_StateMachine__ + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#include +#include +#include "termState.h" + +class TermStateMachine +{ +public: + + TermStateMachine() {} + ~TermStateMachine() { std::cout << "TermStateMachine Released" << std::endl; } + void update(); + void pushState(TermState* theState); + void changeState(TermState* theState); + void popState(); + void clean(); + std::vector& getTermStates() { return TermStates; } + +private: + std::vector TermStates; +}; + +#endif diff --git a/terminal.hpp b/terminal.hpp new file mode 100644 index 0000000..a82511d --- /dev/null +++ b/terminal.hpp @@ -0,0 +1,321 @@ +#ifndef __TERM_H_ +#define __TERM_H_ + +// EtherTerm SVN: $Id$ +// Source: $HeadURL$ +// $LastChangedDate$ +// $LastChangedRevision$ +// $LastChangedBy$ + +#ifdef TARGET_OS_MAC +#include +#ifdef _DEBBUG +#include +#endif +#elif _WIN32 +#include +#ifdef _DEBBUG +#include +#endif +#else +#include +#ifdef _DEBBUG +#include +#endif +#endif + +#include "termStateMachine.h" +#include + +class Terminal +{ +public: + + static Terminal* Instance() + { + if(globalInstance == 0) + { + globalInstance = new Terminal(); + return globalInstance; + } + return globalInstance; + } + + // Release And Clear the Singleton + static void ReleaseInstance() + { + if(globalInstance != 0) + { + delete globalInstance; + globalInstance = 0; + } + return; + } + + // Pass Starting Screen and Font Values. + bool init(const char* title, + int swidth, int sheight, + int wwidth, int wheight, + int fwidth, int fheight); + + void update(); + void clean(); + + void setProgramPath(std::string _programPath) + { + programPath = _programPath; + } + std::string getProgramPath() const + { + return programPath; + } + SDL_Renderer* getRenderer() const + { + return globalRenderer; + } + SDL_Window* getWindow() const + { + return globalWindow; + } + TermStateMachine* getStateMachine() + { + return globalTermStateMachine; + } + + // Holds current connection + typedef struct SystemConnection + { + std::string name; + std::string ip; + int port; + std::string protocol; + std::string login; + std::string password; // Make this encrypted with more time. + std::string font; + std::string keyMap; // ANSI, VT100 + + } SystemConnection; + + SystemConnection getSystemConnection() const + { + return systemConnection; + } + void setSystemConnection(SystemConnection _systemConnection) + { + systemConnection = _systemConnection; + } + void clearSystemConnection() + { + systemConnection.name.erase(); + systemConnection.ip.erase(); + systemConnection.port=0; + systemConnection.protocol.erase(); + systemConnection.login.erase(); + systemConnection.password.erase(); + systemConnection.font.erase(); + systemConnection.keyMap.erase(); + } + + bool running() + { + return isRunning; + } + void quit() + { + isRunning = false; + } + int getSurfaceWidth() const + { + return surfaceWidth; + } + int getSurfaceHeight() const + { + return surfaceHeight; + } + void setWindowWidth(int width) + { + windowWidth = width; + } + void setWindowHeight(int height) + { + windowHeight = height; + } + int getWindowWidth() const + { + return windowWidth; + } + int getWindowHeight() const + { + return windowHeight; + } + bool changingState() + { + return isChangingState; + } + void changingState(bool cs) + { + isChangingState = cs; + } + void setCurrentFont(std::string font) + { + currentFont = font; + } + std::string getCurrentFont() const + { + return currentFont; + } + bool didFontChange() const + { + return (currentFont != previousFont); + } + + + // Now for Rendering Code + void restartWindowSize(bool fullScreen); + void restartWindowRenderer(std::string mode); + void pullSelectionBuffer(int x, int y); + void clearSelectionTexture(); + void renderSelectionScreen(int x, int y); + void freeSurfaceTextures(); + bool loadBitmapImageFromPak(); + bool loadBitmapImage(std::string fontName); + + void createTexture(int textureType, SDL_Surface *surface); + void fillSurface(SDL_Surface *surface); + void convertSurface(int surfaceType); + void createSurface(int surfaceType); + + bool initSurfaceTextures(); + void setScrollRegion(int top, int bot, int terminalHeight); + void scrollRegionUp(); + void scrollScreenUp(); + void clearScreenSurface(); + void renderDeleteCharScreen(int x, int y, int num); + void renderClearLineAboveScreen(int y, int x); + void renderClearLineBelowScreen(int y, int x); + void renderClearLineScreen(int y, int start, int end); + void renderBottomScreen(); + void renderScreen(); + void renderCharScreen(int x, int y); + void renderCursorOnScreen(); + void renderCursorOffScreen(); + void drawGamaTextureScreen(); + void drawTextureScreen(); + void clearScreen(); + int compareSDL_Colors(SDL_Color &src, SDL_Color &dest); + void replaceColor(SDL_Surface *src, Uint32 foreground, Uint32 background); + void setupCursorChar(); + void drawChar(int X, int Y, int asciicode); + void drawString(int X, int Y, char text[]); + void drawCharSet(int X, int Y); + + std::vector getFontFiles() + { + return globalFontFiles; + } + + // Matched Colors with Pablo Draw. + SDL_Color black; + SDL_Color blue; + SDL_Color green; + SDL_Color cyan; + SDL_Color red; + SDL_Color magenta; + SDL_Color brown; + + SDL_Color grey; + SDL_Color darkGrey; + SDL_Color lightBlue; + SDL_Color lightGreen; + SDL_Color lightCyan; + SDL_Color lightRed; + SDL_Color lightMagenta; + SDL_Color yellow; + SDL_Color white; + + SDL_Color currentFGColor; + SDL_Color currentBGColor; + + // Scrolling Region + bool scrollRegionActive; + int topMargin; + int bottomMargin; + +private: + + SystemConnection systemConnection; + std::string programPath; + std::string windowTitle; + std::string currentFont; + std::string previousFont; + + SDL_Window* globalWindow; + SDL_Renderer* globalRenderer; + + // Surfaces + SDL_Surface* tmpSurface; // Char Cell + SDL_Surface* cursorOnSurface; // Char Cell for the cursor. + SDL_Surface* cursorOffSurface; // Char Cell for the cursor. + SDL_Surface* screenSurface; // Internal Screen Buffer + SDL_Surface* bottomSurface; // Last Line Buffer + SDL_Surface* cachedSurface; // Cached Font Surface + + // Textures + SDL_Texture* globalTexture; // Texture for User Screen + SDL_Texture* selectionTexture; // For Copy Text Selection + + std::vector surfaceList; + + // Handle Surface Alias + enum { + TEMP_SURFACE = 0, + CURSOR_ON_SURFACE, + CURSOR_OFF_SURFACE, + SCREEN_SURFACE, + BOTTOM_SURFACE, + CACHED_SURFACE + }; + + // Handle Texture Alias + enum { + GLOBAL_TEXTURE = 0, + SELECTION_TEXTURE + }; + +#ifdef _DEBBUG + TTF_Font* trueTypeFont; // UTF-8 Fonts. +#endif + + TermStateMachine* globalTermStateMachine; + Uint32 redMask, greenMask, blueMask, alphaMask; + + int surfaceWidth; + int surfaceHeight; + int windowWidth; + int windowHeight; + int surfaceBits; + + SDL_Rect displayRect; + SDL_Rect rectBackground; + + int characterWidth; + int characterHeight; + int cursorXPosition; + int cursorYPosition; + + bool isChangingState; + bool isRunning; + bool isUTF8Output; + + static Terminal* globalInstance; + std::vector globalFontFiles; + + Terminal(); + ~Terminal(); + Terminal(const Terminal&); + Terminal& operator=(const Terminal&); +}; + +typedef Terminal TheTerminal; + +#endif diff --git a/tinystr.hpp b/tinystr.hpp new file mode 100644 index 0000000..e25e4ab --- /dev/null +++ b/tinystr.hpp @@ -0,0 +1,349 @@ +/* +www.sourceforge.net/projects/tinyxml + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + + +#ifndef TIXML_USE_STL + +#ifndef TIXML_STRING_INCLUDED +#define TIXML_STRING_INCLUDED + +#include +#include + +/* The support for explicit isn't that universal, and it isn't really + required - it is used to check that the TiXmlString class isn't incorrectly + used. Be nice to old compilers and macro it here: +*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1200 ) +// Microsoft visual studio, version 6 and higher. +#define TIXML_EXPLICIT explicit +#elif defined(__GNUC__) && (__GNUC__ >= 3 ) +// GCC version 3 and higher.s +#define TIXML_EXPLICIT explicit +#else +#define TIXML_EXPLICIT +#endif + +/* + TiXmlString is an emulation of a subset of the std::string template. + Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. + Only the member functions relevant to the TinyXML project have been implemented. + The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase + a string and there's no more room, we allocate a buffer twice as big as we need. +*/ +class TiXmlString +{ +public : + // The size type used + typedef size_t size_type; + + // Error value for find primitive + static const size_type npos; // = -1; + + // TiXmlString empty constructor + TiXmlString() : rep_(&nullrep_) + { + } + + // TiXmlString copy constructor + TiXmlString(const TiXmlString & copy) : rep_(0) + { + init(copy.length()); + memcpy(start(), copy.data(), length()); + } + + // TiXmlString constructor, based on a string + TIXML_EXPLICIT TiXmlString(const char * copy) : rep_(0) + { + init(static_cast(strlen(copy))); + memcpy(start(), copy, length()); + } + + // TiXmlString constructor, based on a string + TIXML_EXPLICIT TiXmlString(const char * str, size_type len) : rep_(0) + { + init(len); + memcpy(start(), str, len); + } + + // TiXmlString destructor + ~TiXmlString() + { + quit(); + } + + TiXmlString& operator = (const char * copy) + { + return assign(copy, (size_type)strlen(copy)); + } + + TiXmlString& operator = (const TiXmlString & copy) + { + return assign(copy.start(), copy.length()); + } + + + // += operator. Maps to append + TiXmlString& operator += (const char * suffix) + { + return append(suffix, static_cast(strlen(suffix))); + } + + // += operator. Maps to append + TiXmlString& operator += (char single) + { + return append(&single, 1); + } + + // += operator. Maps to append + TiXmlString& operator += (const TiXmlString & suffix) + { + return append(suffix.data(), suffix.length()); + } + + // Convert a TiXmlString into a null-terminated char * + const char * c_str() const + { + return rep_->str; + } + + // Convert a TiXmlString into a char * (need not be null terminated). + const char * data() const + { + return rep_->str; + } + + // Return the length of a TiXmlString + size_type length() const + { + return rep_->size; + } + + // Alias for length() + size_type size() const + { + return rep_->size; + } + + // Checks if a TiXmlString is empty + bool empty() const + { + return rep_->size == 0; + } + + // Return capacity of string + size_type capacity() const + { + return rep_->capacity; + } + + // single char extraction + const char& at(size_type index) const + { + assert(index < length()); + return rep_->str[ index ]; + } + + // [] operator + char& operator [](size_type index) const + { + assert(index < length()); + return rep_->str[ index ]; + } + + // find a char in a string. Return TiXmlString::npos if not found + size_type find(char lookup) const + { + return find(lookup, 0); + } + + // find a char in a string from an offset. Return TiXmlString::npos if not found + size_type find(char tofind, size_type offset) const + { + if(offset >= length()) return npos; + + for(const char* p = c_str() + offset; *p != '\0'; ++p) + { + if(*p == tofind) return static_cast< size_type >(p - c_str()); + } + return npos; + } + + void clear() + { + //Lee: + //The original was just too strange, though correct: + // TiXmlString().swap(*this); + //Instead use the quit & re-init: + quit(); + init(0,0); + } + + /* Function to reserve a big amount of data when we know we'll need it. Be aware that this + function DOES NOT clear the content of the TiXmlString if any exists. + */ + void reserve(size_type cap); + TiXmlString& assign(const char* str, size_type len); + TiXmlString& append(const char* str, size_type len); + void swap(TiXmlString& other) + { + Rep* r = rep_; + rep_ = other.rep_; + other.rep_ = r; + } + +private: + + void init(size_type sz) + { + init(sz, sz); + } + void set_size(size_type sz) + { + rep_->str[ rep_->size = sz ] = '\0'; + } + char* start() const + { + return rep_->str; + } + char* finish() const + { + return rep_->str + rep_->size; + } + + struct Rep + { + size_type size, capacity; + char str[1]; + }; + + void init(size_type sz, size_type cap) + { + if(cap) + { + // Lee: the original form: + // rep_ = static_cast(operator new(sizeof(Rep) + cap)); + // doesn't work in some cases of new being overloaded. Switching + // to the normal allocation, although use an 'int' for systems + // that are overly picky about structure alignment. + const size_type bytesNeeded = sizeof(Rep) + cap; + const size_type intsNeeded = (bytesNeeded + sizeof(int) - 1) / sizeof(int); + rep_ = reinterpret_cast(new int[ intsNeeded ]); + rep_->str[ rep_->size = sz ] = '\0'; + rep_->capacity = cap; + } + else + { + rep_ = &nullrep_; + } + } + + void quit() + { + if(rep_ != &nullrep_) + { + // The rep_ is really an array of ints. (see the allocate, above). + // Cast it back before delete, so the compiler won't incorrectly call destructors. + delete [](reinterpret_cast(rep_)); + } + } + Rep * rep_; + static Rep nullrep_; + +} ; + + +inline bool operator == (const TiXmlString & a, const TiXmlString & b) +{ + return (a.length() == b.length()) // optimization on some platforms + && (strcmp(a.c_str(), b.c_str()) == 0); // actual compare +} +inline bool operator < (const TiXmlString & a, const TiXmlString & b) +{ + return strcmp(a.c_str(), b.c_str()) < 0; +} + +inline bool operator != (const TiXmlString & a, const TiXmlString & b) +{ + return !(a == b); +} +inline bool operator > (const TiXmlString & a, const TiXmlString & b) +{ + return b < a; +} +inline bool operator <= (const TiXmlString & a, const TiXmlString & b) +{ + return !(b < a); +} +inline bool operator >= (const TiXmlString & a, const TiXmlString & b) +{ + return !(a < b); +} + +inline bool operator == (const TiXmlString & a, const char* b) +{ + return strcmp(a.c_str(), b) == 0; +} +inline bool operator == (const char* a, const TiXmlString & b) +{ + return b == a; +} +inline bool operator != (const TiXmlString & a, const char* b) +{ + return !(a == b); +} +inline bool operator != (const char* a, const TiXmlString & b) +{ + return !(b == a); +} + +TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); +TiXmlString operator + (const TiXmlString & a, const char* b); +TiXmlString operator + (const char* a, const TiXmlString & b); + +/* + TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. + Only the operators that we need for TinyXML have been developed. +*/ +class TiXmlOutStream : public TiXmlString +{ +public : + + // TiXmlOutStream << operator. + TiXmlOutStream & operator << (const TiXmlString & in) + { + *this += in; + return *this; + } + + // TiXmlOutStream << operator. + TiXmlOutStream & operator << (const char * in) + { + *this += in; + return *this; + } + +} ; + +#endif // TIXML_STRING_INCLUDED +#endif // TIXML_USE_STL diff --git a/tinyxml.hpp b/tinyxml.hpp new file mode 100644 index 0000000..8c165e0 --- /dev/null +++ b/tinyxml.hpp @@ -0,0 +1,2231 @@ +/* +www.sourceforge.net/projects/tinyxml +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef TINYXML_INCLUDED +#define TINYXML_INCLUDED + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4530 ) +#pragma warning( disable : 4786 ) +#endif + +#include +#include +#include +#include +#include + +#define TIXML_USE_STL + +// Help out windows: +#if defined( _DEBUG ) && !defined( DEBUG ) +#define DEBUG +#endif + +#ifdef TIXML_USE_STL +#include +#include +#include +#define TIXML_STRING std::string +#else +#include "tinystr.h" +#define TIXML_STRING TiXmlString +#endif + +// Deprecated library function hell. Compilers want to use the +// new safe versions. This probably doesn't fully address the problem, +// but it gets closer. There are too many compilers for me to fully +// test. If you get compilation troubles, undefined TIXML_SAFE +#define TIXML_SAFE + +#ifdef TIXML_SAFE +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) +// Microsoft visual studio, version 2005 and higher. +#define TIXML_SNPRINTF _snprintf_s +#define TIXML_SSCANF sscanf_s +#elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) +// Microsoft visual studio, version 6 and higher. +//#pragma message( "Using _sn* functions." ) +#define TIXML_SNPRINTF _snprintf +#define TIXML_SSCANF sscanf +#elif defined(__GNUC__) && (__GNUC__ >= 3 ) +// GCC version 3 and higher.s +//#warning( "Using sn* functions." ) +#define TIXML_SNPRINTF snprintf +#define TIXML_SSCANF sscanf +#else +#define TIXML_SNPRINTF snprintf +#define TIXML_SSCANF sscanf +#endif +#endif + +class TiXmlDocument; +class TiXmlElement; +class TiXmlComment; +class TiXmlUnknown; +class TiXmlAttribute; +class TiXmlText; +class TiXmlDeclaration; +class TiXmlParsingData; + +const int TIXML_MAJOR_VERSION = 2; +const int TIXML_MINOR_VERSION = 6; +const int TIXML_PATCH_VERSION = 2; + +/* Internal structure for tracking location of items + in the XML file. +*/ +struct TiXmlCursor +{ + TiXmlCursor() + { + Clear(); + } + void Clear() + { + row = col = -1; + } + + int row; // 0 based. + int col; // 0 based. +}; + + +/** + Implements the interface to the "Visitor pattern" (see the Accept() method.) + If you call the Accept() method, it requires being passed a TiXmlVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves + are simply called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, no children of this node or its siblings will be Visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the TiXmlDocument, although all nodes support Visiting. + + You should never change the document from a callback. + + @sa TiXmlNode::Accept() +*/ +class TiXmlVisitor +{ +public: + virtual ~TiXmlVisitor() {} + /// Visit a document. + virtual bool VisitEnter(const TiXmlDocument& /*doc*/) + { + return true; + } + /// Visit a document. + virtual bool VisitExit(const TiXmlDocument& /*doc*/) + { + return true; + } + /// Visit an element. + virtual bool VisitEnter(const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/) + { + return true; + } + /// Visit an element. + virtual bool VisitExit(const TiXmlElement& /*element*/) + { + return true; + } + /// Visit a declaration + virtual bool Visit(const TiXmlDeclaration& /*declaration*/) + { + return true; + } + /// Visit a text node + virtual bool Visit(const TiXmlText& /*text*/) + { + return true; + } + /// Visit a comment node + virtual bool Visit(const TiXmlComment& /*comment*/) + { + return true; + } + /// Visit an unknown node + virtual bool Visit(const TiXmlUnknown& /*unknown*/) + { + return true; + } +}; + +// Only used by Attribute::Query functions +enum +{ + TIXML_SUCCESS, + TIXML_NO_ATTRIBUTE, + TIXML_WRONG_TYPE +}; + + +// Used by the parsing routines. +enum TiXmlEncoding +{ + TIXML_ENCODING_UNKNOWN, + TIXML_ENCODING_UTF8, + TIXML_ENCODING_LEGACY +}; + +const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; + +/** TiXmlBase is a base class for every class in TinyXml. + It does little except to establish that TinyXml classes + can be printed and provide some utility functions. + + In XML, the document and elements can contain + other elements and other types of nodes. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + A Decleration contains: Attributes (not on tree) + @endverbatim +*/ +class TiXmlBase +{ + friend class TiXmlNode; + friend class TiXmlElement; + friend class TiXmlDocument; + +public: + TiXmlBase() : userData(0) {} + virtual ~TiXmlBase() {} + + /** All TinyXml classes can print themselves to a filestream + or the string class (TiXmlString in non-STL mode, std::string + in STL mode.) Either or both cfile and str can be null. + + This is a formatted print, and will insert + tabs and newlines. + + (For an un-formatted stream, use the << operator.) + */ + virtual void Print(FILE* cfile, int depth) const = 0; + + /** The world does not agree on whether white space should be kept or + not. In order to make everyone happy, these global, static functions + are provided to set whether or not TinyXml will condense all white space + into a single space or not. The default is to condense. Note changing this + value is not thread safe. + */ + static void SetCondenseWhiteSpace(bool condense) + { + condenseWhiteSpace = condense; + } + + /// Return the current white space setting. + static bool IsWhiteSpaceCondensed() + { + return condenseWhiteSpace; + } + + /** Return the position, in the original source file, of this node or attribute. + The row and column are 1-based. (That is the first row and first column is + 1,1). If the returns values are 0 or less, then the parser does not have + a row and column value. + + Generally, the row and column value will be set when the TiXmlDocument::Load(), + TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set + when the DOM was created from operator>>. + + The values reflect the initial load. Once the DOM is modified programmatically + (by adding or changing nodes and attributes) the new values will NOT update to + reflect changes in the document. + + There is a minor performance cost to computing the row and column. Computation + can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. + + @sa TiXmlDocument::SetTabSize() + */ + int Row() const + { + return location.row + 1; + } + int Column() const + { + return location.col + 1; ///< See Row() + } + + void SetUserData(void* user) + { + userData = user; ///< Set a pointer to arbitrary user data. + } + void* GetUserData() + { + return userData; ///< Get a pointer to arbitrary user data. + } + const void* GetUserData() const + { + return userData; ///< Get a pointer to arbitrary user data. + } + + // Table that returns, for a given lead byte, the total number of bytes + // in the UTF-8 sequence. + static const int utf8ByteTable[256]; + + virtual const char* Parse(const char* p, + TiXmlParsingData* data, + TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */) = 0; + + /** Expands entities in a string. Note this should not contain the tag's '<', '>', etc, + or they will be transformed into entities! + */ + static void EncodeString(const TIXML_STRING& str, TIXML_STRING* out); + enum + { + TIXML_NO_ERROR = 0, + TIXML_ERROR, + TIXML_ERROR_OPENING_FILE, + TIXML_ERROR_PARSING_ELEMENT, + TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, + TIXML_ERROR_READING_ELEMENT_VALUE, + TIXML_ERROR_READING_ATTRIBUTES, + TIXML_ERROR_PARSING_EMPTY, + TIXML_ERROR_READING_END_TAG, + TIXML_ERROR_PARSING_UNKNOWN, + TIXML_ERROR_PARSING_COMMENT, + TIXML_ERROR_PARSING_DECLARATION, + TIXML_ERROR_DOCUMENT_EMPTY, + TIXML_ERROR_EMBEDDED_NULL, + TIXML_ERROR_PARSING_CDATA, + TIXML_ERROR_DOCUMENT_TOP_ONLY, + TIXML_ERROR_STRING_COUNT + }; + +protected: + + static const char* SkipWhiteSpace(const char*, TiXmlEncoding encoding); + + inline static bool IsWhiteSpace(char c) + { + return (isspace((unsigned char) c) || c == '\n' || c == '\r'); + } + inline static bool IsWhiteSpace(int c) + { + if(c < 256) + return IsWhiteSpace((char) c); + return false; // Again, only truly correct for English/Latin...but usually works. + } + +#ifdef TIXML_USE_STL + static bool StreamWhiteSpace(std::istream * in, TIXML_STRING * tag); + static bool StreamTo(std::istream * in, int character, TIXML_STRING * tag); +#endif + + /* Reads an XML name into the string provided. Returns + a pointer just past the last character of the name, + or 0 if the function has an error. + */ + static const char* ReadName(const char* p, TIXML_STRING* name, TiXmlEncoding encoding); + + /* Reads text. Returns a pointer past the given end tag. + Wickedly complex options, but it keeps the (sensitive) code in one place. + */ + static const char* ReadText(const char* in, // where to start + TIXML_STRING* text, // the string read + bool ignoreWhiteSpace, // whether to keep the white space + const char* endTag, // what ends this text + bool ignoreCase, // whether to ignore case in the end tag + TiXmlEncoding encoding); // the current encoding + + // If an entity has been found, transform it into a character. + static const char* GetEntity(const char* in, char* value, int* length, TiXmlEncoding encoding); + + // Get a character, while interpreting entities. + // The length can be from 0 to 4 bytes. + inline static const char* GetChar(const char* p, char* _value, int* length, TiXmlEncoding encoding) + { + assert(p); + if(encoding == TIXML_ENCODING_UTF8) + { + *length = utf8ByteTable[ *((const unsigned char*)p) ]; + assert(*length >= 0 && *length < 5); + } + else + { + *length = 1; + } + + if(*length == 1) + { + if(*p == '&') + return GetEntity(p, _value, length, encoding); + *_value = *p; + return p+1; + } + else if(*length) + { + //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), + // and the null terminator isn't needed + for(int i=0; p[i] && i<*length; ++i) + { + _value[i] = p[i]; + } + return p + (*length); + } + else + { + // Not valid text. + return 0; + } + } + + // Return true if the next characters in the stream are any of the endTag sequences. + // Ignore case only works for English, and should only be relied on when comparing + // to English words: StringEqual( p, "version", true ) is fine. + static bool StringEqual(const char* p, + const char* endTag, + bool ignoreCase, + TiXmlEncoding encoding); + + static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; + + TiXmlCursor location; + + /// Field containing a generic user pointer + void* userData; + + // None of these methods are reliable for any language except English. + // Good for approximation, not great for accuracy. + static int IsAlpha(unsigned char anyByte, TiXmlEncoding encoding); + static int IsAlphaNum(unsigned char anyByte, TiXmlEncoding encoding); + inline static int ToLower(int v, TiXmlEncoding encoding) + { + if(encoding == TIXML_ENCODING_UTF8) + { + if(v < 128) return tolower(v); + return v; + } + else + { + return tolower(v); + } + } + static void ConvertUTF32ToUTF8(unsigned long input, char* output, int* length); + +private: + TiXmlBase(const TiXmlBase&); // not implemented. + void operator=(const TiXmlBase& base); // not allowed. + + struct Entity + { + const char* str; + unsigned int strLength; + char chr; + }; + enum + { + NUM_ENTITY = 5, + MAX_ENTITY_LENGTH = 6 + + }; + static Entity entity[ NUM_ENTITY ]; + static bool condenseWhiteSpace; +}; + + +/** The parent class for everything in the Document Object Model. + (Except for attributes). + Nodes have siblings, a parent, and children. A node can be + in a document, or stand on its own. The type of a TiXmlNode + can be queried, and it can be cast to its more defined type. +*/ +class TiXmlNode : public TiXmlBase +{ + friend class TiXmlDocument; + friend class TiXmlElement; + +public: +#ifdef TIXML_USE_STL + + /** An input stream operator, for every class. Tolerant of newlines and + formatting, but doesn't expect them. + */ + friend std::istream& operator >> (std::istream& in, TiXmlNode& base); + + /** An output stream operator, for every class. Note that this outputs + without any newlines or formatting, as opposed to Print(), which + includes tabs and new lines. + + The operator<< and operator>> are not completely symmetric. Writing + a node to a stream is very well defined. You'll get a nice stream + of output, without any extra white-space or newlines. + + But reading is not as well defined. (As it always is.) If you create + a TiXmlElement (for example) and read that from an input stream, + the text needs to define an element or junk will result. This is + true of all input streams, but it's worth keeping in mind. + + A TiXmlDocument will read nodes until it reads a root element, and + all the children of that root element. + */ + friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); + + /// Appends the XML node or attribute to a std::string. + friend std::string& operator<< (std::string& out, const TiXmlNode& base); + +#endif + + /** The types of XML nodes supported by TinyXml. (All the + unsupported types are picked up by UNKNOWN.) + */ + enum NodeType + { + TINYXML_DOCUMENT, + TINYXML_ELEMENT, + TINYXML_COMMENT, + TINYXML_UNKNOWN, + TINYXML_TEXT, + TINYXML_DECLARATION, + TINYXML_TYPECOUNT + }; + + virtual ~TiXmlNode(); + + /** The meaning of 'value' changes for the specific type of + TiXmlNode. + @verbatim + Document: file name of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + + The sub-classes will wrap this function. + */ + const char *Value() const + { + return value.c_str(); + } + +#ifdef TIXML_USE_STL + /** Return Value() as a std::string. If you only use STL, + this is more efficient than calling Value(). + Only available in STL mode. + */ + const std::string& ValueStr() const + { + return value; + } +#endif + + const TIXML_STRING& ValueTStr() const + { + return value; + } + + /** Changes the value of the node. Defined as: + @verbatim + Document: file name of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + void SetValue(const char * _value) + { + value = _value; + } + +#ifdef TIXML_USE_STL + /// STL std::string form. + void SetValue(const std::string& _value) + { + value = _value; + } +#endif + + /// Delete all the children of this node. Does not affect 'this'. + void Clear(); + + /// One step up the DOM. + TiXmlNode* Parent() + { + return parent; + } + const TiXmlNode* Parent() const + { + return parent; + } + const TiXmlNode* FirstChild() const + { + return firstChild; ///< The first child of this node. Will be null if there are no children. + } + TiXmlNode* FirstChild() + { + return firstChild; + } + const TiXmlNode* FirstChild(const char * value) const; ///< The first child of this node with the matching 'value'. Will be null if none found. + /// The first child of this node with the matching 'value'. Will be null if none found. + TiXmlNode* FirstChild(const char * _value) + { + // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) + // call the method, cast the return back to non-const. + return const_cast< TiXmlNode* >((const_cast< const TiXmlNode* >(this))->FirstChild(_value)); + } + const TiXmlNode* LastChild() const + { + return lastChild; /// The last child of this node. Will be null if there are no children. + } + TiXmlNode* LastChild() + { + return lastChild; + } + + const TiXmlNode* LastChild(const char * value) const; /// The last child of this node matching 'value'. Will be null if there are no children. + TiXmlNode* LastChild(const char * _value) + { + return const_cast< TiXmlNode* >((const_cast< const TiXmlNode* >(this))->LastChild(_value)); + } + +#ifdef TIXML_USE_STL + const TiXmlNode* FirstChild(const std::string& _value) const + { + return FirstChild(_value.c_str()); ///< STL std::string form. + } + TiXmlNode* FirstChild(const std::string& _value) + { + return FirstChild(_value.c_str()); ///< STL std::string form. + } + const TiXmlNode* LastChild(const std::string& _value) const + { + return LastChild(_value.c_str()); ///< STL std::string form. + } + TiXmlNode* LastChild(const std::string& _value) + { + return LastChild(_value.c_str()); ///< STL std::string form. + } +#endif + + /** An alternate way to walk the children of a node. + One way to iterate over nodes is: + @verbatim + for( child = parent->FirstChild(); child; child = child->NextSibling() ) + @endverbatim + + IterateChildren does the same thing with the syntax: + @verbatim + child = 0; + while( child = parent->IterateChildren( child ) ) + @endverbatim + + IterateChildren takes the previous child as input and finds + the next one. If the previous child is null, it returns the + first. IterateChildren will return null when done. + */ + const TiXmlNode* IterateChildren(const TiXmlNode* previous) const; + TiXmlNode* IterateChildren(const TiXmlNode* previous) + { + return const_cast< TiXmlNode* >((const_cast< const TiXmlNode* >(this))->IterateChildren(previous)); + } + /// This flavor of IterateChildren searches for children with a particular 'value' + const TiXmlNode* IterateChildren(const char * value, const TiXmlNode* previous) const; + TiXmlNode* IterateChildren(const char * _value, const TiXmlNode* previous) + { + return const_cast< TiXmlNode* >((const_cast< const TiXmlNode* >(this))->IterateChildren(_value, previous)); + } + +#ifdef TIXML_USE_STL + const TiXmlNode* IterateChildren(const std::string& _value, const TiXmlNode* previous) const + { + return IterateChildren(_value.c_str(), previous); ///< STL std::string form. + } + TiXmlNode* IterateChildren(const std::string& _value, const TiXmlNode* previous) + { + return IterateChildren(_value.c_str(), previous); ///< STL std::string form. + } +#endif + + /** Add a new node related to this. Adds a child past the LastChild. + Returns a pointer to the new object or NULL if an error occurred. + */ + TiXmlNode* InsertEndChild(const TiXmlNode& addThis); + + + /** Add a new node related to this. Adds a child past the LastChild. + + NOTE: the node to be added is passed by pointer, and will be + henceforth owned (and deleted) by tinyXml. This method is efficient + and avoids an extra copy, but should be used with care as it + uses a different memory model than the other insert functions. + + @sa InsertEndChild + */ + TiXmlNode* LinkEndChild(TiXmlNode* addThis); + + /** Add a new node related to this. Adds a child before the specified child. + Returns a pointer to the new object or NULL if an error occurred. + */ + TiXmlNode* InsertBeforeChild(TiXmlNode* beforeThis, const TiXmlNode& addThis); + + /** Add a new node related to this. Adds a child after the specified child. + Returns a pointer to the new object or NULL if an error occurred. + */ + TiXmlNode* InsertAfterChild(TiXmlNode* afterThis, const TiXmlNode& addThis); + + /** Replace a child of this node. + Returns a pointer to the new object or NULL if an error occurred. + */ + TiXmlNode* ReplaceChild(TiXmlNode* replaceThis, const TiXmlNode& withThis); + + /// Delete a child of this node. + bool RemoveChild(TiXmlNode* removeThis); + + /// Navigate to a sibling node. + const TiXmlNode* PreviousSibling() const + { + return prev; + } + TiXmlNode* PreviousSibling() + { + return prev; + } + + /// Navigate to a sibling node. + const TiXmlNode* PreviousSibling(const char *) const; + TiXmlNode* PreviousSibling(const char *_prev) + { + return const_cast< TiXmlNode* >((const_cast< const TiXmlNode* >(this))->PreviousSibling(_prev)); + } + +#ifdef TIXML_USE_STL + const TiXmlNode* PreviousSibling(const std::string& _value) const + { + return PreviousSibling(_value.c_str()); ///< STL std::string form. + } + TiXmlNode* PreviousSibling(const std::string& _value) + { + return PreviousSibling(_value.c_str()); ///< STL std::string form. + } + const TiXmlNode* NextSibling(const std::string& _value) const + { + return NextSibling(_value.c_str()); ///< STL std::string form. + } + TiXmlNode* NextSibling(const std::string& _value) + { + return NextSibling(_value.c_str()); ///< STL std::string form. + } +#endif + + /// Navigate to a sibling node. + const TiXmlNode* NextSibling() const + { + return next; + } + TiXmlNode* NextSibling() + { + return next; + } + + /// Navigate to a sibling node with the given 'value'. + const TiXmlNode* NextSibling(const char *) const; + TiXmlNode* NextSibling(const char* _next) + { + return const_cast< TiXmlNode* >((const_cast< const TiXmlNode* >(this))->NextSibling(_next)); + } + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + const TiXmlElement* NextSiblingElement() const; + TiXmlElement* NextSiblingElement() + { + return const_cast< TiXmlElement* >((const_cast< const TiXmlNode* >(this))->NextSiblingElement()); + } + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + const TiXmlElement* NextSiblingElement(const char *) const; + TiXmlElement* NextSiblingElement(const char *_next) + { + return const_cast< TiXmlElement* >((const_cast< const TiXmlNode* >(this))->NextSiblingElement(_next)); + } + +#ifdef TIXML_USE_STL + const TiXmlElement* NextSiblingElement(const std::string& _value) const + { + return NextSiblingElement(_value.c_str()); ///< STL std::string form. + } + TiXmlElement* NextSiblingElement(const std::string& _value) + { + return NextSiblingElement(_value.c_str()); ///< STL std::string form. + } +#endif + + /// Convenience function to get through elements. + const TiXmlElement* FirstChildElement() const; + TiXmlElement* FirstChildElement() + { + return const_cast< TiXmlElement* >((const_cast< const TiXmlNode* >(this))->FirstChildElement()); + } + + /// Convenience function to get through elements. + const TiXmlElement* FirstChildElement(const char * _value) const; + TiXmlElement* FirstChildElement(const char * _value) + { + return const_cast< TiXmlElement* >((const_cast< const TiXmlNode* >(this))->FirstChildElement(_value)); + } + +#ifdef TIXML_USE_STL + const TiXmlElement* FirstChildElement(const std::string& _value) const + { + return FirstChildElement(_value.c_str()); ///< STL std::string form. + } + TiXmlElement* FirstChildElement(const std::string& _value) + { + return FirstChildElement(_value.c_str()); ///< STL std::string form. + } +#endif + + /** Query the type (as an enumerated value, above) of this node. + The possible types are: TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT, + TINYXML_UNKNOWN, TINYXML_TEXT, and TINYXML_DECLARATION. + */ + int Type() const + { + return type; + } + + /** Return a pointer to the Document this node lives in. + Returns null if not in a document. + */ + const TiXmlDocument* GetDocument() const; + TiXmlDocument* GetDocument() + { + return const_cast< TiXmlDocument* >((const_cast< const TiXmlNode* >(this))->GetDocument()); + } + + /// Returns true if this node has no children. + bool NoChildren() const + { + return !firstChild; + } + + virtual const TiXmlDocument* ToDocument() const + { + return 0; ///< Cast to a more defined type. Will return null if not of the requested type. + } + virtual const TiXmlElement* ToElement() const + { + return 0; ///< Cast to a more defined type. Will return null if not of the requested type. + } + virtual const TiXmlComment* ToComment() const + { + return 0; ///< Cast to a more defined type. Will return null if not of the requested type. + } + virtual const TiXmlUnknown* ToUnknown() const + { + return 0; ///< Cast to a more defined type. Will return null if not of the requested type. + } + virtual const TiXmlText* ToText() const + { + return 0; ///< Cast to a more defined type. Will return null if not of the requested type. + } + virtual const TiXmlDeclaration* ToDeclaration() const + { + return 0; ///< Cast to a more defined type. Will return null if not of the requested type. + } + + virtual TiXmlDocument* ToDocument() + { + return 0; ///< Cast to a more defined type. Will return null if not of the requested type. + } + virtual TiXmlElement* ToElement() + { + return 0; ///< Cast to a more defined type. Will return null if not of the requested type. + } + virtual TiXmlComment* ToComment() + { + return 0; ///< Cast to a more defined type. Will return null if not of the requested type. + } + virtual TiXmlUnknown* ToUnknown() + { + return 0; ///< Cast to a more defined type. Will return null if not of the requested type. + } + virtual TiXmlText* ToText() + { + return 0; ///< Cast to a more defined type. Will return null if not of the requested type. + } + virtual TiXmlDeclaration* ToDeclaration() + { + return 0; ///< Cast to a more defined type. Will return null if not of the requested type. + } + + /** Create an exact duplicate of this node and return it. The memory must be deleted + by the caller. + */ + virtual TiXmlNode* Clone() const = 0; + + /** Accept a hierarchical visit the nodes in the TinyXML DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the TiXmlVisitor interface. + + This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + TiXmlPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept(TiXmlVisitor* visitor) const = 0; + +protected: + TiXmlNode(NodeType _type); + + // Copy to the allocated object. Shared functionality between Clone, Copy constructor, + // and the assignment operator. + void CopyTo(TiXmlNode* target) const; + +#ifdef TIXML_USE_STL + // The real work of the input operator. + virtual void StreamIn(std::istream* in, TIXML_STRING* tag) = 0; +#endif + + // Figure out what is at *p, and parse it. Returns null if it is not an xml node. + TiXmlNode* Identify(const char* start, TiXmlEncoding encoding); + + TiXmlNode* parent; + NodeType type; + + TiXmlNode* firstChild; + TiXmlNode* lastChild; + + TIXML_STRING value; + + TiXmlNode* prev; + TiXmlNode* next; + +private: + TiXmlNode(const TiXmlNode&); // not implemented. + void operator=(const TiXmlNode& base); // not allowed. +}; + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not TiXmlNodes, since they are not + part of the tinyXML document object model. There are other + suggested ways to look at this problem. +*/ +class TiXmlAttribute : public TiXmlBase +{ + friend class TiXmlAttributeSet; + +public: + /// Construct an empty attribute. + TiXmlAttribute() : TiXmlBase() + { + document = 0; + prev = next = 0; + } + +#ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlAttribute(const std::string& _name, const std::string& _value) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } +#endif + + /// Construct an attribute with a name and value. + TiXmlAttribute(const char * _name, const char * _value) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + + const char* Name() const + { + return name.c_str(); ///< Return the name of this attribute. + } + const char* Value() const + { + return value.c_str(); ///< Return the value of this attribute. + } +#ifdef TIXML_USE_STL + const std::string& ValueStr() const + { + return value; ///< Return the value of this attribute. + } +#endif + int IntValue() const; ///< Return the value of this attribute, converted to an integer. + double DoubleValue() const; ///< Return the value of this attribute, converted to a double. + + // Get the tinyxml string representation + const TIXML_STRING& NameTStr() const + { + return name; + } + + /** QueryIntValue examines the value string. It is an alternative to the + IntValue() method with richer error checking. + If the value is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. + + A specialized but useful call. Note that for success it returns 0, + which is the opposite of almost all other TinyXml calls. + */ + int QueryIntValue(int* _value) const; + /// QueryDoubleValue examines the value string. See QueryIntValue(). + int QueryDoubleValue(double* _value) const; + + void SetName(const char* _name) + { + name = _name; ///< Set the name of this attribute. + } + void SetValue(const char* _value) + { + value = _value; ///< Set the value. + } + + void SetIntValue(int _value); ///< Set the value from an integer. + void SetDoubleValue(double _value); ///< Set the value from a double. + +#ifdef TIXML_USE_STL + /// STL std::string form. + void SetName(const std::string& _name) + { + name = _name; + } + /// STL std::string form. + void SetValue(const std::string& _value) + { + value = _value; + } +#endif + + /// Get the next sibling attribute in the DOM. Returns null at end. + const TiXmlAttribute* Next() const; + TiXmlAttribute* Next() + { + return const_cast< TiXmlAttribute* >((const_cast< const TiXmlAttribute* >(this))->Next()); + } + + /// Get the previous sibling attribute in the DOM. Returns null at beginning. + const TiXmlAttribute* Previous() const; + TiXmlAttribute* Previous() + { + return const_cast< TiXmlAttribute* >((const_cast< const TiXmlAttribute* >(this))->Previous()); + } + + bool operator==(const TiXmlAttribute& rhs) const + { + return rhs.name == name; + } + bool operator<(const TiXmlAttribute& rhs) const + { + return name < rhs.name; + } + bool operator>(const TiXmlAttribute& rhs) const + { + return name > rhs.name; + } + + /* Attribute parsing starts: first letter of the name + returns: the next char after the value end quote + */ + virtual const char* Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding encoding); + + // Prints this Attribute to a FILE stream. + virtual void Print(FILE* cfile, int depth) const + { + Print(cfile, depth, 0); + } + void Print(FILE* cfile, int depth, TIXML_STRING* str) const; + + // [internal use] + // Set the document pointer so the attribute can report errors. + void SetDocument(TiXmlDocument* doc) + { + document = doc; + } + +private: + TiXmlAttribute(const TiXmlAttribute&); // not implemented. + void operator=(const TiXmlAttribute& base); // not allowed. + + TiXmlDocument* document; // A pointer back to a document, for error reporting. + TIXML_STRING name; + TIXML_STRING value; + TiXmlAttribute* prev; + TiXmlAttribute* next; +}; + + +/* A class used to manage a group of attributes. + It is only used internally, both by the ELEMENT and the DECLARATION. + + The set can be changed transparent to the Element and Declaration + classes that use it, but NOT transparent to the Attribute + which has to implement a next() and previous() method. Which makes + it a bit problematic and prevents the use of STL. + + This version is implemented with circular lists because: + - I like circular lists + - it demonstrates some independence from the (typical) doubly linked list. +*/ +class TiXmlAttributeSet +{ +public: + TiXmlAttributeSet(); + ~TiXmlAttributeSet(); + + void Add(TiXmlAttribute* attribute); + void Remove(TiXmlAttribute* attribute); + + const TiXmlAttribute* First() const + { + return (sentinel.next == &sentinel) ? 0 : sentinel.next; + } + TiXmlAttribute* First() + { + return (sentinel.next == &sentinel) ? 0 : sentinel.next; + } + const TiXmlAttribute* Last() const + { + return (sentinel.prev == &sentinel) ? 0 : sentinel.prev; + } + TiXmlAttribute* Last() + { + return (sentinel.prev == &sentinel) ? 0 : sentinel.prev; + } + + TiXmlAttribute* Find(const char* _name) const; + TiXmlAttribute* FindOrCreate(const char* _name); + +# ifdef TIXML_USE_STL + TiXmlAttribute* Find(const std::string& _name) const; + TiXmlAttribute* FindOrCreate(const std::string& _name); +# endif + + +private: + //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), + //*ME: this class must be also use a hidden/disabled copy-constructor !!! + TiXmlAttributeSet(const TiXmlAttributeSet&); // not allowed + void operator=(const TiXmlAttributeSet&); // not allowed (as TiXmlAttribute) + + TiXmlAttribute sentinel; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TiXmlElement : public TiXmlNode +{ +public: + /// Construct an element. + TiXmlElement(const char * in_value); + +#ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlElement(const std::string& _value); +#endif + + TiXmlElement(const TiXmlElement&); + + TiXmlElement& operator=(const TiXmlElement& base); + + virtual ~TiXmlElement(); + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + */ + const char* Attribute(const char* name) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an integer, + the integer value will be put in the return 'i', if 'i' + is non-null. + */ + const char* Attribute(const char* name, int* i) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an double, + the double value will be put in the return 'd', if 'd' + is non-null. + */ + const char* Attribute(const char* name, double* d) const; + + /** QueryIntAttribute examines the attribute - it is an alternative to the + Attribute() method with richer error checking. + If the attribute is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. If the attribute + does not exist, then TIXML_NO_ATTRIBUTE is returned. + */ + int QueryIntAttribute(const char* name, int* _value) const; + /// QueryUnsignedAttribute examines the attribute - see QueryIntAttribute(). + int QueryUnsignedAttribute(const char* name, unsigned* _value) const; + /** QueryBoolAttribute examines the attribute - see QueryIntAttribute(). + Note that '1', 'true', or 'yes' are considered true, while '0', 'false' + and 'no' are considered false. + */ + int QueryBoolAttribute(const char* name, bool* _value) const; + /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). + int QueryDoubleAttribute(const char* name, double* _value) const; + /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). + int QueryFloatAttribute(const char* name, float* _value) const + { + double d; + int result = QueryDoubleAttribute(name, &d); + if(result == TIXML_SUCCESS) + { + *_value = (float)d; + } + return result; + } + +#ifdef TIXML_USE_STL + /// QueryStringAttribute examines the attribute - see QueryIntAttribute(). + int QueryStringAttribute(const char* name, std::string* _value) const + { + const char* cstr = Attribute(name); + if(cstr) + { + *_value = std::string(cstr); + return TIXML_SUCCESS; + } + return TIXML_NO_ATTRIBUTE; + } + + /** Template form of the attribute query which will try to read the + attribute into the specified type. Very easy, very powerful, but + be careful to make sure to call this with the correct type. + + NOTE: This method doesn't work correctly for 'string' types that contain spaces. + + @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE + */ + template< typename T > int QueryValueAttribute(const std::string& name, T* outValue) const + { + const TiXmlAttribute* node = attributeSet.Find(name); + if(!node) + return TIXML_NO_ATTRIBUTE; + + std::stringstream sstream(node->ValueStr()); + sstream >> *outValue; + if(!sstream.fail()) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; + } + + int QueryValueAttribute(const std::string& name, std::string* outValue) const + { + const TiXmlAttribute* node = attributeSet.Find(name); + if(!node) + return TIXML_NO_ATTRIBUTE; + *outValue = node->ValueStr(); + return TIXML_SUCCESS; + } +#endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute(const char* name, const char * _value); + +#ifdef TIXML_USE_STL + const std::string* Attribute(const std::string& name) const; + const std::string* Attribute(const std::string& name, int* i) const; + const std::string* Attribute(const std::string& name, double* d) const; + int QueryIntAttribute(const std::string& name, int* _value) const; + int QueryDoubleAttribute(const std::string& name, double* _value) const; + + /// STL std::string form. + void SetAttribute(const std::string& name, const std::string& _value); + ///< STL std::string form. + void SetAttribute(const std::string& name, int _value); + ///< STL std::string form. + void SetDoubleAttribute(const std::string& name, double value); +#endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute(const char * name, int value); + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetDoubleAttribute(const char * name, double value); + + /** Deletes an attribute with the given name. + */ + void RemoveAttribute(const char * name); +#ifdef TIXML_USE_STL + void RemoveAttribute(const std::string& name) + { + RemoveAttribute(name.c_str()); ///< STL std::string form. + } +#endif + + const TiXmlAttribute* FirstAttribute() const + { + return attributeSet.First(); ///< Access the first attribute in this element. + } + TiXmlAttribute* FirstAttribute() + { + return attributeSet.First(); + } + const TiXmlAttribute* LastAttribute() const + { + return attributeSet.Last(); ///< Access the last attribute in this element. + } + TiXmlAttribute* LastAttribute() + { + return attributeSet.Last(); + } + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the TiXmlText child + and accessing it directly. + + If the first child of 'this' is a TiXmlText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + This is text + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + This is text + @endverbatim + GetText() will return "This is ". + + WARNING: GetText() accesses a child node - don't become confused with the + similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are + safe type casts on the referenced node. + */ + const char* GetText() const; + + /// Creates a new Element and returns it - the returned element is a copy. + virtual TiXmlNode* Clone() const; + // Print the Element to a FILE stream. + virtual void Print(FILE* cfile, int depth) const; + + /* Attribute parsing starts: next char past '<' + returns: next char past '>' + */ + virtual const char* Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding encoding); + + virtual const TiXmlElement* ToElement() const + { + return this; ///< Cast to a more defined type. Will return null not of the requested type. + } + virtual TiXmlElement* ToElement() + { + return this; ///< Cast to a more defined type. Will return null not of the requested type. + } + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept(TiXmlVisitor* visitor) const; + +protected: + + void CopyTo(TiXmlElement* target) const; + void ClearThis(); // like clear, but initializes 'this' object as well + + // Used to be public [internal use] +#ifdef TIXML_USE_STL + virtual void StreamIn(std::istream * in, TIXML_STRING * tag); +#endif + /* [internal use] + Reads the "value" of the element -- another element, or text. + This should terminate with the current end tag. + */ + const char* ReadValue(const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding); + +private: + TiXmlAttributeSet attributeSet; +}; + + +/** An XML comment. +*/ +class TiXmlComment : public TiXmlNode +{ +public: + /// Constructs an empty comment. + TiXmlComment() : TiXmlNode(TiXmlNode::TINYXML_COMMENT) {} + /// Construct a comment from text. + TiXmlComment(const char* _value) : TiXmlNode(TiXmlNode::TINYXML_COMMENT) + { + SetValue(_value); + } + TiXmlComment(const TiXmlComment&); + TiXmlComment& operator=(const TiXmlComment& base); + + virtual ~TiXmlComment() {} + + /// Returns a copy of this Comment. + virtual TiXmlNode* Clone() const; + // Write this Comment to a FILE stream. + virtual void Print(FILE* cfile, int depth) const; + + /* Attribute parsing starts: at the ! of the !-- + returns: next char past '>' + */ + virtual const char* Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding encoding); + + virtual const TiXmlComment* ToComment() const + { + return this; ///< Cast to a more defined type. Will return null not of the requested type. + } + virtual TiXmlComment* ToComment() + { + return this; ///< Cast to a more defined type. Will return null not of the requested type. + } + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept(TiXmlVisitor* visitor) const; + +protected: + void CopyTo(TiXmlComment* target) const; + + // used to be public +#ifdef TIXML_USE_STL + virtual void StreamIn(std::istream * in, TIXML_STRING * tag); +#endif +// virtual void StreamOut( TIXML_OSTREAM * out ) const; + +private: + +}; + + +/** XML text. A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCDATA() and query it with CDATA(). +*/ +class TiXmlText : public TiXmlNode +{ + friend class TiXmlElement; +public: + /** Constructor for text element. By default, it is treated as + normal, encoded text. If you want it be output as a CDATA text + element, set the parameter _cdata to 'true' + */ + TiXmlText(const char * initValue) : TiXmlNode(TiXmlNode::TINYXML_TEXT) + { + SetValue(initValue); + cdata = false; + } + virtual ~TiXmlText() {} + +#ifdef TIXML_USE_STL + /// Constructor. + TiXmlText(const std::string& initValue) : TiXmlNode(TiXmlNode::TINYXML_TEXT) + { + SetValue(initValue); + cdata = false; + } +#endif + + TiXmlText(const TiXmlText& copy) : TiXmlNode(TiXmlNode::TINYXML_TEXT) + { + copy.CopyTo(this); + } + TiXmlText& operator=(const TiXmlText& base) + { + base.CopyTo(this); + return *this; + } + + // Write this text object to a FILE stream. + virtual void Print(FILE* cfile, int depth) const; + + /// Queries whether this represents text using a CDATA section. + bool CDATA() const + { + return cdata; + } + /// Turns on or off a CDATA representation of text. + void SetCDATA(bool _cdata) + { + cdata = _cdata; + } + + virtual const char* Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding encoding); + + virtual const TiXmlText* ToText() const + { + return this; ///< Cast to a more defined type. Will return null not of the requested type. + } + virtual TiXmlText* ToText() + { + return this; ///< Cast to a more defined type. Will return null not of the requested type. + } + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept(TiXmlVisitor* content) const; + +protected : + /// [internal use] Creates a new Element and returns it. + virtual TiXmlNode* Clone() const; + void CopyTo(TiXmlText* target) const; + + bool Blank() const; // returns true if all white space and new lines + // [internal use] +#ifdef TIXML_USE_STL + virtual void StreamIn(std::istream * in, TIXML_STRING * tag); +#endif + +private: + bool cdata; // true if this should be input and output as a CDATA style text element +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXml will happily read or write files without a declaration, + however. There are 3 possible attributes to the declaration: + version, encoding, and standalone. + + Note: In this version of the code, the attributes are + handled as special cases, not generic attributes, simply + because there can only be at most 3 and they are always the same. +*/ +class TiXmlDeclaration : public TiXmlNode +{ +public: + /// Construct an empty declaration. + TiXmlDeclaration() : TiXmlNode(TiXmlNode::TINYXML_DECLARATION) {} + +#ifdef TIXML_USE_STL + /// Constructor. + TiXmlDeclaration(const std::string& _version, + const std::string& _encoding, + const std::string& _standalone); +#endif + + /// Construct. + TiXmlDeclaration(const char* _version, + const char* _encoding, + const char* _standalone); + + TiXmlDeclaration(const TiXmlDeclaration& copy); + TiXmlDeclaration& operator=(const TiXmlDeclaration& copy); + + virtual ~TiXmlDeclaration() {} + + /// Version. Will return an empty string if none was found. + const char *Version() const + { + return version.c_str(); + } + /// Encoding. Will return an empty string if none was found. + const char *Encoding() const + { + return encoding.c_str(); + } + /// Is this a standalone document? + const char *Standalone() const + { + return standalone.c_str(); + } + + /// Creates a copy of this Declaration and returns it. + virtual TiXmlNode* Clone() const; + // Print this declaration to a FILE stream. + virtual void Print(FILE* cfile, int depth, TIXML_STRING* str) const; + virtual void Print(FILE* cfile, int depth) const + { + Print(cfile, depth, 0); + } + + virtual const char* Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding encoding); + + virtual const TiXmlDeclaration* ToDeclaration() const + { + return this; ///< Cast to a more defined type. Will return null not of the requested type. + } + virtual TiXmlDeclaration* ToDeclaration() + { + return this; ///< Cast to a more defined type. Will return null not of the requested type. + } + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept(TiXmlVisitor* visitor) const; + +protected: + void CopyTo(TiXmlDeclaration* target) const; + // used to be public +#ifdef TIXML_USE_STL + virtual void StreamIn(std::istream * in, TIXML_STRING * tag); +#endif + +private: + + TIXML_STRING version; + TIXML_STRING encoding; + TIXML_STRING standalone; +}; + + +/** Any tag that tinyXml doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into TiXmlUnknowns. +*/ +class TiXmlUnknown : public TiXmlNode +{ +public: + TiXmlUnknown() : TiXmlNode(TiXmlNode::TINYXML_UNKNOWN) {} + virtual ~TiXmlUnknown() {} + + TiXmlUnknown(const TiXmlUnknown& copy) : TiXmlNode(TiXmlNode::TINYXML_UNKNOWN) + { + copy.CopyTo(this); + } + TiXmlUnknown& operator=(const TiXmlUnknown& copy) + { + copy.CopyTo(this); + return *this; + } + + /// Creates a copy of this Unknown and returns it. + virtual TiXmlNode* Clone() const; + // Print this Unknown to a FILE stream. + virtual void Print(FILE* cfile, int depth) const; + + virtual const char* Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding encoding); + + virtual const TiXmlUnknown* ToUnknown() const + { + return this; ///< Cast to a more defined type. Will return null not of the requested type. + } + virtual TiXmlUnknown* ToUnknown() + { + return this; ///< Cast to a more defined type. Will return null not of the requested type. + } + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept(TiXmlVisitor* content) const; + +protected: + void CopyTo(TiXmlUnknown* target) const; + +#ifdef TIXML_USE_STL + virtual void StreamIn(std::istream * in, TIXML_STRING * tag); +#endif + +private: + +}; + + +/** Always the top level node. A document binds together all the + XML pieces. It can be saved, loaded, and printed to the screen. + The 'value' of a document node is the xml file name. +*/ +class TiXmlDocument : public TiXmlNode +{ +public: + /// Create an empty document, that has no name. + TiXmlDocument(); + /// Create a document with a name. The name of the document is also the filename of the xml. + TiXmlDocument(const char * documentName); + +#ifdef TIXML_USE_STL + /// Constructor. + TiXmlDocument(const std::string& documentName); +#endif + + TiXmlDocument(const TiXmlDocument& copy); + TiXmlDocument& operator=(const TiXmlDocument& copy); + + virtual ~TiXmlDocument() {} + + /** Load a file using the current document value. + Returns true if successful. Will delete any existing + document data before loading. + */ + bool LoadFile(TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); + /// Save a file using the current document value. Returns true if successful. + bool SaveFile() const; + /// Load a file using the given file name. Returns true if successful. + bool LoadFile(const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); + /// Save a file using the given file name. Returns true if successful. + bool SaveFile(const char * filename) const; + /** Load a file using the given FILE*. Returns true if successful. Note that this method + doesn't stream - the entire object pointed at by the FILE* + will be interpreted as an XML file. TinyXML doesn't stream in XML from the current + file location. Streaming may be added in the future. + */ + bool LoadFile(FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); + /// Save a file using the given FILE*. Returns true if successful. + bool SaveFile(FILE*) const; + +#ifdef TIXML_USE_STL + bool LoadFile(const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING) ///< STL std::string version. + { + return LoadFile(filename.c_str(), encoding); + } + bool SaveFile(const std::string& filename) const ///< STL std::string version. + { + return SaveFile(filename.c_str()); + } +#endif + + /** Parse the given null terminated block of xml data. Passing in an encoding to this + method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml + to use that encoding, regardless of what TinyXml might otherwise try to detect. + */ + virtual const char* Parse(const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); + + /** Get the root element -- the only top level element -- of the document. + In well formed XML, there should only be one. TinyXml is tolerant of + multiple elements at the document level. + */ + const TiXmlElement* RootElement() const + { + return FirstChildElement(); + } + TiXmlElement* RootElement() + { + return FirstChildElement(); + } + + /** If an error occurs, Error will be set to true. Also, + - The ErrorId() will contain the integer identifier of the error (not generally useful) + - The ErrorDesc() method will return the name of the error. (very useful) + - The ErrorRow() and ErrorCol() will return the location of the error (if known) + */ + bool Error() const + { + return error; + } + + /// Contains a textual (English) description of the error if one occurs. + const char * ErrorDesc() const + { + return errorDesc.c_str(); + } + + /** Generally, you probably want the error string ( ErrorDesc() ). But if you + prefer the ErrorId, this function will fetch it. + */ + int ErrorId() const + { + return errorId; + } + + /** Returns the location (if known) of the error. The first column is column 1, + and the first row is row 1. A value of 0 means the row and column wasn't applicable + (memory errors, for example, have no row/column) or the parser lost the error. (An + error in the error reporting, in that case.) + + @sa SetTabSize, Row, Column + */ + int ErrorRow() const + { + return errorLocation.row+1; + } + int ErrorCol() const + { + return errorLocation.col+1; ///< The column where the error occurred. See ErrorRow() + } + + /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) + to report the correct values for row and column. It does not change the output + or input in any way. + + By calling this method, with a tab size + greater than 0, the row and column of each node and attribute is stored + when the file is loaded. Very useful for tracking the DOM back in to + the source file. + + The tab size is required for calculating the location of nodes. If not + set, the default of 4 is used. The tab-size is set per document. Setting + the tab-size to 0 disables row/column tracking. + + Note that row and column tracking is not supported when using operator>>. + + The tab size needs to be enabled before the parse or load. Correct usage: + @verbatim + TiXmlDocument doc; + doc.SetTabSize( 8 ); + doc.Load( "myfile.xml" ); + @endverbatim + + @sa Row, Column + */ + void SetTabSize(int _tabsize) + { + tabsize = _tabsize; + } + + int TabSize() const + { + return tabsize; + } + + /** If you have handled the error, it can be reset with this call. The error + state is automatically cleared if you Parse a new XML block. + */ + void ClearError() + { + error = false; + errorId = 0; + errorDesc = ""; + errorLocation.row = errorLocation.col = 0; + //errorLocation.last = 0; + } + + /** Write the document to standard out using formatted printing ("pretty print"). */ + void Print() const + { + Print(stdout, 0); + } + + /* Write the document to a string using formatted printing ("pretty print"). This + will allocate a character array (new char[]) and return it as a pointer. The + calling code pust call delete[] on the return char* to avoid a memory leak. + */ + //char* PrintToMemory() const; + + /// Print this Document to a FILE stream. + virtual void Print(FILE* cfile, int depth = 0) const; + // [internal use] + void SetError(int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding); + + virtual const TiXmlDocument* ToDocument() const + { + return this; ///< Cast to a more defined type. Will return null not of the requested type. + } + virtual TiXmlDocument* ToDocument() + { + return this; ///< Cast to a more defined type. Will return null not of the requested type. + } + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept(TiXmlVisitor* content) const; + +protected : + // [internal use] + virtual TiXmlNode* Clone() const; +#ifdef TIXML_USE_STL + virtual void StreamIn(std::istream * in, TIXML_STRING * tag); +#endif + +private: + void CopyTo(TiXmlDocument* target) const; + + bool error; + int errorId; + TIXML_STRING errorDesc; + int tabsize; + TiXmlCursor errorLocation; + bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. +}; + + +/** + A TiXmlHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + TiXmlElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + TiXmlElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + TiXmlElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + TiXmlElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity + of such code. A TiXmlHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + TiXmlHandle docHandle( &document ); + TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + TiXmlHandle handleCopy = handle; + @endverbatim + + What they should not be used for is iteration: + + @verbatim + int i=0; + while ( true ) + { + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); + if ( !child ) + break; + // do something + ++i; + } + @endverbatim + + It seems reasonable, but it is in fact two embedded while loops. The Child method is + a linear walk to find the element, so this code would iterate much more than it needs + to. Instead, prefer: + + @verbatim + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); + + for( child; child; child=child->NextSiblingElement() ) + { + // do something + } + @endverbatim +*/ +class TiXmlHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + TiXmlHandle(TiXmlNode* _node) + { + this->node = _node; + } + /// Copy constructor + TiXmlHandle(const TiXmlHandle& ref) + { + this->node = ref.node; + } + TiXmlHandle operator=(const TiXmlHandle& ref) + { + if(&ref != this) this->node = ref.node; + return *this; + } + + /// Return a handle to the first child node. + TiXmlHandle FirstChild() const; + /// Return a handle to the first child node with the given name. + TiXmlHandle FirstChild(const char * value) const; + /// Return a handle to the first child element. + TiXmlHandle FirstChildElement() const; + /// Return a handle to the first child element with the given name. + TiXmlHandle FirstChildElement(const char * value) const; + + /** Return a handle to the "index" child with the given name. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child(const char* value, int index) const; + /** Return a handle to the "index" child. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child(int index) const; + /** Return a handle to the "index" child element with the given name. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement(const char* value, int index) const; + /** Return a handle to the "index" child element. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement(int index) const; + +#ifdef TIXML_USE_STL + TiXmlHandle FirstChild(const std::string& _value) const + { + return FirstChild(_value.c_str()); + } + TiXmlHandle FirstChildElement(const std::string& _value) const + { + return FirstChildElement(_value.c_str()); + } + + TiXmlHandle Child(const std::string& _value, int index) const + { + return Child(_value.c_str(), index); + } + TiXmlHandle ChildElement(const std::string& _value, int index) const + { + return ChildElement(_value.c_str(), index); + } +#endif + + /** Return the handle as a TiXmlNode. This may return null. + */ + TiXmlNode* ToNode() const + { + return node; + } + /** Return the handle as a TiXmlElement. This may return null. + */ + TiXmlElement* ToElement() const + { + return ((node && node->ToElement()) ? node->ToElement() : 0); + } + /** Return the handle as a TiXmlText. This may return null. + */ + TiXmlText* ToText() const + { + return ((node && node->ToText()) ? node->ToText() : 0); + } + /** Return the handle as a TiXmlUnknown. This may return null. + */ + TiXmlUnknown* ToUnknown() const + { + return ((node && node->ToUnknown()) ? node->ToUnknown() : 0); + } + + /** @deprecated use ToNode. + Return the handle as a TiXmlNode. This may return null. + */ + TiXmlNode* Node() const + { + return ToNode(); + } + /** @deprecated use ToElement. + Return the handle as a TiXmlElement. This may return null. + */ + TiXmlElement* Element() const + { + return ToElement(); + } + /** @deprecated use ToText() + Return the handle as a TiXmlText. This may return null. + */ + TiXmlText* Text() const + { + return ToText(); + } + /** @deprecated use ToUnknown() + Return the handle as a TiXmlUnknown. This may return null. + */ + TiXmlUnknown* Unknown() const + { + return ToUnknown(); + } + +private: + TiXmlNode* node; +}; + + +/** Print to memory functionality. The TiXmlPrinter is useful when you need to: + + -# Print to memory (especially in non-STL mode) + -# Control formatting (line endings, etc.) + + When constructed, the TiXmlPrinter is in its default "pretty printing" mode. + Before calling Accept() you can call methods to control the printing + of the XML document. After TiXmlNode::Accept() is called, the printed document can + be accessed via the CStr(), Str(), and Size() methods. + + TiXmlPrinter uses the Visitor API. + @verbatim + TiXmlPrinter printer; + printer.SetIndent( " " ); + + doc.Accept( &printer ); + fprintf( stdout, "%s", printer.CStr() ); + @endverbatim +*/ +class TiXmlPrinter : public TiXmlVisitor +{ +public: + TiXmlPrinter() : depth(0), simpleTextPrint(false), + buffer(), indent(" "), lineBreak("\n") {} + + virtual bool VisitEnter(const TiXmlDocument& doc); + virtual bool VisitExit(const TiXmlDocument& doc); + + virtual bool VisitEnter(const TiXmlElement& element, const TiXmlAttribute* firstAttribute); + virtual bool VisitExit(const TiXmlElement& element); + + virtual bool Visit(const TiXmlDeclaration& declaration); + virtual bool Visit(const TiXmlText& text); + virtual bool Visit(const TiXmlComment& comment); + virtual bool Visit(const TiXmlUnknown& unknown); + + /** Set the indent characters for printing. By default 4 spaces + but tab ( ) is also useful, or null/empty string for no indentation. + */ + void SetIndent(const char* _indent) + { + indent = _indent ? _indent : "" ; + } + /// Query the indention string. + const char* Indent() + { + return indent.c_str(); + } + /** Set the line breaking string. By default set to newline (\n). + Some operating systems prefer other characters, or can be + set to the null/empty string for no indention. + */ + void SetLineBreak(const char* _lineBreak) + { + lineBreak = _lineBreak ? _lineBreak : ""; + } + /// Query the current line breaking string. + const char* LineBreak() + { + return lineBreak.c_str(); + } + + /** Switch over to "stream printing" which is the most dense formatting without + line-breaks. Common when the XML is needed for network transmission. + */ + void SetStreamPrinting() + { + indent = ""; + lineBreak = ""; + } + /// Return the result. + const char* CStr() + { + return buffer.c_str(); + } + /// Return the length of the result string. + size_t Size() + { + return buffer.size(); + } + +#ifdef TIXML_USE_STL + /// Return the result. + const std::string& Str() + { + return buffer; + } +#endif + +private: + void DoIndent() + { + for(int i=0; i