├── assets ├── fonts │ └── Ouders.ttf ├── images │ ├── comet.jpg │ ├── enemy.png │ ├── bullet3.png │ ├── space.jpeg │ ├── asteroid.png │ ├── player1.jpeg │ ├── exit_button.jpg │ ├── exit_button.png │ ├── play_button.png │ ├── restart_button.png │ └── resume_button.png └── sounds │ └── sfx │ └── boom.wav ├── src ├── GameState.cpp ├── Comet.cpp ├── Bullet.cpp ├── main.cpp ├── GameOverState.cpp ├── GameObjectFactory.cpp ├── GameStateMachine.cpp ├── LoaderParams.cpp ├── PauseState.cpp ├── SoundManager.cpp ├── MenuButton.cpp ├── TextureManager.cpp ├── GameObject.cpp ├── tinyxmlerror.cpp ├── Vector2D.cpp ├── MenuState.cpp ├── UFO.cpp ├── PlayState.cpp ├── InputHandler.cpp ├── StateParser.cpp ├── tinystr.cpp ├── Game.cpp ├── BulletHandler.cpp ├── CollisionManager.cpp ├── Player.cpp ├── tinyxmlparser.cpp └── tinyxml.cpp ├── include ├── Enemy.h ├── GameStateMachine.h ├── UFO.h ├── CollisionManager.h ├── GameState.h ├── StateParser.h ├── PauseState.h ├── PlayState.h ├── GameOverState.h ├── Comet.h ├── GameObjectFactory.h ├── Collision.h ├── LoaderParams.h ├── Bullet.h ├── SoundManager.h ├── TextureManager.h ├── Vector2D.h ├── InputHandler.h ├── BulletHandler.h ├── MenuButton.h ├── Player.h ├── Game.h ├── MenuState.h ├── GameObject.h └── tinystr.h ├── .gitignore ├── README.md ├── LICENSE ├── Makefile └── test.xml /assets/fonts/Ouders.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gustavooquinteiro/comet-busters/HEAD/assets/fonts/Ouders.ttf -------------------------------------------------------------------------------- /assets/images/comet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gustavooquinteiro/comet-busters/HEAD/assets/images/comet.jpg -------------------------------------------------------------------------------- /assets/images/enemy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gustavooquinteiro/comet-busters/HEAD/assets/images/enemy.png -------------------------------------------------------------------------------- /src/GameState.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/GameState.h" 2 | 3 | const char* GameState::configFile = "test.xml"; 4 | -------------------------------------------------------------------------------- /assets/images/bullet3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gustavooquinteiro/comet-busters/HEAD/assets/images/bullet3.png -------------------------------------------------------------------------------- /assets/images/space.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gustavooquinteiro/comet-busters/HEAD/assets/images/space.jpeg -------------------------------------------------------------------------------- /assets/images/asteroid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gustavooquinteiro/comet-busters/HEAD/assets/images/asteroid.png -------------------------------------------------------------------------------- /assets/images/player1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gustavooquinteiro/comet-busters/HEAD/assets/images/player1.jpeg -------------------------------------------------------------------------------- /assets/sounds/sfx/boom.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gustavooquinteiro/comet-busters/HEAD/assets/sounds/sfx/boom.wav -------------------------------------------------------------------------------- /assets/images/exit_button.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gustavooquinteiro/comet-busters/HEAD/assets/images/exit_button.jpg -------------------------------------------------------------------------------- /assets/images/exit_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gustavooquinteiro/comet-busters/HEAD/assets/images/exit_button.png -------------------------------------------------------------------------------- /assets/images/play_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gustavooquinteiro/comet-busters/HEAD/assets/images/play_button.png -------------------------------------------------------------------------------- /assets/images/restart_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gustavooquinteiro/comet-busters/HEAD/assets/images/restart_button.png -------------------------------------------------------------------------------- /assets/images/resume_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gustavooquinteiro/comet-busters/HEAD/assets/images/resume_button.png -------------------------------------------------------------------------------- /include/Enemy.h: -------------------------------------------------------------------------------- 1 | #ifndef _ENEMY_H_ 2 | #define _ENEMY_H_ 3 | 4 | #include "GameObject.h" 5 | 6 | using namespace std; 7 | 8 | class Enemy: public ShooterObject 9 | { 10 | public: 11 | virtual string type(){ return "Enemy"; } 12 | 13 | protected: 14 | int health; 15 | 16 | Enemy(): ShooterObject(){} 17 | virtual ~Enemy(){} 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object folder 2 | build/ 3 | 4 | # Prerequisites 5 | *.d 6 | 7 | # Compiled Object files 8 | *.slo 9 | *.lo 10 | *.o 11 | *.obj 12 | 13 | # Precompiled Headers 14 | *.gch 15 | *.pch 16 | 17 | # Compiled Dynamic libraries 18 | *.so 19 | *.dylib 20 | *.dll 21 | 22 | # Fortran module files 23 | *.mod 24 | *.smod 25 | 26 | # Compiled Static libraries 27 | *.lai 28 | *.la 29 | *.a 30 | *.lib 31 | 32 | # Executables 33 | *.exe 34 | *.out 35 | *.app 36 | comet 37 | -------------------------------------------------------------------------------- /include/GameStateMachine.h: -------------------------------------------------------------------------------- 1 | #ifndef _GAME_STATE_MACHINE_H_ 2 | #define _GAME_STATE_MACHINE_H_ 3 | 4 | #include "GameState.h" 5 | #include 6 | 7 | class GameStateMachine 8 | { 9 | public: 10 | GameStateMachine(); 11 | void pushState(GameState* state); 12 | void changeState(GameState* state); 13 | void popState(); 14 | 15 | void update(); 16 | void render(); 17 | private: 18 | stack gameStates; 19 | 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /include/UFO.h: -------------------------------------------------------------------------------- 1 | #ifndef _UFO_H_ 2 | #define _UFO_H_ 3 | 4 | #include "Enemy.h" 5 | #include "GameObjectFactory.h" 6 | 7 | class UFO: public Enemy 8 | { 9 | public: 10 | virtual ~UFO(){} 11 | UFO(); 12 | virtual void collision(); 13 | virtual void update(); 14 | void shoot(); 15 | }; 16 | 17 | class UFOCreator: public BaseCreator 18 | { 19 | GameObject* createGameObject() const 20 | { 21 | return new UFO(); 22 | } 23 | }; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /include/CollisionManager.h: -------------------------------------------------------------------------------- 1 | #ifndef _COLLISION_MANAGER_H_ 2 | #define _COLLISION_MANAGER_H_ 3 | 4 | #include "Player.h" 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | class CollisionManager 10 | { 11 | public: 12 | void checkPlayerEnemyBulletCollision(Player* player); 13 | void checkPlayerEnemyCollision(Player* player, const vector &gameObjects); 14 | void checkEnemyPlayerBulletCollision(const vector &gameObjects); 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /include/GameState.h: -------------------------------------------------------------------------------- 1 | #ifndef _GAME_STATE_H_ 2 | #define _GAME_STATE_H_ 3 | 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | class GameState 9 | { 10 | public: 11 | virtual void update() = 0; 12 | virtual void render() = 0; 13 | 14 | virtual bool onEnter() = 0; 15 | virtual bool onExit() = 0; 16 | 17 | virtual string getStateID() const = 0; 18 | 19 | protected: 20 | vector textureIDList; 21 | static const char* configFile; 22 | }; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /include/StateParser.h: -------------------------------------------------------------------------------- 1 | #ifndef _STATE_PARSER_H_ 2 | #define _STATE_PARSER_H_ 3 | 4 | #include 5 | #include 6 | #include "tinyxml.h" 7 | 8 | using namespace std; 9 | 10 | class GameObject; 11 | 12 | class StateParser 13 | { 14 | public: 15 | bool parseState(const char* stateFile, string stateID, vector* objects, vector* textureIDs); 16 | private: 17 | void parseObjects(TiXmlElement* stateRoot, vector* objects); 18 | void parseTexture(TiXmlElement* stateRoot, vector* textureIDs); 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /include/PauseState.h: -------------------------------------------------------------------------------- 1 | #ifndef _PAUSE_STATE_H_ 2 | #define _PAUSE_STATE_H_ 3 | 4 | #include "GameState.h" 5 | #include "GameObject.h" 6 | #include 7 | using namespace std; 8 | 9 | class PauseState: public GameState 10 | { 11 | public: 12 | void update() override; 13 | void render() override; 14 | bool onEnter() override; 15 | bool onExit() override; 16 | string getStateID() const override; 17 | private: 18 | static void pauseToMain(); 19 | static void resumePlay(); 20 | 21 | static const string pauseID; 22 | vector gameObjects; 23 | }; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /include/PlayState.h: -------------------------------------------------------------------------------- 1 | #ifndef _PLAY_STATE_H_ 2 | #define _PLAY_STATE_H_ 3 | 4 | #include "GameState.h" 5 | #include "CollisionManager.h" 6 | #include 7 | using namespace std; 8 | 9 | class PlayState: public GameState 10 | { 11 | public: 12 | void update() override; 13 | void render() override; 14 | 15 | bool onEnter() override; 16 | bool onExit() override; 17 | 18 | string getStateID() const override; 19 | 20 | private: 21 | static const string playID; 22 | 23 | CollisionManager collisionManager; 24 | 25 | vector gameObjects; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/Comet.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/Comet.h" 2 | 3 | Comet::Comet(): ShooterObject() 4 | { 5 | srand(time(NULL)); 6 | acceleration.setX(rand() % 3); 7 | } 8 | 9 | void Comet::load(const unique_ptr& params) 10 | { 11 | ShooterObject::load(move(params)); 12 | } 13 | 14 | void Comet::draw() 15 | { 16 | ShooterObject::draw(); 17 | } 18 | 19 | void Comet::update() 20 | { 21 | velocity += acceleration; 22 | ShooterObject::update(); 23 | } 24 | 25 | void Comet::clean() 26 | { 27 | ShooterObject::clean(); 28 | } 29 | 30 | void Comet::collision() 31 | { 32 | ShooterObject::collision(); 33 | } 34 | -------------------------------------------------------------------------------- /include/GameOverState.h: -------------------------------------------------------------------------------- 1 | #ifndef _GAME_OVER_STATE_H_ 2 | #define _GAME_OVER_STATE_H_ 3 | 4 | #include "GameState.h" 5 | #include "GameObject.h" 6 | #include 7 | using namespace std; 8 | 9 | class GameOverState: public GameState 10 | { 11 | public: 12 | void update() override; 13 | void render() override; 14 | 15 | bool onEnter() override; 16 | bool onExit() override; 17 | string getStateID() const override; 18 | private: 19 | static void gameOverToMain(); 20 | static void restartPlay(); 21 | 22 | static const string gameOverID; 23 | vector gameObjects; 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /include/Comet.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMET_H_ 2 | #define _COMET_H_ 3 | 4 | #include 5 | #include "GameObject.h" 6 | #include "GameObjectFactory.h" 7 | 8 | class Comet: public ShooterObject 9 | { 10 | public: 11 | Comet(); 12 | virtual void load(const unique_ptr ¶ms); 13 | virtual void draw(); 14 | virtual void update(); 15 | virtual void clean(); 16 | virtual void collision(); 17 | string type(){ return "Comet"; } 18 | }; 19 | 20 | class CometCreator: public BaseCreator 21 | { 22 | public: 23 | GameObject* createGameObject() const 24 | { 25 | return new Comet(); 26 | } 27 | }; 28 | #endif 29 | -------------------------------------------------------------------------------- /include/GameObjectFactory.h: -------------------------------------------------------------------------------- 1 | #ifndef _GAME_OBJECT_FACTORY_H_ 2 | #define _GAME_OBJECT_FACTORY_H_ 3 | 4 | #include 5 | #include 6 | #include "GameObject.h" 7 | 8 | class BaseCreator 9 | { 10 | public: 11 | virtual GameObject* createGameObject() const = 0; 12 | virtual ~BaseCreator(){} 13 | 14 | }; 15 | 16 | class GameObjectFactory 17 | { 18 | public: 19 | static GameObjectFactory* Instance(); 20 | bool registerType(string typeID, BaseCreator* creator); 21 | GameObject* create(string typeID); 22 | private: 23 | GameObjectFactory(); 24 | 25 | map creators; 26 | static GameObjectFactory* instance; 27 | }; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/Collision.h: -------------------------------------------------------------------------------- 1 | #ifndef _COLLISION_ 2 | #define _COLLISION_ 3 | #include 4 | 5 | static const int collisionBuffer = 4; 6 | 7 | static bool RectRect(SDL_Rect* A, SDL_Rect* B) 8 | { 9 | int aHbuf = A->h / collisionBuffer; 10 | int aWbuf = A->w / collisionBuffer; 11 | 12 | int bHbuf = B->h / collisionBuffer; 13 | int bWbuf = B->w / collisionBuffer; 14 | 15 | if ((A->y + A->h) - aHbuf <= B->y + bHbuf) return false; 16 | if (A->y + aHbuf >= (B->h + B->y) - bHbuf) return false; 17 | if ((A->x + A->w) - aWbuf <= B->x + bWbuf) return false; 18 | if (A->x + aWbuf >= (B->x + B->w) - bWbuf) return false; 19 | 20 | return true; 21 | } 22 | #endif 23 | -------------------------------------------------------------------------------- /include/LoaderParams.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOADER_PARAMS_H_ 2 | #define _LOADER_PARAMS_H_ 3 | 4 | #include "Vector2D.h" 5 | #include 6 | using namespace std; 7 | 8 | class LoaderParams 9 | { 10 | public: 11 | LoaderParams(int x, int y, int width, int height, string textureID, int numFrames, int callbackID, int animationSpeed); 12 | int getWidth() const; 13 | int getHeight() const; 14 | string getTextureID() const; 15 | int getX() const; 16 | int getY() const; 17 | int getCallbackID() const; 18 | private: 19 | int x; 20 | int y; 21 | int width; 22 | int height; 23 | 24 | string textureID; 25 | 26 | int numFrames; 27 | int callbackID; 28 | int animationSpeed; 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/Bullet.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/Bullet.h" 2 | 3 | PlayerBullet::~PlayerBullet() 4 | { 5 | } 6 | 7 | EnemyBullet::~EnemyBullet() 8 | { 9 | } 10 | 11 | void PlayerBullet::load(const unique_ptr ¶ms, 12 | Vector2D heading) 13 | { 14 | ShooterObject::load(move(params)); 15 | this->heading = heading; 16 | } 17 | 18 | void PlayerBullet::draw() 19 | { 20 | ShooterObject::draw(); 21 | } 22 | 23 | void PlayerBullet::collision() 24 | { 25 | dead = true; 26 | } 27 | 28 | void PlayerBullet::update() 29 | { 30 | velocity.setX(heading.getX()); 31 | velocity.setY(heading.getY()); 32 | ShooterObject::update(); 33 | } 34 | 35 | void PlayerBullet::clean() 36 | { 37 | ShooterObject::clean(); 38 | } 39 | -------------------------------------------------------------------------------- /include/Bullet.h: -------------------------------------------------------------------------------- 1 | #ifndef _BULLET_MANAGER_H_ 2 | #define _BULLET_MANAGER_H_ 3 | 4 | #include "GameObject.h" 5 | using namespace std; 6 | 7 | class PlayerBullet: public ShooterObject 8 | { 9 | public: 10 | PlayerBullet(): ShooterObject(){} 11 | virtual ~PlayerBullet(); 12 | string type() { return "PlayerBullet"; } 13 | void load(const unique_ptr ¶ms, Vector2D heading); 14 | void draw() override; 15 | void collision() override; 16 | void update() override; 17 | void clean() override; 18 | private: 19 | Vector2D heading; 20 | }; 21 | 22 | class EnemyBullet: public PlayerBullet 23 | { 24 | public: 25 | EnemyBullet(): PlayerBullet(){} 26 | virtual ~EnemyBullet(); 27 | string type(){ return "EnemyBullet"; } 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/SoundManager.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOUND_MANAGER_H_ 2 | #define _SOUND_MANAGER_H_ 3 | 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | enum sound_type 9 | { 10 | SOUND_MUSIC, 11 | SOUND_SFX 12 | }; 13 | 14 | class SoundManager 15 | { 16 | public: 17 | static SoundManager* Instance(); 18 | bool load(string filename, string id, sound_type type); 19 | void playSound(string id, int loop); 20 | void playMusic(string id, int loop); 21 | private: 22 | static SoundManager* instance; 23 | map sfxs; 24 | map musics; 25 | SoundManager(); 26 | ~SoundManager(); 27 | 28 | SoundManager(const SoundManager&); 29 | SoundManager& operator=(const SoundManager&); 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /include/TextureManager.h: -------------------------------------------------------------------------------- 1 | #ifndef _TEXTURE_MANAGER_H_ 2 | #define _TEXTURE_MANAGER_H_ 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | using namespace std; 10 | 11 | class TextureManager 12 | { 13 | public: 14 | void draw(string id, int x, int y, int width, int height, 15 | SDL_Renderer* renderer, double angle = 0, 16 | SDL_RendererFlip flip = SDL_FLIP_NONE); 17 | bool load(string filename, string id, SDL_Renderer* renderer); 18 | static TextureManager* Instance(); 19 | void clearFromTextureMap(string id); 20 | void clearTextureMap(); 21 | private: 22 | TextureManager(); 23 | map textureMap; 24 | static TextureManager* textureManagerInstance; 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/Game.h" 2 | const char* TITLE = "Comet Busters! 1994"; 3 | 4 | const int FPS = 60; 5 | const int DELAY_TIME = 1000.0f / FPS; 6 | 7 | int main(int argc, char* argv[]) 8 | { 9 | Uint32 frameStart, frameTime; 10 | 11 | Game::Instance()->init(TITLE, 100, 100, 640, 480, 0); 12 | 13 | while(Game::Instance()->running()) 14 | { 15 | frameStart = SDL_GetTicks(); 16 | 17 | Game::Instance()->handleEvents(); 18 | Game::Instance()->update(); 19 | Game::Instance()->render(); 20 | 21 | frameTime = SDL_GetTicks() - frameStart; 22 | if (frameTime < DELAY_TIME) 23 | SDL_Delay((int) (DELAY_TIME - frameTime)); 24 | } 25 | 26 | Game::Instance()->clean(); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /include/Vector2D.h: -------------------------------------------------------------------------------- 1 | #ifndef _VECTOR_2D_H_ 2 | #define _VECTOR_2D_H_ 3 | 4 | #include 5 | 6 | class Vector2D 7 | { 8 | public: 9 | Vector2D(); 10 | Vector2D(float x, float y); 11 | float getX() const; 12 | float getY() const; 13 | void setX(float x); 14 | void setY(float y); 15 | 16 | float length(); 17 | Vector2D operator+(const Vector2D& vector); 18 | Vector2D& operator+=(const Vector2D& vector2); 19 | Vector2D operator*(float scalar); 20 | Vector2D& operator*=(float scalar); 21 | Vector2D operator-(const Vector2D& vector); 22 | Vector2D& operator-=(const Vector2D& vector2); 23 | Vector2D operator/(float scalar); 24 | Vector2D& operator /=(float scalar); 25 | void normalize(); 26 | private: 27 | float x; 28 | float y; 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/GameOverState.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/Game.h" 2 | #include "../include/PlayState.h" 3 | #include "../include/MenuState.h" 4 | #include "../include/GameOverState.h" 5 | 6 | 7 | const string GameOverState::gameOverID = "GAMEOVER"; 8 | 9 | void GameOverState::gameOverToMain() 10 | { 11 | Game::Instance()->getStateMachine()->changeState(new MainMenuState()); 12 | } 13 | 14 | void GameOverState::restartPlay() 15 | { 16 | Game::Instance()->getStateMachine()->changeState(new PlayState()); 17 | } 18 | 19 | bool GameOverState::onEnter() 20 | { 21 | return true; 22 | } 23 | 24 | bool GameOverState::onExit() 25 | { 26 | return true; 27 | } 28 | 29 | void GameOverState::render() 30 | { 31 | } 32 | 33 | void GameOverState::update() 34 | { 35 | } 36 | 37 | string GameOverState::getStateID() const{ return this->gameOverID; } 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # comet-busters 2 | ![License](https://img.shields.io/github/license/gustavooquinteiro/comet-busters) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/gustavooquinteiro/comet-busters?color=orange) 3 | 4 | This repository is a "Comet Busters! 1994"'s remake using SDL as a way to both study the SDL engine in C++ and recollect the very first offline multiplayer game that I played in my childhood 5 | 6 | ## :ballot_box_with_check: Requirements 7 | 8 | * [SDL2](https://www.libsdl.org/download-2.0.php) 9 | 10 | ## :hammer_and_wrench: Compilation 11 | 12 | For UNIX platforms, is available a [Makefile](Makefile) to compile the game with the command: 13 | ```sh 14 | make all 15 | ``` 16 | 17 | ## :arrow_forward: Execution 18 | 19 | To run the game, type the command in a terminal: 20 | ```sh 21 | ./comet 22 | ``` 23 | -------------------------------------------------------------------------------- /include/InputHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef _INPUT_HANDLER_H_ 2 | #define _INPUT_HANDLER_H_ 3 | 4 | #include 5 | #include "Vector2D.h" 6 | #include 7 | 8 | using namespace std; 9 | 10 | class InputHandler 11 | { 12 | public: 13 | bool isKeyDown(SDL_Scancode key); 14 | void onKeyDown(); 15 | void onKeyUp(); 16 | 17 | static InputHandler* Instance(); 18 | void update(); 19 | 20 | bool getMouseButtonState(int buttonNumber); 21 | Vector2D* getMousePosition(); 22 | void reset(); 23 | 24 | enum mouse_buttons 25 | { 26 | LEFT, 27 | MIDDLE, 28 | RIGHT 29 | }; 30 | private: 31 | InputHandler(); 32 | ~InputHandler(); 33 | static InputHandler* instance; 34 | 35 | const Uint8* keyState; 36 | 37 | vector mouseButtonStates; 38 | Vector2D* mousePosition; 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/BulletHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef _BULLET_HANDLER_H_ 2 | #define _BULLET_HANDLER_H_ 3 | 4 | #include "Vector2D.h" 5 | #include "Bullet.h" 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | class BulletHandler 11 | { 12 | public: 13 | void addPlayerBullet(int x, int y, int width, int height, string textureID, int numFrames, Vector2D heading); 14 | void addEnemyBullet(int x, int y, int width, int height, string textureID, int numFrames, Vector2D heading); 15 | static BulletHandler* Instance(); 16 | 17 | void updateBullets(); 18 | void drawBullets(); 19 | void clearBullets(); 20 | 21 | vector getPlayerBullets() const; 22 | vector getEnemyBullets() const; 23 | private: 24 | BulletHandler(); 25 | static BulletHandler* instance; 26 | 27 | vector playerBullets; 28 | vector enemyBullets; 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/MenuButton.h: -------------------------------------------------------------------------------- 1 | #ifndef _MENU_BUTTON_H_ 2 | #define _MENU_BUTTON_H_ 3 | 4 | #include "GameObject.h" 5 | #include "GameObjectFactory.h" 6 | 7 | class MenuButton: public ShooterObject 8 | { 9 | public: 10 | MenuButton(); 11 | void update() override; 12 | void draw() override; 13 | void clean() override; 14 | void load(const unique_ptr ¶ms) override; 15 | void collision() override; 16 | string type(){ return "MenuButton"; } 17 | void setCallback(void (*callback)()); 18 | int getCallbackID(); 19 | private: 20 | enum button_state 21 | { 22 | MOUSE_OUT = 0, 23 | MOUSE_OVER = 1, 24 | CLICKED = 2 25 | }; 26 | 27 | void (*callback)(); 28 | bool buttonReleased; 29 | int callbackID; 30 | }; 31 | 32 | class MenuButtonCreator: public BaseCreator 33 | { 34 | public: 35 | GameObject * createGameObject() const 36 | { 37 | return new MenuButton(); 38 | } 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/Player.h: -------------------------------------------------------------------------------- 1 | #ifndef _PLAYER_H_ 2 | #define _PLAYER_H_ 3 | 4 | #include 5 | #include "GameObject.h" 6 | #include "GameObjectFactory.h" 7 | 8 | class Player: public ShooterObject 9 | { 10 | public: 11 | Player(); 12 | virtual void draw(); 13 | virtual void update(); 14 | virtual void clean(); 15 | virtual void load(unique_ptr const ¶ms); 16 | long int getScore() const; 17 | private: 18 | void handleInput(); 19 | void handleAnimation(); 20 | void setAngle(bool direction); 21 | void setVelocity(); 22 | 23 | enum Angle 24 | { 25 | FIRST_QUADRANT, 26 | SECOND_QUANDRANT, 27 | THIRD_QUADRANT, 28 | FOURTH_QUADRANT 29 | }; 30 | 31 | Angle myAngle; 32 | long int score; 33 | }; 34 | 35 | class PlayerCreator: public BaseCreator 36 | { 37 | public: 38 | GameObject* createGameObject() const 39 | { 40 | return new Player(); 41 | } 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/GameObjectFactory.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/GameObjectFactory.h" 2 | 3 | GameObjectFactory* GameObjectFactory::instance = 0; 4 | 5 | GameObjectFactory::GameObjectFactory(){} 6 | 7 | bool GameObjectFactory::registerType(string typeId, BaseCreator* creator) 8 | { 9 | map::iterator mapIterator = creators.find(typeId); 10 | if (mapIterator != creators.end()) 11 | { 12 | delete creator; 13 | return false; 14 | } 15 | 16 | creators[typeId] = creator; 17 | return true; 18 | } 19 | 20 | GameObject * GameObjectFactory::create(string typeID) 21 | { 22 | map::iterator mapIterator = creators.find(typeID); 23 | if (mapIterator == creators.end()) 24 | return NULL; 25 | 26 | BaseCreator* creator = (*mapIterator).second; 27 | return creator->createGameObject(); 28 | } 29 | 30 | GameObjectFactory * GameObjectFactory::Instance() 31 | { 32 | if (instance == 0) 33 | instance = new GameObjectFactory(); 34 | return instance; 35 | } 36 | -------------------------------------------------------------------------------- /src/GameStateMachine.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/GameStateMachine.h" 2 | 3 | GameStateMachine::GameStateMachine(){} 4 | 5 | void GameStateMachine::pushState(GameState* state) 6 | { 7 | gameStates.push(state); 8 | gameStates.top()->onEnter(); 9 | } 10 | 11 | void GameStateMachine::popState() 12 | { 13 | if (!gameStates.empty()) 14 | { 15 | if (gameStates.top()->onExit()) 16 | { 17 | gameStates.pop(); 18 | } 19 | } 20 | } 21 | 22 | 23 | void GameStateMachine::changeState(GameState* state) 24 | { 25 | if (!gameStates.empty()) 26 | { 27 | if (gameStates.top()->getStateID() == state->getStateID()) 28 | return; 29 | popState(); 30 | } 31 | pushState(state); 32 | } 33 | 34 | void GameStateMachine::update() 35 | { 36 | if (!gameStates.empty()) 37 | gameStates.top()->update(); 38 | 39 | } 40 | 41 | void GameStateMachine::render() 42 | { 43 | if (!gameStates.empty()) 44 | gameStates.top()->render(); 45 | } 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Gustavo Oliveira Quinteiro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/LoaderParams.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/LoaderParams.h" 2 | 3 | LoaderParams::LoaderParams(int x, int y, int width, int height, string textureID, int numFrames, 4 | int callbackID = 0, int animationSpeed = 0): x(x), y(y), 5 | width(width), 6 | height(height), 7 | textureID(textureID), 8 | numFrames(numFrames), 9 | callbackID(callbackID), 10 | animationSpeed(animationSpeed){} 11 | 12 | int LoaderParams::getX() const{ return x; } 13 | 14 | int LoaderParams::getY() const{ return y; } 15 | 16 | int LoaderParams::getHeight() const{ return height; } 17 | 18 | int LoaderParams::getWidth() const{ return width; } 19 | 20 | string LoaderParams::getTextureID() const{ return textureID; } 21 | 22 | int LoaderParams::getCallbackID() const{ return callbackID; } 23 | -------------------------------------------------------------------------------- /include/Game.h: -------------------------------------------------------------------------------- 1 | #ifndef _GAME_H_ 2 | #define _GAME_H_ 3 | 4 | #include 5 | #include 6 | #include "GameObject.h" 7 | #include "GameStateMachine.h" 8 | 9 | using namespace std; 10 | 11 | class Game 12 | { 13 | public: 14 | 15 | bool init(const char* title, int xpos, int ypos, int width, int height, int flags); 16 | void render(); 17 | void update(); 18 | void handleEvents(); 19 | void clean(); 20 | bool running(); 21 | void quit(); 22 | SDL_Renderer* getRenderer(); 23 | static Game* Instance(); 24 | GameStateMachine* getStateMachine(); 25 | int getPlayerLives() { return playerLives; } 26 | void setPlayerLives(int lives){ playerLives = lives; } 27 | int getGameHeight() { return gameHeight; } 28 | int getGameWidth() { return gameWidth; } 29 | private: 30 | Game(); 31 | ~Game(); 32 | 33 | Game(const Game&); 34 | Game& operator= (const Game&); 35 | 36 | static Game * instance; 37 | SDL_Window* window; 38 | SDL_Renderer* renderer; 39 | 40 | GameStateMachine* gameStateMachine; 41 | 42 | int playerLives; 43 | int gameWidth; 44 | int gameHeight; 45 | 46 | bool run; 47 | }; 48 | #endif 49 | -------------------------------------------------------------------------------- /src/PauseState.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/TextureManager.h" 2 | #include "../include/InputHandler.h" 3 | #include "../include/PauseState.h" 4 | #include "../include/MenuState.h" 5 | #include "../include/Game.h" 6 | 7 | const string PauseState::pauseID = "PAUSE"; 8 | 9 | void PauseState::pauseToMain() 10 | { 11 | Game::Instance()->getStateMachine()->changeState(new MainMenuState()); 12 | } 13 | 14 | void PauseState::resumePlay() 15 | { 16 | Game::Instance()->getStateMachine()->popState(); 17 | } 18 | 19 | void PauseState::update() 20 | { 21 | for (auto object: gameObjects) 22 | object->update(); 23 | } 24 | 25 | void PauseState::render() 26 | { 27 | for (auto object: gameObjects) 28 | object->draw(); 29 | } 30 | 31 | bool PauseState::onEnter() 32 | { 33 | return false; 34 | } 35 | 36 | bool PauseState::onExit() 37 | { 38 | for (auto object: gameObjects) 39 | object->clean(); 40 | 41 | gameObjects.clear(); 42 | 43 | for (auto texture: textureIDList) 44 | TextureManager::Instance()->clearFromTextureMap(texture); 45 | 46 | InputHandler::Instance()->reset(); 47 | return true; 48 | } 49 | 50 | 51 | string PauseState::getStateID() const{ return this->pauseID; } 52 | -------------------------------------------------------------------------------- /include/MenuState.h: -------------------------------------------------------------------------------- 1 | #ifndef _MENU_STATE_H_ 2 | #define _MENU_STATE_H_ 3 | 4 | #include "GameObject.h" 5 | #include "GameState.h" 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | class MenuState: public GameState 12 | { 13 | public: 14 | void update() override; 15 | void render() override; 16 | 17 | bool onEnter() override; 18 | bool onExit() override; 19 | 20 | string getStateID() const override; 21 | 22 | protected: 23 | typedef void(*Callback)(); 24 | virtual void setCallbacks(const vector& callbacks) = 0; 25 | 26 | vector callbacks; 27 | private: 28 | 29 | static const string menuID; 30 | }; 31 | 32 | class MainMenuState: public MenuState 33 | { 34 | public: 35 | MainMenuState(); 36 | void update() override; 37 | void render() override; 38 | 39 | bool onEnter() override; 40 | bool onExit() override; 41 | 42 | string getStateID() const override; 43 | private: 44 | void setCallbacks(const vector& callbacks) override; 45 | 46 | static void menuToPlay(); 47 | static void exitFromMenu(); 48 | 49 | static const string menuID; 50 | vector gameObjects; 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/SoundManager.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/SoundManager.h" 2 | #include 3 | 4 | SoundManager* SoundManager::instance = 0; 5 | 6 | SoundManager* SoundManager::Instance() 7 | { 8 | if (instance == 0) 9 | instance = new SoundManager(); 10 | return instance; 11 | } 12 | 13 | SoundManager::SoundManager() 14 | { 15 | Mix_OpenAudio(22050, AUDIO_S16, 2, 4096); 16 | } 17 | 18 | bool SoundManager::load(string filename, string id, sound_type type) 19 | { 20 | if (type == SOUND_MUSIC) 21 | { 22 | Mix_Music* music = Mix_LoadMUS(filename.c_str()); 23 | if (music == 0) 24 | { 25 | cerr << Mix_GetError() << endl; 26 | return false; 27 | } 28 | musics[id] = music; 29 | return true; 30 | } 31 | else if (type == SOUND_SFX) 32 | { 33 | Mix_Chunk* chunk = Mix_LoadWAV(filename.c_str()); 34 | if (chunk == 0) 35 | { 36 | cerr << Mix_GetError() << endl; 37 | return false; 38 | } 39 | sfxs[id] = chunk; 40 | return true; 41 | } 42 | return false; 43 | } 44 | 45 | void SoundManager::playMusic(string id, int loop) 46 | { 47 | Mix_PlayMusic(musics[id], loop); 48 | } 49 | 50 | void SoundManager::playSound(std::string id, int loop) 51 | { 52 | Mix_PlayChannel(-1, sfxs[id], loop); 53 | } 54 | 55 | SoundManager::~SoundManager() 56 | { 57 | Mix_CloseAudio(); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/MenuButton.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/MenuButton.h" 2 | #include "../include/InputHandler.h" 3 | 4 | MenuButton::MenuButton(){} 5 | 6 | void MenuButton::update() 7 | { 8 | Vector2D* mousePosition = InputHandler::Instance()->getMousePosition(); 9 | if (mousePosition->getX() < (position.getX() + width) && mousePosition->getX() > position.getX() && 10 | mousePosition->getY() < (position.getY() + height) && mousePosition->getY() > position.getY()) 11 | { 12 | if (InputHandler::Instance()->getMouseButtonState(InputHandler::LEFT) && buttonReleased) 13 | { 14 | currentFrame = CLICKED; 15 | callback(); 16 | buttonReleased = false; 17 | } 18 | else if (!InputHandler::Instance()->getMouseButtonState(InputHandler::LEFT)) 19 | { 20 | buttonReleased = true; 21 | currentFrame = MOUSE_OVER; 22 | } 23 | else 24 | { 25 | currentFrame = MOUSE_OUT; 26 | } 27 | } 28 | } 29 | 30 | void MenuButton::clean() 31 | { 32 | ShooterObject::clean(); 33 | } 34 | 35 | void MenuButton::draw() 36 | { 37 | ShooterObject::draw(); 38 | } 39 | 40 | void MenuButton::collision() 41 | { 42 | } 43 | 44 | void MenuButton::load(const unique_ptr& params) 45 | { 46 | ShooterObject::load(move(params)); 47 | callbackID = params->getCallbackID(); 48 | currentFrame = MOUSE_OUT; 49 | } 50 | 51 | void MenuButton::setCallback(void (*callback)()){ this->callback = callback; } 52 | 53 | int MenuButton::getCallbackID(){ return this->callbackID; } 54 | -------------------------------------------------------------------------------- /src/TextureManager.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/TextureManager.h" 2 | 3 | TextureManager * TextureManager::textureManagerInstance = 0; 4 | 5 | TextureManager::TextureManager() 6 | { 7 | IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG); 8 | } 9 | 10 | bool TextureManager::load(string filename, string id, SDL_Renderer* renderer) 11 | { 12 | SDL_Surface* temp = IMG_Load(filename.c_str()); 13 | if (temp == 0) 14 | return false; 15 | 16 | SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, temp); 17 | SDL_FreeSurface(temp); 18 | 19 | if (texture) 20 | { 21 | textureMap[id] = texture; 22 | return true; 23 | } 24 | return false; 25 | } 26 | 27 | void TextureManager::draw(string id, int x, int y, 28 | int width, int height, 29 | SDL_Renderer* renderer, 30 | double angle, SDL_RendererFlip flip) 31 | { 32 | SDL_Rect srcRect; 33 | SDL_Rect dstRect; 34 | 35 | srcRect.x = 0; 36 | srcRect.y = 0; 37 | srcRect.w = dstRect.w = width; 38 | srcRect.h = dstRect.h = height; 39 | 40 | dstRect.x = x; 41 | dstRect.y = y; 42 | 43 | SDL_RenderCopyEx(renderer, textureMap[id], &srcRect, &dstRect, angle, 0, flip); 44 | } 45 | 46 | TextureManager * TextureManager::Instance() 47 | { 48 | if (textureManagerInstance == 0) 49 | textureManagerInstance = new TextureManager(); 50 | return textureManagerInstance; 51 | } 52 | 53 | void TextureManager::clearFromTextureMap(string id) 54 | { 55 | textureMap.erase(id); 56 | } 57 | 58 | void TextureManager::clearTextureMap() 59 | { 60 | textureMap.clear(); 61 | } 62 | -------------------------------------------------------------------------------- /src/GameObject.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/Game.h" 2 | #include "../include/GameObject.h" 3 | #include "../include/TextureManager.h" 4 | 5 | GameObject::~GameObject(){} 6 | 7 | GameObject::GameObject(): updating(true), dead(false){} 8 | 9 | ShooterObject::ShooterObject(): GameObject(), 10 | bulletFiringSpeed(0), 11 | bulletCounter(0), 12 | moveSpeed(0), 13 | dyingTime(0), 14 | dyingCounter(0), 15 | playedDeathSound(false){} 16 | 17 | void ShooterObject::draw() 18 | { 19 | TextureManager::Instance()->draw(textureId, 20 | (Uint32) position.getX(), 21 | (Uint32) position.getY(), 22 | width, 23 | height, 24 | Game::Instance()->getRenderer(), angle); 25 | } 26 | 27 | void ShooterObject::update() 28 | { 29 | position += velocity; 30 | } 31 | 32 | void ShooterObject::load(unique_ptr const ¶ms) 33 | { 34 | position = Vector2D(params->getX(), params->getY()); 35 | 36 | width = params->getWidth(); 37 | height = params->getHeight(); 38 | textureId = params->getTextureID(); 39 | currentFrame = 1; 40 | currentRow = 1; 41 | } 42 | 43 | void ShooterObject::clean() 44 | { 45 | } 46 | 47 | ShooterObject::~ShooterObject() 48 | { 49 | } 50 | 51 | void ShooterObject::collision() 52 | { 53 | } 54 | 55 | void ShooterObject::doDyingAnimation() 56 | { 57 | if (dyingCounter == dyingTime) 58 | dead = true; 59 | dyingCounter++; 60 | } 61 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GAME = comet 2 | 3 | MAIN = ./src/main.cpp 4 | OBJ = $(subst .cpp,.o,$(subst ./src/,./build/, $(filter-out $(MAIN), $(wildcard ./src/*.cpp)))) 5 | 6 | CC = g++ 7 | 8 | CFLAGS = `sdl2-config --cflags`\ 9 | -g 10 | 11 | CXXFLAGS = `sdl2-config --cflags` \ 12 | -std=c++11 \ 13 | -std=c++11 \ 14 | -Wall \ 15 | -g \ 16 | 17 | 18 | LDFLAGS = `sdl2-config --libs` \ 19 | -lSDL2_mixer \ 20 | -lSDL2_image \ 21 | -lSDL2_ttf \ 22 | -lSDL2_gfx \ 23 | -lm 24 | 25 | INCLUDE = -I"/usr/include/SDL" 26 | 27 | MKDIR = mkdir -p 28 | RM = rm -rf 29 | 30 | ifeq ($(OS), Windows_NT) 31 | ECHO = ECHO 32 | MKDIR = 33 | RM = 34 | else 35 | UNAME_S := $(shell uname -s) 36 | ifeq ($(UNAME_S), Linux) 37 | ECHO = echo -e -n 38 | endif 39 | endif 40 | 41 | all: build $(GAME) 42 | 43 | build: 44 | @ $(ECHO) "Creating build folder...\n" 45 | @ $(MKDIR) build 46 | 47 | $(GAME): $(OBJ) 48 | @ $(ECHO) "Linking everything...\n" 49 | @ $(CC) $(MAIN) $^ -o $(GAME) $(LDFLAGS) 50 | @ $(ECHO) "Executable created: $@\n" 51 | 52 | ./build/%.o: ./src/%.cpp ./include/%.h 53 | @ $(ECHO) "Compiling $< in $@...\n" 54 | @ $(CC) $(CXXFLAGS) $(INCLUDE) $< -c -o $@ 55 | @ $(ECHO) "Compiled $@\n" 56 | 57 | ./build/tinyxmlerror.o: ./src/tinyxmlerror.cpp ./include/tinyxml.h 58 | @ $(ECHO) "Compiling $< in $@...\n" 59 | @ $(CC) $(CXXFLAGS) $(INCLUDE) $< -c -o $@ 60 | @ $(ECHO) "Compiled $@\n" 61 | 62 | ./build/tinyxmlparser.o: ./src/tinyxmlparser.cpp ./include/tinyxml.h 63 | @ $(ECHO) "Compiling $< in $@...\n" 64 | @ $(CC) $(CXXFLAGS) $(INCLUDE) $< -c -o $@ 65 | @ $(ECHO) "Compiled $@\n" 66 | 67 | clean: 68 | @ $(ECHO) "Cleaning workspace...\n" 69 | @ $(RM) build/ $(GAME) 70 | @ $(ECHO) "Workspace clean\n" 71 | 72 | .PHONY: all clean 73 | -------------------------------------------------------------------------------- /include/GameObject.h: -------------------------------------------------------------------------------- 1 | #ifndef _GAME_OBJECT_H_ 2 | #define _GAME_OBJECT_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "Vector2D.h" 8 | #include "LoaderParams.h" 9 | 10 | using namespace std; 11 | 12 | class GameObject 13 | { 14 | public: 15 | virtual ~GameObject(); 16 | virtual void load(unique_ptr const ¶ms) = 0; 17 | virtual void draw() = 0; 18 | virtual void update() = 0; 19 | virtual void clean() = 0; 20 | virtual void collision() = 0; 21 | virtual string type() = 0; 22 | Vector2D& getPosition() { return position; } 23 | int getHeight() { return height; } 24 | int getWidth() { return width; } 25 | bool isUpdating() { return updating; } 26 | bool isDead() { return dead; } 27 | void setUpdating(bool update) { updating = update; } 28 | protected: 29 | GameObject(); 30 | Vector2D position; 31 | Vector2D velocity; 32 | Vector2D acceleration; 33 | 34 | int width; 35 | int height; 36 | 37 | int currentRow; 38 | int currentFrame; 39 | 40 | string textureId; 41 | 42 | double angle; 43 | 44 | bool updating; 45 | bool dead; 46 | }; 47 | 48 | 49 | class ShooterObject: public GameObject 50 | { 51 | public: 52 | ~ShooterObject(); 53 | virtual void draw(); 54 | virtual void update(); 55 | virtual void clean(); 56 | virtual void load(unique_ptr const ¶ms); 57 | virtual void collision(); 58 | virtual string type() { return "ShooterObject"; } 59 | protected: 60 | ShooterObject(); 61 | void doDyingAnimation(); 62 | 63 | int bulletFiringSpeed; 64 | int bulletCounter; 65 | int moveSpeed; 66 | 67 | int dyingTime; 68 | int dyingCounter; 69 | 70 | bool playedDeathSound; 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/tinyxmlerror.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | www.sourceforge.net/projects/tinyxml 3 | Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any 7 | damages arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any 10 | purpose, including commercial applications, and to alter it and 11 | redistribute it freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must 14 | not claim that you wrote the original software. If you use this 15 | software in a product, an acknowledgment in the product documentation 16 | would be appreciated but is not required. 17 | 18 | 2. Altered source versions must be plainly marked as such, and 19 | must not be misrepresented as being the original software. 20 | 21 | 3. This notice may not be removed or altered from any source 22 | distribution. 23 | */ 24 | 25 | #include "../include/tinyxml.h" 26 | 27 | // The goal of the seperate error file is to make the first 28 | // step towards localization. tinyxml (currently) only supports 29 | // english error messages, but the could now be translated. 30 | // 31 | // It also cleans up the code a bit. 32 | // 33 | 34 | const char* TiXmlBase::errorString[ TiXmlBase::TIXML_ERROR_STRING_COUNT ] = 35 | { 36 | "No error", 37 | "Error", 38 | "Failed to open file", 39 | "Error parsing Element.", 40 | "Failed to read Element name", 41 | "Error reading Element value.", 42 | "Error reading Attributes.", 43 | "Error: empty tag.", 44 | "Error reading end tag.", 45 | "Error parsing Unknown.", 46 | "Error parsing Comment.", 47 | "Error parsing Declaration.", 48 | "Error document empty.", 49 | "Error null (0) or unexpected EOF found in input stream.", 50 | "Error parsing CDATA.", 51 | "Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.", 52 | }; 53 | -------------------------------------------------------------------------------- /test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/Vector2D.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/Vector2D.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | Vector2D::Vector2D(): x(0), y(0) {} 7 | 8 | Vector2D::Vector2D(float x_position, float y_position): x(x_position), y(y_position) {} 9 | 10 | float Vector2D::getX() const 11 | { 12 | return this->x; 13 | } 14 | 15 | float Vector2D::getY() const 16 | { 17 | return this->y; 18 | } 19 | 20 | void Vector2D::setX(float x) 21 | { 22 | this->x = x; 23 | } 24 | 25 | void Vector2D::setY(float y) 26 | { 27 | this->y = y; 28 | } 29 | 30 | float Vector2D::length() 31 | { 32 | return sqrt(pow(this->x, 2) + pow(this->y, 2)); 33 | } 34 | 35 | Vector2D Vector2D::operator+(const Vector2D& vector) 36 | { 37 | return Vector2D(this->x + vector.getX(), this->y + vector.getY()); 38 | } 39 | 40 | Vector2D& Vector2D::operator+=(const Vector2D& vector2) 41 | { 42 | this->setX(this->getX() + vector2.getX()); 43 | this->setY(this->getY() + vector2.getY()); 44 | return *this; 45 | } 46 | 47 | Vector2D Vector2D::operator*(float scalar) 48 | { 49 | return Vector2D(this->getX() * scalar, this->getY() * scalar); 50 | } 51 | 52 | Vector2D& Vector2D::operator*=(float scalar) 53 | { 54 | this->setX(this->getX() * scalar); 55 | this->setY(this->getY() * scalar); 56 | return *this; 57 | } 58 | 59 | Vector2D Vector2D::operator-(const Vector2D& vector) 60 | { 61 | return Vector2D(this->getX() - vector.getX(), this->getY() - vector.getY()); 62 | } 63 | 64 | Vector2D& Vector2D::operator-=(const Vector2D& vector2) 65 | { 66 | this->setX(this->getX() - vector2.getX()); 67 | this->setY(this->getY() - vector2.getY()); 68 | return *this; 69 | } 70 | 71 | Vector2D Vector2D::operator/(float scalar) 72 | { 73 | return Vector2D(this->getX() / scalar, this->getY() / scalar); 74 | } 75 | 76 | Vector2D& Vector2D::operator/=(float scalar) 77 | { 78 | this->setX(this->getX() / scalar); 79 | this->setY(this->getY() / scalar); 80 | return *this; 81 | } 82 | 83 | void Vector2D::normalize() 84 | { 85 | if (this->length() == 0) 86 | throw runtime_error("Math error: Attempted to divide by zero\n"); 87 | (*this) *= 1 / this->length(); 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/MenuState.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/MenuState.h" 2 | #include "../include/StateParser.h" 3 | #include "../include/TextureManager.h" 4 | #include "../include/MenuButton.h" 5 | #include "../include/Game.h" 6 | #include "../include/PlayState.h" 7 | 8 | const string MenuState::menuID = "MENU"; 9 | const string MainMenuState::menuID = "MENU"; 10 | 11 | bool MenuState::onEnter() 12 | { 13 | cout << "Entering menu state" << endl; 14 | return true; 15 | } 16 | 17 | bool MenuState::onExit() 18 | { 19 | cout << "Exiting menu state" << endl; 20 | return true; 21 | } 22 | 23 | void MenuState::render() 24 | { 25 | } 26 | 27 | void MenuState::update() 28 | { 29 | } 30 | 31 | string MenuState::getStateID() const{ return this->menuID; } 32 | 33 | 34 | MainMenuState::MainMenuState(): MenuState(){} 35 | 36 | string MainMenuState::getStateID() const{ return this->menuID; } 37 | 38 | bool MainMenuState::onEnter() 39 | { 40 | StateParser stateparser; 41 | stateparser.parseState(configFile, menuID, &gameObjects, &textureIDList); 42 | callbacks.push_back(0); 43 | callbacks.push_back(menuToPlay); 44 | callbacks.push_back(exitFromMenu); 45 | setCallbacks(callbacks); 46 | return true; 47 | } 48 | 49 | void MainMenuState::setCallbacks(const vector& callbacks) 50 | { 51 | for(auto gameObject: gameObjects) 52 | { 53 | if (dynamic_cast(gameObject)) 54 | { 55 | MenuButton* button = dynamic_cast(gameObject); 56 | button->setCallback(callbacks[button->getCallbackID()]); 57 | } 58 | } 59 | } 60 | 61 | bool MainMenuState::onExit() 62 | { 63 | for(auto textureIDs: textureIDList) 64 | { 65 | TextureManager::Instance()->clearFromTextureMap(textureIDs); 66 | } 67 | return true; 68 | } 69 | 70 | void MainMenuState::exitFromMenu() 71 | { 72 | Game::Instance()->quit(); 73 | } 74 | 75 | void MainMenuState::menuToPlay() 76 | { 77 | Game::Instance()->getStateMachine()->changeState(new PlayState()); 78 | } 79 | 80 | void MainMenuState::render() 81 | { 82 | for (auto object: gameObjects) 83 | object->draw();} 84 | 85 | void MainMenuState::update() 86 | { 87 | for (auto object: gameObjects) 88 | object->update(); 89 | } 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/UFO.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/UFO.h" 2 | #include "../include/Game.h" 3 | #include "../include/BulletHandler.h" 4 | 5 | UFO::UFO(): Enemy() 6 | { 7 | health = 1; 8 | moveSpeed = 2; 9 | } 10 | 11 | bool isOutOfWidth(Vector2D position) 12 | { 13 | if (position.getX() > Game::Instance()->getGameWidth() || 14 | position.getX() < 0) 15 | return true; 16 | return false; 17 | } 18 | 19 | bool isOutOfHeight(Vector2D position) 20 | { 21 | if (position.getY() > Game::Instance()->getGameHeight() || 22 | position.getY() < 0) 23 | return true; 24 | return false; 25 | } 26 | 27 | bool isInScreen(Vector2D position) 28 | { 29 | if (!isOutOfWidth(position) && !isOutOfHeight(position)) 30 | return true; 31 | return false; 32 | } 33 | 34 | void UFO::update() 35 | { 36 | if (!isDead()) 37 | { 38 | static int xShift = moveSpeed; 39 | static int yShift = moveSpeed; 40 | 41 | if (!isInScreen(position)) 42 | { 43 | if (isOutOfHeight(position) && isOutOfWidth(position)) 44 | { 45 | xShift = -xShift + 1; 46 | yShift = -yShift + 1; 47 | } 48 | else if (isOutOfWidth(position)) 49 | { 50 | xShift = -xShift; 51 | } 52 | else if (isOutOfHeight(position)) 53 | { 54 | yShift = -yShift; 55 | } 56 | } 57 | 58 | velocity.setX(xShift); 59 | velocity.setY(yShift); 60 | shoot(); 61 | } 62 | else 63 | { 64 | velocity.setX(0); 65 | velocity.setY(0); 66 | // TODO: Dying animation 67 | } 68 | ShooterObject::update(); 69 | } 70 | 71 | void UFO::shoot() 72 | { 73 | int x = rand() % 7 - 3; 74 | int y = rand() % 7 - 3; 75 | Vector2D heading = Vector2D(x, y); 76 | BulletHandler::Instance()->addEnemyBullet(position.getX(), position.getY(), 77 | 16, 16, "bullet", 1, heading); 78 | BulletHandler::Instance()->drawBullets(); 79 | 80 | } 81 | 82 | void UFO::collision() 83 | { 84 | health -= 1; 85 | if (health == 0) 86 | { 87 | // TODO: Dying animation 88 | delete this; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/PlayState.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/Game.h" 2 | #include "../include/PlayState.h" 3 | #include "../include/PauseState.h" 4 | #include "../include/InputHandler.h" 5 | #include "../include/GameOverState.h" 6 | #include "../include/TextureManager.h" 7 | #include "../include/BulletHandler.h" 8 | #include "../include/StateParser.h" 9 | 10 | const string PlayState::playID = "PLAY"; 11 | 12 | bool PlayState::onEnter() 13 | { 14 | Game::Instance()->setPlayerLives(5); 15 | 16 | StateParser stateParser; 17 | stateParser.parseState(configFile, playID, &gameObjects, &textureIDList); 18 | 19 | TextureManager::Instance()->load("assets/images/space.jpeg", 20 | "background", 21 | Game::Instance()->getRenderer()); 22 | TextureManager::Instance()->load("assets/images/bullet3.png", 23 | "bullet3", 24 | Game::Instance()->getRenderer()); 25 | 26 | cout << "Entering play state" << endl; 27 | return true; 28 | } 29 | 30 | bool PlayState::onExit() 31 | { 32 | InputHandler::Instance()->reset(); 33 | BulletHandler::Instance()->clearBullets(); 34 | cout << "Exiting play state" << endl; 35 | return true; 36 | } 37 | 38 | void PlayState::render() 39 | { 40 | for (auto gameObject: gameObjects) 41 | gameObject->draw(); 42 | 43 | BulletHandler::Instance()->drawBullets(); 44 | } 45 | 46 | void PlayState::update() 47 | { 48 | if (InputHandler::Instance()->isKeyDown(SDL_SCANCODE_ESCAPE)) 49 | Game::Instance()->getStateMachine()->pushState(new PauseState()); 50 | 51 | BulletHandler::Instance()->updateBullets(); 52 | 53 | if (Game::Instance()->getPlayerLives() == 0) 54 | Game::Instance()->getStateMachine()->changeState(new GameOverState()); 55 | 56 | for (auto object: gameObjects) 57 | { 58 | if (dynamic_cast(object)) 59 | { 60 | Player* player = dynamic_cast(object); 61 | collisionManager.checkPlayerEnemyCollision(player, gameObjects); 62 | collisionManager.checkPlayerEnemyBulletCollision(player); 63 | } 64 | collisionManager.checkEnemyPlayerBulletCollision(gameObjects); 65 | object->update(); 66 | } 67 | } 68 | 69 | string PlayState::getStateID() const{ return this->playID; } 70 | -------------------------------------------------------------------------------- /src/InputHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/InputHandler.h" 2 | #include "../include/Game.h" 3 | #include 4 | using namespace std; 5 | 6 | InputHandler* InputHandler::instance = 0; 7 | 8 | InputHandler::InputHandler() 9 | { 10 | keyState = SDL_GetKeyboardState(0); 11 | mousePosition = new Vector2D(); 12 | for (long unsigned int i = 1; i < sizeof(mouse_buttons); i++) 13 | mouseButtonStates.push_back(false); 14 | } 15 | InputHandler::~InputHandler(){} 16 | 17 | InputHandler* InputHandler::Instance() 18 | { 19 | if (instance == 0) 20 | instance = new InputHandler(); 21 | return instance; 22 | } 23 | 24 | void InputHandler::update() 25 | { 26 | 27 | SDL_Event event; 28 | while(SDL_PollEvent(&event)) 29 | { 30 | switch(event.type) 31 | { 32 | case SDL_MOUSEMOTION: 33 | mousePosition->setX(event.motion.x); 34 | mousePosition->setY(event.motion.y); 35 | break; 36 | case SDL_MOUSEBUTTONDOWN: 37 | if (event.button.button == SDL_BUTTON_LEFT) 38 | mouseButtonStates[LEFT] = true; 39 | 40 | if (event.button.button == SDL_BUTTON_MIDDLE) 41 | mouseButtonStates[MIDDLE] = true; 42 | 43 | if (event.button.button == SDL_BUTTON_RIGHT) 44 | mouseButtonStates[RIGHT] = true; 45 | break; 46 | case SDL_MOUSEBUTTONUP: 47 | if (event.button.button == SDL_BUTTON_LEFT) 48 | mouseButtonStates[LEFT] = false; 49 | 50 | if (event.button.button == SDL_BUTTON_MIDDLE) 51 | mouseButtonStates[MIDDLE] = false; 52 | 53 | if (event.button.button == SDL_BUTTON_RIGHT) 54 | mouseButtonStates[RIGHT] = false; 55 | break; 56 | case SDL_KEYUP: 57 | onKeyUp(); 58 | break; 59 | case SDL_KEYDOWN: 60 | onKeyDown(); 61 | break; 62 | case SDL_QUIT: 63 | Game::Instance()->quit(); 64 | break; 65 | default: 66 | break; 67 | 68 | } 69 | } 70 | } 71 | 72 | void InputHandler::onKeyDown() 73 | { 74 | } 75 | 76 | void InputHandler::onKeyUp() 77 | { 78 | } 79 | 80 | bool InputHandler::isKeyDown(SDL_Scancode key) 81 | { 82 | if (keyState != 0) 83 | return keyState[key]; 84 | return false; 85 | } 86 | 87 | bool InputHandler::getMouseButtonState(int buttonNumber){ return mouseButtonStates[buttonNumber]; } 88 | 89 | Vector2D * InputHandler::getMousePosition(){ return mousePosition; } 90 | 91 | void InputHandler::reset() 92 | { 93 | for (long unsigned int i = 0; i < sizeof(mouse_buttons) - 1; i++) 94 | mouseButtonStates[i] = false; 95 | } 96 | 97 | -------------------------------------------------------------------------------- /src/StateParser.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/Game.h" 2 | #include "../include/StateParser.h" 3 | #include "../include/TextureManager.h" 4 | #include "../include/GameObjectFactory.h" 5 | 6 | bool StateParser::parseState(const char* stateFile, string stateID, vector* objects, vector* textureIDs) 7 | { 8 | TiXmlDocument xmlDoc; 9 | if (!xmlDoc.LoadFile(stateFile)) 10 | { 11 | cerr << xmlDoc.ErrorDesc() << endl; 12 | return false; 13 | } 14 | 15 | TiXmlElement* root = xmlDoc.RootElement(); 16 | TiXmlElement* stateRoot = 0; 17 | 18 | for(TiXmlElement* element = root->FirstChildElement(); element != NULL; element = element->NextSiblingElement()) 19 | { 20 | if (element->Value() == stateID) 21 | stateRoot = element; 22 | } 23 | 24 | TiXmlElement* textureRoot = 0; 25 | for(TiXmlElement* element = stateRoot->FirstChildElement(); element != NULL; element = element->NextSiblingElement()) 26 | { 27 | if (element->Value() == string("TEXTURES")) 28 | textureRoot = element; 29 | } 30 | parseTexture(textureRoot, textureIDs); 31 | TiXmlElement* objectRoot = 0; 32 | 33 | for(TiXmlElement* element = stateRoot->FirstChildElement(); element != NULL; element = element->NextSiblingElement()) 34 | { 35 | if (element->Value() == string("OBJECTS")) 36 | objectRoot = element; 37 | } 38 | parseObjects(objectRoot, objects); 39 | 40 | return true; 41 | } 42 | 43 | void StateParser::parseTexture(TiXmlElement* stateRoot, vector* textureIDs) 44 | { 45 | for(TiXmlElement* element = stateRoot->FirstChildElement(); element != NULL; element = element->NextSiblingElement()) 46 | { 47 | string filename = element->Attribute("filename"); 48 | string id = element->Attribute("ID"); 49 | textureIDs->push_back(id); 50 | TextureManager::Instance()->load(filename, id, Game::Instance()->getRenderer()); 51 | } 52 | } 53 | 54 | void StateParser::parseObjects(TiXmlElement* stateRoot, vector* objects) 55 | { 56 | for(TiXmlElement* element = stateRoot->FirstChildElement(); element != NULL; element = element->NextSiblingElement()) 57 | { 58 | int x, y, width, height, numFrames, callbackID = 0, animSpeed = 0; 59 | string textureID; 60 | 61 | element->Attribute("x", &x); 62 | element->Attribute("y", &y); 63 | element->Attribute("width", &width); 64 | element->Attribute("height", &height); 65 | element->Attribute("numFrames", &numFrames); 66 | element->Attribute("callbackID", &callbackID); 67 | element->Attribute("animSpeed", &animSpeed); 68 | 69 | textureID = element->Attribute("textureID"); 70 | 71 | GameObject* gameObject = GameObjectFactory::Instance()->create(element->Attribute("type")); 72 | gameObject->load(unique_ptr(new LoaderParams(x, y, width, height, textureID, numFrames, callbackID, animSpeed))); 73 | objects->push_back(gameObject); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/tinystr.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | www.sourceforge.net/projects/tinyxml 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any 6 | damages arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any 9 | purpose, including commercial applications, and to alter it and 10 | redistribute it freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must 13 | not claim that you wrote the original software. If you use this 14 | software in a product, an acknowledgment in the product documentation 15 | would be appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, and 18 | must not be misrepresented as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source 21 | distribution. 22 | */ 23 | 24 | 25 | #ifndef TIXML_USE_STL 26 | 27 | #include "../include/tinystr.h" 28 | 29 | // Error value for find primitive 30 | const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); 31 | 32 | 33 | // Null rep. 34 | TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; 35 | 36 | 37 | void TiXmlString::reserve (size_type cap) 38 | { 39 | if (cap > capacity()) 40 | { 41 | TiXmlString tmp; 42 | tmp.init(length(), cap); 43 | memcpy(tmp.start(), data(), length()); 44 | swap(tmp); 45 | } 46 | } 47 | 48 | 49 | TiXmlString& TiXmlString::assign(const char* str, size_type len) 50 | { 51 | size_type cap = capacity(); 52 | if (len > cap || cap > 3*(len + 8)) 53 | { 54 | TiXmlString tmp; 55 | tmp.init(len); 56 | memcpy(tmp.start(), str, len); 57 | swap(tmp); 58 | } 59 | else 60 | { 61 | memmove(start(), str, len); 62 | set_size(len); 63 | } 64 | return *this; 65 | } 66 | 67 | 68 | TiXmlString& TiXmlString::append(const char* str, size_type len) 69 | { 70 | size_type newsize = length() + len; 71 | if (newsize > capacity()) 72 | { 73 | reserve (newsize + capacity()); 74 | } 75 | memmove(finish(), str, len); 76 | set_size(newsize); 77 | return *this; 78 | } 79 | 80 | 81 | TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) 82 | { 83 | TiXmlString tmp; 84 | tmp.reserve(a.length() + b.length()); 85 | tmp += a; 86 | tmp += b; 87 | return tmp; 88 | } 89 | 90 | TiXmlString operator + (const TiXmlString & a, const char* b) 91 | { 92 | TiXmlString tmp; 93 | TiXmlString::size_type b_len = static_cast( strlen(b) ); 94 | tmp.reserve(a.length() + b_len); 95 | tmp += a; 96 | tmp.append(b, b_len); 97 | return tmp; 98 | } 99 | 100 | TiXmlString operator + (const char* a, const TiXmlString & b) 101 | { 102 | TiXmlString tmp; 103 | TiXmlString::size_type a_len = static_cast( strlen(a) ); 104 | tmp.reserve(a_len + b.length()); 105 | tmp.append(a, a_len); 106 | tmp += b; 107 | return tmp; 108 | } 109 | 110 | 111 | #endif // TIXML_USE_STL 112 | -------------------------------------------------------------------------------- /src/Game.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/Game.h" 2 | #include "../include/TextureManager.h" 3 | #include "../include/GameObjectFactory.h" 4 | #include "../include/InputHandler.h" 5 | #include "../include/MenuState.h" 6 | #include "../include/PlayState.h" 7 | #include "../include/MenuButton.h" 8 | #include "../include/Comet.h" 9 | #include "../include/Player.h" 10 | #include "../include/UFO.h" 11 | 12 | Game* Game::instance = 0; 13 | 14 | Game::Game(): window(0), renderer(0), gameStateMachine(0), playerLives(5), run(false){} 15 | 16 | Game::~Game() 17 | { 18 | renderer = 0; 19 | window = 0; 20 | } 21 | 22 | bool Game::init(const char* title, int xpos, int ypos, int width, int height, int flags) 23 | { 24 | gameHeight = height; 25 | gameWidth = width; 26 | 27 | if (SDL_Init(SDL_INIT_EVERYTHING) == 0) 28 | { 29 | window = SDL_CreateWindow(title, xpos, ypos, width, height, flags); 30 | if (window) 31 | { 32 | renderer = SDL_CreateRenderer(window, -1, 0); 33 | if (renderer) 34 | { 35 | SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); 36 | } else 37 | { 38 | return false; 39 | } 40 | } else 41 | { 42 | return false; 43 | } 44 | } else 45 | { 46 | return false; 47 | } 48 | GameObjectFactory::Instance()->registerType("MenuButton", new MenuButtonCreator()); 49 | GameObjectFactory::Instance()->registerType("Player", new PlayerCreator()); 50 | GameObjectFactory::Instance()->registerType("Comet", new CometCreator()); 51 | GameObjectFactory::Instance()->registerType("UFO", new UFOCreator()); 52 | 53 | 54 | gameStateMachine = new GameStateMachine(); 55 | gameStateMachine->changeState(new MainMenuState()); 56 | 57 | run = true; 58 | return true; 59 | } 60 | 61 | void Game::render() 62 | { 63 | SDL_RenderClear(renderer); 64 | 65 | gameStateMachine->render(); 66 | 67 | SDL_RenderPresent(renderer); 68 | } 69 | 70 | void Game::update() 71 | { 72 | gameStateMachine->update(); 73 | } 74 | 75 | 76 | void Game::handleEvents() 77 | { 78 | InputHandler::Instance()->update(); 79 | if (InputHandler::Instance()->isKeyDown(SDL_SCANCODE_ESCAPE)) 80 | quit(); 81 | if (InputHandler::Instance()->isKeyDown(SDL_SCANCODE_RETURN)) 82 | gameStateMachine->changeState(new PlayState()); 83 | } 84 | 85 | void Game::clean() 86 | { 87 | gameStateMachine = 0; 88 | delete gameStateMachine; 89 | 90 | SDL_DestroyWindow(window); 91 | SDL_DestroyRenderer(renderer); 92 | SDL_Quit(); 93 | } 94 | 95 | bool Game::running(){ return this->run; } 96 | 97 | Game * Game::Instance() 98 | { 99 | if (instance == 0) 100 | instance = new Game(); 101 | return instance; 102 | } 103 | 104 | void Game::quit() 105 | { 106 | this->run = false; 107 | } 108 | 109 | SDL_Renderer* Game::getRenderer(){ return this->renderer; } 110 | 111 | GameStateMachine * Game::getStateMachine(){ return this->gameStateMachine; } 112 | -------------------------------------------------------------------------------- /src/BulletHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/BulletHandler.h" 2 | 3 | BulletHandler* BulletHandler::instance = 0; 4 | 5 | BulletHandler::BulletHandler(){} 6 | 7 | BulletHandler* BulletHandler::Instance() 8 | { 9 | if (instance == 0) 10 | instance = new BulletHandler(); 11 | return instance; 12 | } 13 | 14 | void BulletHandler::addPlayerBullet(int x, int y, int width, int height, 15 | string textureID, int numFrames, 16 | Vector2D heading) 17 | { 18 | PlayerBullet* playerBullet = new PlayerBullet(); 19 | LoaderParams* parameters = new LoaderParams(x, y, width, height, 20 | textureID, numFrames, 0, 0); 21 | playerBullet->load(unique_ptr(parameters), heading); 22 | playerBullets.push_back(playerBullet); 23 | } 24 | 25 | void BulletHandler::addEnemyBullet(int x, int y, int width, int height, 26 | string textureID, int numFrames, 27 | Vector2D heading) 28 | { 29 | EnemyBullet* enemyBullet = new EnemyBullet(); 30 | LoaderParams* parameters = new LoaderParams(x, y, width, height, 31 | textureID, numFrames, 0, 0); 32 | enemyBullet->load(unique_ptr(parameters), heading); 33 | enemyBullets.push_back(enemyBullet); 34 | } 35 | 36 | void BulletHandler::updateBullets() 37 | { 38 | vector::iterator playerIterator; 39 | for (playerIterator = playerBullets.begin(); playerIterator != playerBullets.end();) 40 | { 41 | PlayerBullet* bullet = *playerIterator; 42 | if (bullet->getPosition().getX() < 0 || 43 | bullet->getPosition().getY() < 0 || 44 | bullet->isDead()) 45 | { 46 | delete *playerIterator; 47 | playerBullets.erase(playerIterator); 48 | } 49 | else 50 | { 51 | bullet->update(); 52 | playerIterator++; 53 | } 54 | } 55 | 56 | vector::iterator enemyIterator; 57 | for (enemyIterator = enemyBullets.begin(); enemyIterator != enemyBullets.end();) 58 | { 59 | EnemyBullet* bullet = *enemyIterator; 60 | if (bullet->getPosition().getX() < 0 || 61 | bullet->getPosition().getY() < 0 || 62 | bullet->isDead()) 63 | { 64 | delete *enemyIterator; 65 | enemyBullets.erase(enemyIterator); 66 | } 67 | else 68 | { 69 | bullet->update(); 70 | enemyIterator++; 71 | } 72 | } 73 | } 74 | 75 | void BulletHandler::drawBullets() 76 | { 77 | for (auto bullet: playerBullets) 78 | bullet->draw(); 79 | 80 | for (auto bullet: enemyBullets) 81 | bullet->draw(); 82 | } 83 | 84 | void BulletHandler::clearBullets() 85 | { 86 | playerBullets.clear(); 87 | enemyBullets.clear(); 88 | } 89 | 90 | 91 | vector BulletHandler::getEnemyBullets() const 92 | { 93 | return enemyBullets; 94 | } 95 | 96 | vector BulletHandler::getPlayerBullets() const 97 | { 98 | return playerBullets; 99 | } 100 | 101 | -------------------------------------------------------------------------------- /src/CollisionManager.cpp: -------------------------------------------------------------------------------- 1 | #include "../include/CollisionManager.h" 2 | #include "../include/BulletHandler.h" 3 | #include "../include/Collision.h" 4 | 5 | void CollisionManager::checkPlayerEnemyBulletCollision(Player* player) 6 | { 7 | SDL_Rect* rectPlayer = new SDL_Rect(); 8 | rectPlayer->x = player->getPosition().getX(); 9 | rectPlayer->y = player->getPosition().getY(); 10 | rectPlayer->h = player->getHeight(); 11 | rectPlayer->w = player->getWidth(); 12 | 13 | for (auto bullet: BulletHandler::Instance()->getEnemyBullets()) 14 | { 15 | SDL_Rect* shot = new SDL_Rect(); 16 | shot->x = bullet->getPosition().getX(); 17 | shot->y = bullet->getPosition().getY(); 18 | shot->h = bullet->getHeight(); 19 | shot->w = bullet->getWidth(); 20 | 21 | if (RectRect(rectPlayer, shot)) 22 | { 23 | if (!player->isDead() && !bullet->isDead()) 24 | { 25 | bullet->collision(); 26 | player->collision(); 27 | } 28 | } 29 | delete shot; 30 | } 31 | delete rectPlayer; 32 | } 33 | 34 | void CollisionManager::checkPlayerEnemyCollision(Player* player, const vector &gameObjects) 35 | { 36 | SDL_Rect* rectPlayer = new SDL_Rect(); 37 | rectPlayer->x = player->getPosition().getX(); 38 | rectPlayer->y = player->getPosition().getY(); 39 | rectPlayer->h = player->getHeight(); 40 | rectPlayer->w = player->getWidth(); 41 | 42 | for (auto object: gameObjects) 43 | { 44 | if (object->type() != "Enemy" || !object->isUpdating()) 45 | continue; 46 | 47 | SDL_Rect* enemy = new SDL_Rect(); 48 | enemy->x = object->getPosition().getX(); 49 | enemy->y = object->getPosition().getY(); 50 | enemy->h = object->getHeight(); 51 | enemy->w = object->getWidth(); 52 | 53 | if (RectRect(rectPlayer, enemy)) 54 | { 55 | if (!object->isDead()) 56 | player->collision(); 57 | } 58 | delete enemy; 59 | } 60 | delete rectPlayer; 61 | } 62 | 63 | void CollisionManager::checkEnemyPlayerBulletCollision(const vector& gameObjects) 64 | { 65 | for (auto object: gameObjects) 66 | { 67 | for (auto playerBullets: BulletHandler::Instance()->getPlayerBullets()) 68 | { 69 | if (object->type() != "Enemy") 70 | continue; 71 | 72 | SDL_Rect* rectEnemy = new SDL_Rect(); 73 | rectEnemy->x = object->getPosition().getX(); 74 | rectEnemy->y = object->getPosition().getY(); 75 | rectEnemy->h = object->getHeight(); 76 | rectEnemy->w = object->getWidth(); 77 | 78 | SDL_Rect* playerShot = new SDL_Rect(); 79 | playerShot->x = playerBullets->getPosition().getX(); 80 | playerShot->y = playerBullets->getPosition().getY(); 81 | playerShot->h = playerBullets->getHeight(); 82 | playerShot->w = playerBullets->getWidth(); 83 | 84 | if (RectRect(rectEnemy, playerShot)) 85 | { 86 | playerBullets->collision(); 87 | object->collision(); 88 | } 89 | 90 | delete rectEnemy; 91 | delete playerShot; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Player.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../include/Player.h" 3 | #include "../include/InputHandler.h" 4 | #include "../include/BulletHandler.h" 5 | 6 | Player::Player(): ShooterObject() 7 | { 8 | angle = 0; 9 | myAngle = FIRST_QUADRANT; 10 | } 11 | 12 | 13 | void Player::draw() 14 | { 15 | ShooterObject::draw(); 16 | } 17 | 18 | void Player::update() 19 | { 20 | handleInput(); 21 | ShooterObject::update(); 22 | handleAnimation(); 23 | } 24 | 25 | void Player::clean() 26 | { 27 | ShooterObject::clean(); 28 | } 29 | 30 | void Player::setAngle(bool direction) 31 | { 32 | direction? angle += 10: angle -= 10; 33 | 34 | angle = (360 + (int) angle % 360) % 360; 35 | 36 | if (angle >= 0 && angle <= 90) 37 | { 38 | myAngle = FIRST_QUADRANT; 39 | } 40 | else if (angle > 90 && angle <= 180) 41 | { 42 | myAngle = SECOND_QUANDRANT; 43 | } 44 | else if (angle > 180 && angle <= 270) 45 | { 46 | myAngle = THIRD_QUADRANT; 47 | } 48 | else 49 | { 50 | myAngle = FOURTH_QUADRANT; 51 | } 52 | 53 | } 54 | 55 | void Player::handleInput() 56 | { 57 | if (!dead) 58 | { 59 | if (InputHandler::Instance()->isKeyDown(SDL_SCANCODE_RIGHT)) 60 | { 61 | setAngle(true); 62 | //velocity.setX(moveSpeed); 63 | } 64 | if (InputHandler::Instance()->isKeyDown(SDL_SCANCODE_LEFT)) 65 | { 66 | setAngle(false); 67 | //velocity.setX(moveSpeed); 68 | } 69 | if (InputHandler::Instance()->isKeyDown(SDL_SCANCODE_UP)) 70 | { 71 | cout << "posicao x: " << position.getX() << " y: " << position.getY() << endl; 72 | setVelocity(); 73 | } 74 | if (InputHandler::Instance()->isKeyDown(SDL_SCANCODE_SPACE)) 75 | { 76 | if (bulletCounter == bulletFiringSpeed) 77 | { 78 | BulletHandler::Instance()->addPlayerBullet(position.getX(), 79 | position.getY(), 80 | 11, 81 | 11, 82 | "bullet", 1, 83 | Vector2D(10,0)); 84 | bulletCounter = 0; 85 | } 86 | else 87 | { 88 | bulletCounter = bulletFiringSpeed; 89 | } 90 | } 91 | } 92 | } 93 | 94 | void Player::setVelocity() 95 | { 96 | // int xRotated = acceleration.getX() * cos(angle) + acceleration.getY() * sin(angle); 97 | // int yRotated = acceleration.getX() * -sin(angle) + acceleration.getY() * cos(angle); 98 | // 99 | // acceleration.setX(xRotated); 100 | // acceleration.setY(yRotated); 101 | // cout <<" Aceleration: x: " << acceleration.getX()<< " y: " << acceleration.getY() << endl; 102 | cout << angle << endl; 103 | acceleration.setX(0); 104 | acceleration.setY(0); 105 | switch(myAngle) 106 | { 107 | case FIRST_QUADRANT: 108 | if (angle == 0) 109 | acceleration.setY(-moveSpeed); 110 | else if (angle == 90) 111 | acceleration.setX(moveSpeed); 112 | else 113 | { 114 | acceleration.setY(-moveSpeed); 115 | acceleration.setX(moveSpeed); 116 | } 117 | break; 118 | case SECOND_QUANDRANT: 119 | acceleration.setY(moveSpeed); 120 | if (angle != 180) 121 | acceleration.setX(moveSpeed); 122 | break; 123 | case THIRD_QUADRANT: 124 | acceleration.setX(-moveSpeed); 125 | if (angle != 270) 126 | acceleration.setY(moveSpeed); 127 | break; 128 | case FOURTH_QUADRANT: 129 | acceleration.setX(-moveSpeed); 130 | acceleration.setY(-moveSpeed); 131 | break; 132 | } 133 | 134 | velocity += acceleration; 135 | } 136 | 137 | 138 | long int Player::getScore() const{ return this->score; } 139 | 140 | void Player::load(unique_ptr const ¶ms) 141 | { 142 | ShooterObject::load(move(params)); 143 | bulletFiringSpeed = 15; 144 | moveSpeed = 3; 145 | bulletCounter = bulletFiringSpeed; 146 | dyingTime = 100; 147 | } 148 | 149 | void Player::handleAnimation(){} 150 | -------------------------------------------------------------------------------- /include/tinystr.h: -------------------------------------------------------------------------------- 1 | /* 2 | www.sourceforge.net/projects/tinyxml 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any 6 | damages arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any 9 | purpose, including commercial applications, and to alter it and 10 | redistribute it freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must 13 | not claim that you wrote the original software. If you use this 14 | software in a product, an acknowledgment in the product documentation 15 | would be appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, and 18 | must not be misrepresented as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source 21 | distribution. 22 | */ 23 | 24 | 25 | #ifndef TIXML_USE_STL 26 | 27 | #ifndef TIXML_STRING_INCLUDED 28 | #define TIXML_STRING_INCLUDED 29 | 30 | #include 31 | #include 32 | 33 | /* The support for explicit isn't that universal, and it isn't really 34 | required - it is used to check that the TiXmlString class isn't incorrectly 35 | used. Be nice to old compilers and macro it here: 36 | */ 37 | #if defined(_MSC_VER) && (_MSC_VER >= 1200 ) 38 | // Microsoft visual studio, version 6 and higher. 39 | #define TIXML_EXPLICIT explicit 40 | #elif defined(__GNUC__) && (__GNUC__ >= 3 ) 41 | // GCC version 3 and higher.s 42 | #define TIXML_EXPLICIT explicit 43 | #else 44 | #define TIXML_EXPLICIT 45 | #endif 46 | 47 | 48 | /* 49 | TiXmlString is an emulation of a subset of the std::string template. 50 | Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. 51 | Only the member functions relevant to the TinyXML project have been implemented. 52 | The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase 53 | a string and there's no more room, we allocate a buffer twice as big as we need. 54 | */ 55 | class TiXmlString 56 | { 57 | public : 58 | // The size type used 59 | typedef size_t size_type; 60 | 61 | // Error value for find primitive 62 | static const size_type npos; // = -1; 63 | 64 | 65 | // TiXmlString empty constructor 66 | TiXmlString () : rep_(&nullrep_) 67 | { 68 | } 69 | 70 | // TiXmlString copy constructor 71 | TiXmlString ( const TiXmlString & copy) : rep_(0) 72 | { 73 | init(copy.length()); 74 | memcpy(start(), copy.data(), length()); 75 | } 76 | 77 | // TiXmlString constructor, based on a string 78 | TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) 79 | { 80 | init( static_cast( strlen(copy) )); 81 | memcpy(start(), copy, length()); 82 | } 83 | 84 | // TiXmlString constructor, based on a string 85 | TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) 86 | { 87 | init(len); 88 | memcpy(start(), str, len); 89 | } 90 | 91 | // TiXmlString destructor 92 | ~TiXmlString () 93 | { 94 | quit(); 95 | } 96 | 97 | TiXmlString& operator = (const char * copy) 98 | { 99 | return assign( copy, (size_type)strlen(copy)); 100 | } 101 | 102 | TiXmlString& operator = (const TiXmlString & copy) 103 | { 104 | return assign(copy.start(), copy.length()); 105 | } 106 | 107 | 108 | // += operator. Maps to append 109 | TiXmlString& operator += (const char * suffix) 110 | { 111 | return append(suffix, static_cast( strlen(suffix) )); 112 | } 113 | 114 | // += operator. Maps to append 115 | TiXmlString& operator += (char single) 116 | { 117 | return append(&single, 1); 118 | } 119 | 120 | // += operator. Maps to append 121 | TiXmlString& operator += (const TiXmlString & suffix) 122 | { 123 | return append(suffix.data(), suffix.length()); 124 | } 125 | 126 | 127 | // Convert a TiXmlString into a null-terminated char * 128 | const char * c_str () const { return rep_->str; } 129 | 130 | // Convert a TiXmlString into a char * (need not be null terminated). 131 | const char * data () const { return rep_->str; } 132 | 133 | // Return the length of a TiXmlString 134 | size_type length () const { return rep_->size; } 135 | 136 | // Alias for length() 137 | size_type size () const { return rep_->size; } 138 | 139 | // Checks if a TiXmlString is empty 140 | bool empty () const { return rep_->size == 0; } 141 | 142 | // Return capacity of string 143 | size_type capacity () const { return rep_->capacity; } 144 | 145 | 146 | // single char extraction 147 | const char& at (size_type index) const 148 | { 149 | assert( index < length() ); 150 | return rep_->str[ index ]; 151 | } 152 | 153 | // [] operator 154 | char& operator [] (size_type index) const 155 | { 156 | assert( index < length() ); 157 | return rep_->str[ index ]; 158 | } 159 | 160 | // find a char in a string. Return TiXmlString::npos if not found 161 | size_type find (char lookup) const 162 | { 163 | return find(lookup, 0); 164 | } 165 | 166 | // find a char in a string from an offset. Return TiXmlString::npos if not found 167 | size_type find (char tofind, size_type offset) const 168 | { 169 | if (offset >= length()) return npos; 170 | 171 | for (const char* p = c_str() + offset; *p != '\0'; ++p) 172 | { 173 | if (*p == tofind) return static_cast< size_type >( p - c_str() ); 174 | } 175 | return npos; 176 | } 177 | 178 | void clear () 179 | { 180 | //Lee: 181 | //The original was just too strange, though correct: 182 | // TiXmlString().swap(*this); 183 | //Instead use the quit & re-init: 184 | quit(); 185 | init(0,0); 186 | } 187 | 188 | /* Function to reserve a big amount of data when we know we'll need it. Be aware that this 189 | function DOES NOT clear the content of the TiXmlString if any exists. 190 | */ 191 | void reserve (size_type cap); 192 | 193 | TiXmlString& assign (const char* str, size_type len); 194 | 195 | TiXmlString& append (const char* str, size_type len); 196 | 197 | void swap (TiXmlString& other) 198 | { 199 | Rep* r = rep_; 200 | rep_ = other.rep_; 201 | other.rep_ = r; 202 | } 203 | 204 | private: 205 | 206 | void init(size_type sz) { init(sz, sz); } 207 | void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } 208 | char* start() const { return rep_->str; } 209 | char* finish() const { return rep_->str + rep_->size; } 210 | 211 | struct Rep 212 | { 213 | size_type size, capacity; 214 | char str[1]; 215 | }; 216 | 217 | void init(size_type sz, size_type cap) 218 | { 219 | if (cap) 220 | { 221 | // Lee: the original form: 222 | // rep_ = static_cast(operator new(sizeof(Rep) + cap)); 223 | // doesn't work in some cases of new being overloaded. Switching 224 | // to the normal allocation, although use an 'int' for systems 225 | // that are overly picky about structure alignment. 226 | const size_type bytesNeeded = sizeof(Rep) + cap; 227 | const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); 228 | rep_ = reinterpret_cast( new int[ intsNeeded ] ); 229 | 230 | rep_->str[ rep_->size = sz ] = '\0'; 231 | rep_->capacity = cap; 232 | } 233 | else 234 | { 235 | rep_ = &nullrep_; 236 | } 237 | } 238 | 239 | void quit() 240 | { 241 | if (rep_ != &nullrep_) 242 | { 243 | // The rep_ is really an array of ints. (see the allocator, above). 244 | // Cast it back before delete, so the compiler won't incorrectly call destructors. 245 | delete [] ( reinterpret_cast( rep_ ) ); 246 | } 247 | } 248 | 249 | Rep * rep_; 250 | static Rep nullrep_; 251 | 252 | } ; 253 | 254 | 255 | inline bool operator == (const TiXmlString & a, const TiXmlString & b) 256 | { 257 | return ( a.length() == b.length() ) // optimization on some platforms 258 | && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare 259 | } 260 | inline bool operator < (const TiXmlString & a, const TiXmlString & b) 261 | { 262 | return strcmp(a.c_str(), b.c_str()) < 0; 263 | } 264 | 265 | inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } 266 | inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } 267 | inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } 268 | inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } 269 | 270 | inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } 271 | inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } 272 | inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } 273 | inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } 274 | 275 | TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); 276 | TiXmlString operator + (const TiXmlString & a, const char* b); 277 | TiXmlString operator + (const char* a, const TiXmlString & b); 278 | 279 | 280 | /* 281 | TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. 282 | Only the operators that we need for TinyXML have been developped. 283 | */ 284 | class TiXmlOutStream : public TiXmlString 285 | { 286 | public : 287 | 288 | // TiXmlOutStream << operator. 289 | TiXmlOutStream & operator << (const TiXmlString & in) 290 | { 291 | *this += in; 292 | return *this; 293 | } 294 | 295 | // TiXmlOutStream << operator. 296 | TiXmlOutStream & operator << (const char * in) 297 | { 298 | *this += in; 299 | return *this; 300 | } 301 | 302 | } ; 303 | 304 | #endif // TIXML_STRING_INCLUDED 305 | #endif // TIXML_USE_STL 306 | -------------------------------------------------------------------------------- /src/tinyxmlparser.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | www.sourceforge.net/projects/tinyxml 3 | Original code by Lee Thomason (www.grinninglizard.com) 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any 7 | damages arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any 10 | purpose, including commercial applications, and to alter it and 11 | redistribute it freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must 14 | not claim that you wrote the original software. If you use this 15 | software in a product, an acknowledgment in the product documentation 16 | would be appreciated but is not required. 17 | 18 | 2. Altered source versions must be plainly marked as such, and 19 | must not be misrepresented as being the original software. 20 | 21 | 3. This notice may not be removed or altered from any source 22 | distribution. 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | #include "../include/tinyxml.h" 29 | 30 | //#define DEBUG_PARSER 31 | #if defined( DEBUG_PARSER ) 32 | # if defined( DEBUG ) && defined( _MSC_VER ) 33 | # include 34 | # define TIXML_LOG OutputDebugString 35 | # else 36 | # define TIXML_LOG printf 37 | # endif 38 | #endif 39 | 40 | // Note tha "PutString" hardcodes the same list. This 41 | // is less flexible than it appears. Changing the entries 42 | // or order will break putstring. 43 | TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = 44 | { 45 | { "&", 5, '&' }, 46 | { "<", 4, '<' }, 47 | { ">", 4, '>' }, 48 | { """, 6, '\"' }, 49 | { "'", 6, '\'' } 50 | }; 51 | 52 | // Bunch of unicode info at: 53 | // http://www.unicode.org/faq/utf_bom.html 54 | // Including the basic of this table, which determines the #bytes in the 55 | // sequence from the lead byte. 1 placed for invalid sequences -- 56 | // although the result will be junk, pass it through as much as possible. 57 | // Beware of the non-characters in UTF-8: 58 | // ef bb bf (Microsoft "lead bytes") 59 | // ef bf be 60 | // ef bf bf 61 | 62 | const unsigned char TIXML_UTF_LEAD_0 = 0xefU; 63 | const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; 64 | const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; 65 | 66 | const int TiXmlBase::utf8ByteTable[256] = 67 | { 68 | // 0 1 2 3 4 5 6 7 8 9 a b c d e f 69 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 70 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 71 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 72 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 73 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 74 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 75 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 76 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range 77 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid 78 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 79 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 80 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 81 | 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte 82 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 83 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte 84 | 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid 85 | }; 86 | 87 | 88 | void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) 89 | { 90 | const unsigned long BYTE_MASK = 0xBF; 91 | const unsigned long BYTE_MARK = 0x80; 92 | const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 93 | 94 | if (input < 0x80) 95 | *length = 1; 96 | else if ( input < 0x800 ) 97 | *length = 2; 98 | else if ( input < 0x10000 ) 99 | *length = 3; 100 | else if ( input < 0x200000 ) 101 | *length = 4; 102 | else 103 | { *length = 0; return; } // This code won't covert this correctly anyway. 104 | 105 | output += *length; 106 | 107 | // Scary scary fall throughs. 108 | switch (*length) 109 | { 110 | case 4: 111 | --output; 112 | *output = (char)((input | BYTE_MARK) & BYTE_MASK); 113 | input >>= 6; 114 | case 3: 115 | --output; 116 | *output = (char)((input | BYTE_MARK) & BYTE_MASK); 117 | input >>= 6; 118 | case 2: 119 | --output; 120 | *output = (char)((input | BYTE_MARK) & BYTE_MASK); 121 | input >>= 6; 122 | case 1: 123 | --output; 124 | *output = (char)(input | FIRST_BYTE_MARK[*length]); 125 | } 126 | } 127 | 128 | 129 | /*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) 130 | { 131 | // This will only work for low-ascii, everything else is assumed to be a valid 132 | // letter. I'm not sure this is the best approach, but it is quite tricky trying 133 | // to figure out alhabetical vs. not across encoding. So take a very 134 | // conservative approach. 135 | 136 | // if ( encoding == TIXML_ENCODING_UTF8 ) 137 | // { 138 | if ( anyByte < 127 ) 139 | return isalpha( anyByte ); 140 | else 141 | return 1; // What else to do? The unicode set is huge...get the english ones right. 142 | // } 143 | // else 144 | // { 145 | // return isalpha( anyByte ); 146 | // } 147 | } 148 | 149 | 150 | /*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) 151 | { 152 | // This will only work for low-ascii, everything else is assumed to be a valid 153 | // letter. I'm not sure this is the best approach, but it is quite tricky trying 154 | // to figure out alhabetical vs. not across encoding. So take a very 155 | // conservative approach. 156 | 157 | // if ( encoding == TIXML_ENCODING_UTF8 ) 158 | // { 159 | if ( anyByte < 127 ) 160 | return isalnum( anyByte ); 161 | else 162 | return 1; // What else to do? The unicode set is huge...get the english ones right. 163 | // } 164 | // else 165 | // { 166 | // return isalnum( anyByte ); 167 | // } 168 | } 169 | 170 | 171 | class TiXmlParsingData 172 | { 173 | friend class TiXmlDocument; 174 | public: 175 | void Stamp( const char* now, TiXmlEncoding encoding ); 176 | 177 | const TiXmlCursor& Cursor() const { return cursor; } 178 | 179 | private: 180 | // Only used by the document! 181 | TiXmlParsingData( const char* start, int _tabsize, int row, int col ) 182 | { 183 | assert( start ); 184 | stamp = start; 185 | tabsize = _tabsize; 186 | cursor.row = row; 187 | cursor.col = col; 188 | } 189 | 190 | TiXmlCursor cursor; 191 | const char* stamp; 192 | int tabsize; 193 | }; 194 | 195 | 196 | void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) 197 | { 198 | assert( now ); 199 | 200 | // Do nothing if the tabsize is 0. 201 | if ( tabsize < 1 ) 202 | { 203 | return; 204 | } 205 | 206 | // Get the current row, column. 207 | int row = cursor.row; 208 | int col = cursor.col; 209 | const char* p = stamp; 210 | assert( p ); 211 | 212 | while ( p < now ) 213 | { 214 | // Treat p as unsigned, so we have a happy compiler. 215 | const unsigned char* pU = (const unsigned char*)p; 216 | 217 | // Code contributed by Fletcher Dunn: (modified by lee) 218 | switch (*pU) { 219 | case 0: 220 | // We *should* never get here, but in case we do, don't 221 | // advance past the terminating null character, ever 222 | return; 223 | 224 | case '\r': 225 | // bump down to the next line 226 | ++row; 227 | col = 0; 228 | // Eat the character 229 | ++p; 230 | 231 | // Check for \r\n sequence, and treat this as a single character 232 | if (*p == '\n') { 233 | ++p; 234 | } 235 | break; 236 | 237 | case '\n': 238 | // bump down to the next line 239 | ++row; 240 | col = 0; 241 | 242 | // Eat the character 243 | ++p; 244 | 245 | // Check for \n\r sequence, and treat this as a single 246 | // character. (Yes, this bizarre thing does occur still 247 | // on some arcane platforms...) 248 | if (*p == '\r') { 249 | ++p; 250 | } 251 | break; 252 | 253 | case '\t': 254 | // Eat the character 255 | ++p; 256 | 257 | // Skip to next tab stop 258 | col = (col / tabsize + 1) * tabsize; 259 | break; 260 | 261 | case TIXML_UTF_LEAD_0: 262 | if ( encoding == TIXML_ENCODING_UTF8 ) 263 | { 264 | if ( *(p+1) && *(p+2) ) 265 | { 266 | // In these cases, don't advance the column. These are 267 | // 0-width spaces. 268 | if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) 269 | p += 3; 270 | else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) 271 | p += 3; 272 | else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) 273 | p += 3; 274 | else 275 | { p +=3; ++col; } // A normal character. 276 | } 277 | } 278 | else 279 | { 280 | ++p; 281 | ++col; 282 | } 283 | break; 284 | 285 | default: 286 | if ( encoding == TIXML_ENCODING_UTF8 ) 287 | { 288 | // Eat the 1 to 4 byte utf8 character. 289 | int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; 290 | if ( step == 0 ) 291 | step = 1; // Error case from bad encoding, but handle gracefully. 292 | p += step; 293 | 294 | // Just advance one column, of course. 295 | ++col; 296 | } 297 | else 298 | { 299 | ++p; 300 | ++col; 301 | } 302 | break; 303 | } 304 | } 305 | cursor.row = row; 306 | cursor.col = col; 307 | assert( cursor.row >= -1 ); 308 | assert( cursor.col >= -1 ); 309 | stamp = p; 310 | assert( stamp ); 311 | } 312 | 313 | 314 | const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) 315 | { 316 | if ( !p || !*p ) 317 | { 318 | return 0; 319 | } 320 | if ( encoding == TIXML_ENCODING_UTF8 ) 321 | { 322 | while ( *p ) 323 | { 324 | const unsigned char* pU = (const unsigned char*)p; 325 | 326 | // Skip the stupid Microsoft UTF-8 Byte order marks 327 | if ( *(pU+0)==TIXML_UTF_LEAD_0 328 | && *(pU+1)==TIXML_UTF_LEAD_1 329 | && *(pU+2)==TIXML_UTF_LEAD_2 ) 330 | { 331 | p += 3; 332 | continue; 333 | } 334 | else if(*(pU+0)==TIXML_UTF_LEAD_0 335 | && *(pU+1)==0xbfU 336 | && *(pU+2)==0xbeU ) 337 | { 338 | p += 3; 339 | continue; 340 | } 341 | else if(*(pU+0)==TIXML_UTF_LEAD_0 342 | && *(pU+1)==0xbfU 343 | && *(pU+2)==0xbfU ) 344 | { 345 | p += 3; 346 | continue; 347 | } 348 | 349 | if ( IsWhiteSpace( *p ) ) // Still using old rules for white space. 350 | ++p; 351 | else 352 | break; 353 | } 354 | } 355 | else 356 | { 357 | while ( *p && IsWhiteSpace( *p ) ) 358 | ++p; 359 | } 360 | 361 | return p; 362 | } 363 | 364 | #ifdef TIXML_USE_STL 365 | /*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) 366 | { 367 | for( ;; ) 368 | { 369 | if ( !in->good() ) return false; 370 | 371 | int c = in->peek(); 372 | // At this scope, we can't get to a document. So fail silently. 373 | if ( !IsWhiteSpace( c ) || c <= 0 ) 374 | return true; 375 | 376 | *tag += (char) in->get(); 377 | } 378 | } 379 | 380 | /*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) 381 | { 382 | //assert( character > 0 && character < 128 ); // else it won't work in utf-8 383 | while ( in->good() ) 384 | { 385 | int c = in->peek(); 386 | if ( c == character ) 387 | return true; 388 | if ( c <= 0 ) // Silent failure: can't get document at this scope 389 | return false; 390 | 391 | in->get(); 392 | *tag += (char) c; 393 | } 394 | return false; 395 | } 396 | #endif 397 | 398 | // One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The 399 | // "assign" optimization removes over 10% of the execution time. 400 | // 401 | const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) 402 | { 403 | // Oddly, not supported on some comilers, 404 | //name->clear(); 405 | // So use this: 406 | *name = ""; 407 | assert( p ); 408 | 409 | // Names start with letters or underscores. 410 | // Of course, in unicode, tinyxml has no idea what a letter *is*. The 411 | // algorithm is generous. 412 | // 413 | // After that, they can be letters, underscores, numbers, 414 | // hyphens, or colons. (Colons are valid ony for namespaces, 415 | // but tinyxml can't tell namespaces from names.) 416 | if ( p && *p 417 | && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) 418 | { 419 | const char* start = p; 420 | while( p && *p 421 | && ( IsAlphaNum( (unsigned char ) *p, encoding ) 422 | || *p == '_' 423 | || *p == '-' 424 | || *p == '.' 425 | || *p == ':' ) ) 426 | { 427 | //(*name) += *p; // expensive 428 | ++p; 429 | } 430 | if ( p-start > 0 ) { 431 | name->assign( start, p-start ); 432 | } 433 | return p; 434 | } 435 | return 0; 436 | } 437 | 438 | const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) 439 | { 440 | // Presume an entity, and pull it out. 441 | TIXML_STRING ent; 442 | int i; 443 | *length = 0; 444 | 445 | if ( *(p+1) && *(p+1) == '#' && *(p+2) ) 446 | { 447 | unsigned long ucs = 0; 448 | ptrdiff_t delta = 0; 449 | unsigned mult = 1; 450 | 451 | if ( *(p+2) == 'x' ) 452 | { 453 | // Hexadecimal. 454 | if ( !*(p+3) ) return 0; 455 | 456 | const char* q = p+3; 457 | q = strchr( q, ';' ); 458 | 459 | if ( !q || !*q ) return 0; 460 | 461 | delta = q-p; 462 | --q; 463 | 464 | while ( *q != 'x' ) 465 | { 466 | if ( *q >= '0' && *q <= '9' ) 467 | ucs += mult * (*q - '0'); 468 | else if ( *q >= 'a' && *q <= 'f' ) 469 | ucs += mult * (*q - 'a' + 10); 470 | else if ( *q >= 'A' && *q <= 'F' ) 471 | ucs += mult * (*q - 'A' + 10 ); 472 | else 473 | return 0; 474 | mult *= 16; 475 | --q; 476 | } 477 | } 478 | else 479 | { 480 | // Decimal. 481 | if ( !*(p+2) ) return 0; 482 | 483 | const char* q = p+2; 484 | q = strchr( q, ';' ); 485 | 486 | if ( !q || !*q ) return 0; 487 | 488 | delta = q-p; 489 | --q; 490 | 491 | while ( *q != '#' ) 492 | { 493 | if ( *q >= '0' && *q <= '9' ) 494 | ucs += mult * (*q - '0'); 495 | else 496 | return 0; 497 | mult *= 10; 498 | --q; 499 | } 500 | } 501 | if ( encoding == TIXML_ENCODING_UTF8 ) 502 | { 503 | // convert the UCS to UTF-8 504 | ConvertUTF32ToUTF8( ucs, value, length ); 505 | } 506 | else 507 | { 508 | *value = (char)ucs; 509 | *length = 1; 510 | } 511 | return p + delta + 1; 512 | } 513 | 514 | // Now try to match it. 515 | for( i=0; iappend( cArr, len ); 594 | } 595 | } 596 | else 597 | { 598 | bool whitespace = false; 599 | 600 | // Remove leading white space: 601 | p = SkipWhiteSpace( p, encoding ); 602 | while ( p && *p 603 | && !StringEqual( p, endTag, caseInsensitive, encoding ) ) 604 | { 605 | if ( *p == '\r' || *p == '\n' ) 606 | { 607 | whitespace = true; 608 | ++p; 609 | } 610 | else if ( IsWhiteSpace( *p ) ) 611 | { 612 | whitespace = true; 613 | ++p; 614 | } 615 | else 616 | { 617 | // If we've found whitespace, add it before the 618 | // new character. Any whitespace just becomes a space. 619 | if ( whitespace ) 620 | { 621 | (*text) += ' '; 622 | whitespace = false; 623 | } 624 | int len; 625 | char cArr[4] = { 0, 0, 0, 0 }; 626 | p = GetChar( p, cArr, &len, encoding ); 627 | if ( len == 1 ) 628 | (*text) += cArr[0]; // more efficient 629 | else 630 | text->append( cArr, len ); 631 | } 632 | } 633 | } 634 | if ( p && *p ) 635 | p += strlen( endTag ); 636 | return ( p && *p ) ? p : 0; 637 | } 638 | 639 | #ifdef TIXML_USE_STL 640 | 641 | void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) 642 | { 643 | // The basic issue with a document is that we don't know what we're 644 | // streaming. Read something presumed to be a tag (and hope), then 645 | // identify it, and call the appropriate stream method on the tag. 646 | // 647 | // This "pre-streaming" will never read the closing ">" so the 648 | // sub-tag can orient itself. 649 | 650 | if ( !StreamTo( in, '<', tag ) ) 651 | { 652 | SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); 653 | return; 654 | } 655 | 656 | while ( in->good() ) 657 | { 658 | int tagIndex = (int) tag->length(); 659 | while ( in->good() && in->peek() != '>' ) 660 | { 661 | int c = in->get(); 662 | if ( c <= 0 ) 663 | { 664 | SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); 665 | break; 666 | } 667 | (*tag) += (char) c; 668 | } 669 | 670 | if ( in->good() ) 671 | { 672 | // We now have something we presume to be a node of 673 | // some sort. Identify it, and call the node to 674 | // continue streaming. 675 | TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); 676 | 677 | if ( node ) 678 | { 679 | node->StreamIn( in, tag ); 680 | bool isElement = node->ToElement() != 0; 681 | delete node; 682 | node = 0; 683 | 684 | // If this is the root element, we're done. Parsing will be 685 | // done by the >> operator. 686 | if ( isElement ) 687 | { 688 | return; 689 | } 690 | } 691 | else 692 | { 693 | SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); 694 | return; 695 | } 696 | } 697 | } 698 | // We should have returned sooner. 699 | SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); 700 | } 701 | 702 | #endif 703 | 704 | const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) 705 | { 706 | ClearError(); 707 | 708 | // Parse away, at the document level. Since a document 709 | // contains nothing but other tags, most of what happens 710 | // here is skipping white space. 711 | if ( !p || !*p ) 712 | { 713 | SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); 714 | return 0; 715 | } 716 | 717 | // Note that, for a document, this needs to come 718 | // before the while space skip, so that parsing 719 | // starts from the pointer we are given. 720 | location.Clear(); 721 | if ( prevData ) 722 | { 723 | location.row = prevData->cursor.row; 724 | location.col = prevData->cursor.col; 725 | } 726 | else 727 | { 728 | location.row = 0; 729 | location.col = 0; 730 | } 731 | TiXmlParsingData data( p, TabSize(), location.row, location.col ); 732 | location = data.Cursor(); 733 | 734 | if ( encoding == TIXML_ENCODING_UNKNOWN ) 735 | { 736 | // Check for the Microsoft UTF-8 lead bytes. 737 | const unsigned char* pU = (const unsigned char*)p; 738 | if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 739 | && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 740 | && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) 741 | { 742 | encoding = TIXML_ENCODING_UTF8; 743 | useMicrosoftBOM = true; 744 | } 745 | } 746 | 747 | p = SkipWhiteSpace( p, encoding ); 748 | if ( !p ) 749 | { 750 | SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); 751 | return 0; 752 | } 753 | 754 | while ( p && *p ) 755 | { 756 | TiXmlNode* node = Identify( p, encoding ); 757 | if ( node ) 758 | { 759 | p = node->Parse( p, &data, encoding ); 760 | LinkEndChild( node ); 761 | } 762 | else 763 | { 764 | break; 765 | } 766 | 767 | // Did we get encoding info? 768 | if ( encoding == TIXML_ENCODING_UNKNOWN 769 | && node->ToDeclaration() ) 770 | { 771 | TiXmlDeclaration* dec = node->ToDeclaration(); 772 | const char* enc = dec->Encoding(); 773 | assert( enc ); 774 | 775 | if ( *enc == 0 ) 776 | encoding = TIXML_ENCODING_UTF8; 777 | else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) 778 | encoding = TIXML_ENCODING_UTF8; 779 | else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) 780 | encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice 781 | else 782 | encoding = TIXML_ENCODING_LEGACY; 783 | } 784 | 785 | p = SkipWhiteSpace( p, encoding ); 786 | } 787 | 788 | // Was this empty? 789 | if ( !firstChild ) { 790 | SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); 791 | return 0; 792 | } 793 | 794 | // All is well. 795 | return p; 796 | } 797 | 798 | void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) 799 | { 800 | // The first error in a chain is more accurate - don't set again! 801 | if ( error ) 802 | return; 803 | 804 | assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); 805 | error = true; 806 | errorId = err; 807 | errorDesc = errorString[ errorId ]; 808 | 809 | errorLocation.Clear(); 810 | if ( pError && data ) 811 | { 812 | data->Stamp( pError, encoding ); 813 | errorLocation = data->Cursor(); 814 | } 815 | } 816 | 817 | 818 | TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) 819 | { 820 | TiXmlNode* returnNode = 0; 821 | 822 | p = SkipWhiteSpace( p, encoding ); 823 | if( !p || !*p || *p != '<' ) 824 | { 825 | return 0; 826 | } 827 | 828 | p = SkipWhiteSpace( p, encoding ); 829 | 830 | if ( !p || !*p ) 831 | { 832 | return 0; 833 | } 834 | 835 | // What is this thing? 836 | // - Elements start with a letter or underscore, but xml is reserved. 837 | // - Comments: "; 1351 | 1352 | if ( !StringEqual( p, startTag, false, encoding ) ) 1353 | { 1354 | if ( document ) 1355 | document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); 1356 | return 0; 1357 | } 1358 | p += strlen( startTag ); 1359 | 1360 | // [ 1475201 ] TinyXML parses entities in comments 1361 | // Oops - ReadText doesn't work, because we don't want to parse the entities. 1362 | // p = ReadText( p, &value, false, endTag, false, encoding ); 1363 | // 1364 | // from the XML spec: 1365 | /* 1366 | [Definition: Comments may appear anywhere in a document outside other markup; in addition, 1367 | they may appear within the document type declaration at places allowed by the grammar. 1368 | They are not part of the document's character data; an XML processor MAY, but need not, 1369 | make it possible for an application to retrieve the text of comments. For compatibility, 1370 | the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity 1371 | references MUST NOT be recognized within comments. 1372 | 1373 | An example of a comment: 1374 | 1375 | 1376 | */ 1377 | 1378 | value = ""; 1379 | // Keep all the white space. 1380 | while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) 1381 | { 1382 | value.append( p, 1 ); 1383 | ++p; 1384 | } 1385 | if ( p && *p ) 1386 | p += strlen( endTag ); 1387 | 1388 | return p; 1389 | } 1390 | 1391 | 1392 | const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) 1393 | { 1394 | p = SkipWhiteSpace( p, encoding ); 1395 | if ( !p || !*p ) return 0; 1396 | 1397 | if ( data ) 1398 | { 1399 | data->Stamp( p, encoding ); 1400 | location = data->Cursor(); 1401 | } 1402 | // Read the name, the '=' and the value. 1403 | const char* pErr = p; 1404 | p = ReadName( p, &name, encoding ); 1405 | if ( !p || !*p ) 1406 | { 1407 | if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); 1408 | return 0; 1409 | } 1410 | p = SkipWhiteSpace( p, encoding ); 1411 | if ( !p || !*p || *p != '=' ) 1412 | { 1413 | if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); 1414 | return 0; 1415 | } 1416 | 1417 | ++p; // skip '=' 1418 | p = SkipWhiteSpace( p, encoding ); 1419 | if ( !p || !*p ) 1420 | { 1421 | if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); 1422 | return 0; 1423 | } 1424 | 1425 | const char* end; 1426 | const char SINGLE_QUOTE = '\''; 1427 | const char DOUBLE_QUOTE = '\"'; 1428 | 1429 | if ( *p == SINGLE_QUOTE ) 1430 | { 1431 | ++p; 1432 | end = "\'"; // single quote in string 1433 | p = ReadText( p, &value, false, end, false, encoding ); 1434 | } 1435 | else if ( *p == DOUBLE_QUOTE ) 1436 | { 1437 | ++p; 1438 | end = "\""; // double quote in string 1439 | p = ReadText( p, &value, false, end, false, encoding ); 1440 | } 1441 | else 1442 | { 1443 | // All attribute values should be in single or double quotes. 1444 | // But this is such a common error that the parser will try 1445 | // its best, even without them. 1446 | value = ""; 1447 | while ( p && *p // existence 1448 | && !IsWhiteSpace( *p ) // whitespace 1449 | && *p != '/' && *p != '>' ) // tag end 1450 | { 1451 | if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { 1452 | // [ 1451649 ] Attribute values with trailing quotes not handled correctly 1453 | // We did not have an opening quote but seem to have a 1454 | // closing one. Give up and throw an error. 1455 | if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); 1456 | return 0; 1457 | } 1458 | value += *p; 1459 | ++p; 1460 | } 1461 | } 1462 | return p; 1463 | } 1464 | 1465 | #ifdef TIXML_USE_STL 1466 | void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) 1467 | { 1468 | while ( in->good() ) 1469 | { 1470 | int c = in->peek(); 1471 | if ( !cdata && (c == '<' ) ) 1472 | { 1473 | return; 1474 | } 1475 | if ( c <= 0 ) 1476 | { 1477 | TiXmlDocument* document = GetDocument(); 1478 | if ( document ) 1479 | document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); 1480 | return; 1481 | } 1482 | 1483 | (*tag) += (char) c; 1484 | in->get(); // "commits" the peek made above 1485 | 1486 | if ( cdata && c == '>' && tag->size() >= 3 ) { 1487 | size_t len = tag->size(); 1488 | if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { 1489 | // terminator of cdata. 1490 | return; 1491 | } 1492 | } 1493 | } 1494 | } 1495 | #endif 1496 | 1497 | const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) 1498 | { 1499 | value = ""; 1500 | TiXmlDocument* document = GetDocument(); 1501 | 1502 | if ( data ) 1503 | { 1504 | data->Stamp( p, encoding ); 1505 | location = data->Cursor(); 1506 | } 1507 | 1508 | const char* const startTag = ""; 1510 | 1511 | if ( cdata || StringEqual( p, startTag, false, encoding ) ) 1512 | { 1513 | cdata = true; 1514 | 1515 | if ( !StringEqual( p, startTag, false, encoding ) ) 1516 | { 1517 | if ( document ) 1518 | document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); 1519 | return 0; 1520 | } 1521 | p += strlen( startTag ); 1522 | 1523 | // Keep all the white space, ignore the encoding, etc. 1524 | while ( p && *p 1525 | && !StringEqual( p, endTag, false, encoding ) 1526 | ) 1527 | { 1528 | value += *p; 1529 | ++p; 1530 | } 1531 | 1532 | TIXML_STRING dummy; 1533 | p = ReadText( p, &dummy, false, endTag, false, encoding ); 1534 | return p; 1535 | } 1536 | else 1537 | { 1538 | bool ignoreWhite = true; 1539 | 1540 | const char* end = "<"; 1541 | p = ReadText( p, &value, ignoreWhite, end, false, encoding ); 1542 | if ( p && *p ) 1543 | return p-1; // don't truncate the '<' 1544 | return 0; 1545 | } 1546 | } 1547 | 1548 | #ifdef TIXML_USE_STL 1549 | void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) 1550 | { 1551 | while ( in->good() ) 1552 | { 1553 | int c = in->get(); 1554 | if ( c <= 0 ) 1555 | { 1556 | TiXmlDocument* document = GetDocument(); 1557 | if ( document ) 1558 | document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); 1559 | return; 1560 | } 1561 | (*tag) += (char) c; 1562 | 1563 | if ( c == '>' ) 1564 | { 1565 | // All is well. 1566 | return; 1567 | } 1568 | } 1569 | } 1570 | #endif 1571 | 1572 | const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) 1573 | { 1574 | p = SkipWhiteSpace( p, _encoding ); 1575 | // Find the beginning, find the end, and look for 1576 | // the stuff in-between. 1577 | TiXmlDocument* document = GetDocument(); 1578 | if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); 1581 | return 0; 1582 | } 1583 | if ( data ) 1584 | { 1585 | data->Stamp( p, _encoding ); 1586 | location = data->Cursor(); 1587 | } 1588 | p += 5; 1589 | 1590 | version = ""; 1591 | encoding = ""; 1592 | standalone = ""; 1593 | 1594 | while ( p && *p ) 1595 | { 1596 | if ( *p == '>' ) 1597 | { 1598 | ++p; 1599 | return p; 1600 | } 1601 | 1602 | p = SkipWhiteSpace( p, _encoding ); 1603 | if ( StringEqual( p, "version", true, _encoding ) ) 1604 | { 1605 | TiXmlAttribute attrib; 1606 | p = attrib.Parse( p, data, _encoding ); 1607 | version = attrib.Value(); 1608 | } 1609 | else if ( StringEqual( p, "encoding", true, _encoding ) ) 1610 | { 1611 | TiXmlAttribute attrib; 1612 | p = attrib.Parse( p, data, _encoding ); 1613 | encoding = attrib.Value(); 1614 | } 1615 | else if ( StringEqual( p, "standalone", true, _encoding ) ) 1616 | { 1617 | TiXmlAttribute attrib; 1618 | p = attrib.Parse( p, data, _encoding ); 1619 | standalone = attrib.Value(); 1620 | } 1621 | else 1622 | { 1623 | // Read over whatever it is. 1624 | while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) 1625 | ++p; 1626 | } 1627 | } 1628 | return 0; 1629 | } 1630 | 1631 | bool TiXmlText::Blank() const 1632 | { 1633 | for ( unsigned i=0; i 26 | 27 | #ifdef TIXML_USE_STL 28 | #include 29 | #include 30 | #endif 31 | 32 | #include "../include/tinyxml.h" 33 | 34 | FILE* TiXmlFOpen( const char* filename, const char* mode ); 35 | 36 | bool TiXmlBase::condenseWhiteSpace = true; 37 | 38 | // Microsoft compiler security 39 | FILE* TiXmlFOpen( const char* filename, const char* mode ) 40 | { 41 | #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) 42 | FILE* fp = 0; 43 | errno_t err = fopen_s( &fp, filename, mode ); 44 | if ( !err && fp ) 45 | return fp; 46 | return 0; 47 | #else 48 | return fopen( filename, mode ); 49 | #endif 50 | } 51 | 52 | void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString ) 53 | { 54 | int i=0; 55 | 56 | while( i<(int)str.length() ) 57 | { 58 | unsigned char c = (unsigned char) str[i]; 59 | 60 | if ( c == '&' 61 | && i < ( (int)str.length() - 2 ) 62 | && str[i+1] == '#' 63 | && str[i+2] == 'x' ) 64 | { 65 | // Hexadecimal character reference. 66 | // Pass through unchanged. 67 | // © -- copyright symbol, for example. 68 | // 69 | // The -1 is a bug fix from Rob Laveaux. It keeps 70 | // an overflow from happening if there is no ';'. 71 | // There are actually 2 ways to exit this loop - 72 | // while fails (error case) and break (semicolon found). 73 | // However, there is no mechanism (currently) for 74 | // this function to return an error. 75 | while ( i<(int)str.length()-1 ) 76 | { 77 | outString->append( str.c_str() + i, 1 ); 78 | ++i; 79 | if ( str[i] == ';' ) 80 | break; 81 | } 82 | } 83 | else if ( c == '&' ) 84 | { 85 | outString->append( entity[0].str, entity[0].strLength ); 86 | ++i; 87 | } 88 | else if ( c == '<' ) 89 | { 90 | outString->append( entity[1].str, entity[1].strLength ); 91 | ++i; 92 | } 93 | else if ( c == '>' ) 94 | { 95 | outString->append( entity[2].str, entity[2].strLength ); 96 | ++i; 97 | } 98 | else if ( c == '\"' ) 99 | { 100 | outString->append( entity[3].str, entity[3].strLength ); 101 | ++i; 102 | } 103 | else if ( c == '\'' ) 104 | { 105 | outString->append( entity[4].str, entity[4].strLength ); 106 | ++i; 107 | } 108 | else if ( c < 32 ) 109 | { 110 | // Easy pass at non-alpha/numeric/symbol 111 | // Below 32 is symbolic. 112 | char buf[ 32 ]; 113 | 114 | #if defined(TIXML_SNPRINTF) 115 | TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); 116 | #else 117 | sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); 118 | #endif 119 | 120 | //*ME: warning C4267: convert 'size_t' to 'int' 121 | //*ME: Int-Cast to make compiler happy ... 122 | outString->append( buf, (int)strlen( buf ) ); 123 | ++i; 124 | } 125 | else 126 | { 127 | //char realc = (char) c; 128 | //outString->append( &realc, 1 ); 129 | *outString += (char) c; // somewhat more efficient function call. 130 | ++i; 131 | } 132 | } 133 | } 134 | 135 | 136 | TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() 137 | { 138 | parent = 0; 139 | type = _type; 140 | firstChild = 0; 141 | lastChild = 0; 142 | prev = 0; 143 | next = 0; 144 | } 145 | 146 | 147 | TiXmlNode::~TiXmlNode() 148 | { 149 | TiXmlNode* node = firstChild; 150 | TiXmlNode* temp = 0; 151 | 152 | while ( node ) 153 | { 154 | temp = node; 155 | node = node->next; 156 | delete temp; 157 | } 158 | } 159 | 160 | 161 | void TiXmlNode::CopyTo( TiXmlNode* target ) const 162 | { 163 | target->SetValue (value.c_str() ); 164 | target->userData = userData; 165 | target->location = location; 166 | } 167 | 168 | 169 | void TiXmlNode::Clear() 170 | { 171 | TiXmlNode* node = firstChild; 172 | TiXmlNode* temp = 0; 173 | 174 | while ( node ) 175 | { 176 | temp = node; 177 | node = node->next; 178 | delete temp; 179 | } 180 | 181 | firstChild = 0; 182 | lastChild = 0; 183 | } 184 | 185 | 186 | TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) 187 | { 188 | assert( node->parent == 0 || node->parent == this ); 189 | assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); 190 | 191 | if ( node->Type() == TiXmlNode::TINYXML_DOCUMENT ) 192 | { 193 | delete node; 194 | if ( GetDocument() ) 195 | GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); 196 | return 0; 197 | } 198 | 199 | node->parent = this; 200 | 201 | node->prev = lastChild; 202 | node->next = 0; 203 | 204 | if ( lastChild ) 205 | lastChild->next = node; 206 | else 207 | firstChild = node; // it was an empty list. 208 | 209 | lastChild = node; 210 | return node; 211 | } 212 | 213 | 214 | TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) 215 | { 216 | if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) 217 | { 218 | if ( GetDocument() ) 219 | GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); 220 | return 0; 221 | } 222 | TiXmlNode* node = addThis.Clone(); 223 | if ( !node ) 224 | return 0; 225 | 226 | return LinkEndChild( node ); 227 | } 228 | 229 | 230 | TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) 231 | { 232 | if ( !beforeThis || beforeThis->parent != this ) { 233 | return 0; 234 | } 235 | if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) 236 | { 237 | if ( GetDocument() ) 238 | GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); 239 | return 0; 240 | } 241 | 242 | TiXmlNode* node = addThis.Clone(); 243 | if ( !node ) 244 | return 0; 245 | node->parent = this; 246 | 247 | node->next = beforeThis; 248 | node->prev = beforeThis->prev; 249 | if ( beforeThis->prev ) 250 | { 251 | beforeThis->prev->next = node; 252 | } 253 | else 254 | { 255 | assert( firstChild == beforeThis ); 256 | firstChild = node; 257 | } 258 | beforeThis->prev = node; 259 | return node; 260 | } 261 | 262 | 263 | TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) 264 | { 265 | if ( !afterThis || afterThis->parent != this ) { 266 | return 0; 267 | } 268 | if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) 269 | { 270 | if ( GetDocument() ) 271 | GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); 272 | return 0; 273 | } 274 | 275 | TiXmlNode* node = addThis.Clone(); 276 | if ( !node ) 277 | return 0; 278 | node->parent = this; 279 | 280 | node->prev = afterThis; 281 | node->next = afterThis->next; 282 | if ( afterThis->next ) 283 | { 284 | afterThis->next->prev = node; 285 | } 286 | else 287 | { 288 | assert( lastChild == afterThis ); 289 | lastChild = node; 290 | } 291 | afterThis->next = node; 292 | return node; 293 | } 294 | 295 | 296 | TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) 297 | { 298 | if ( !replaceThis ) 299 | return 0; 300 | 301 | if ( replaceThis->parent != this ) 302 | return 0; 303 | 304 | if ( withThis.ToDocument() ) { 305 | // A document can never be a child. Thanks to Noam. 306 | TiXmlDocument* document = GetDocument(); 307 | if ( document ) 308 | document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); 309 | return 0; 310 | } 311 | 312 | TiXmlNode* node = withThis.Clone(); 313 | if ( !node ) 314 | return 0; 315 | 316 | node->next = replaceThis->next; 317 | node->prev = replaceThis->prev; 318 | 319 | if ( replaceThis->next ) 320 | replaceThis->next->prev = node; 321 | else 322 | lastChild = node; 323 | 324 | if ( replaceThis->prev ) 325 | replaceThis->prev->next = node; 326 | else 327 | firstChild = node; 328 | 329 | delete replaceThis; 330 | node->parent = this; 331 | return node; 332 | } 333 | 334 | 335 | bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) 336 | { 337 | if ( !removeThis ) { 338 | return false; 339 | } 340 | 341 | if ( removeThis->parent != this ) 342 | { 343 | assert( 0 ); 344 | return false; 345 | } 346 | 347 | if ( removeThis->next ) 348 | removeThis->next->prev = removeThis->prev; 349 | else 350 | lastChild = removeThis->prev; 351 | 352 | if ( removeThis->prev ) 353 | removeThis->prev->next = removeThis->next; 354 | else 355 | firstChild = removeThis->next; 356 | 357 | delete removeThis; 358 | return true; 359 | } 360 | 361 | const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const 362 | { 363 | const TiXmlNode* node; 364 | for ( node = firstChild; node; node = node->next ) 365 | { 366 | if ( strcmp( node->Value(), _value ) == 0 ) 367 | return node; 368 | } 369 | return 0; 370 | } 371 | 372 | 373 | const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const 374 | { 375 | const TiXmlNode* node; 376 | for ( node = lastChild; node; node = node->prev ) 377 | { 378 | if ( strcmp( node->Value(), _value ) == 0 ) 379 | return node; 380 | } 381 | return 0; 382 | } 383 | 384 | 385 | const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const 386 | { 387 | if ( !previous ) 388 | { 389 | return FirstChild(); 390 | } 391 | else 392 | { 393 | assert( previous->parent == this ); 394 | return previous->NextSibling(); 395 | } 396 | } 397 | 398 | 399 | const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const 400 | { 401 | if ( !previous ) 402 | { 403 | return FirstChild( val ); 404 | } 405 | else 406 | { 407 | assert( previous->parent == this ); 408 | return previous->NextSibling( val ); 409 | } 410 | } 411 | 412 | 413 | const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const 414 | { 415 | const TiXmlNode* node; 416 | for ( node = next; node; node = node->next ) 417 | { 418 | if ( strcmp( node->Value(), _value ) == 0 ) 419 | return node; 420 | } 421 | return 0; 422 | } 423 | 424 | 425 | const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const 426 | { 427 | const TiXmlNode* node; 428 | for ( node = prev; node; node = node->prev ) 429 | { 430 | if ( strcmp( node->Value(), _value ) == 0 ) 431 | return node; 432 | } 433 | return 0; 434 | } 435 | 436 | 437 | void TiXmlElement::RemoveAttribute( const char * name ) 438 | { 439 | #ifdef TIXML_USE_STL 440 | TIXML_STRING str( name ); 441 | TiXmlAttribute* node = attributeSet.Find( str ); 442 | #else 443 | TiXmlAttribute* node = attributeSet.Find( name ); 444 | #endif 445 | if ( node ) 446 | { 447 | attributeSet.Remove( node ); 448 | delete node; 449 | } 450 | } 451 | 452 | const TiXmlElement* TiXmlNode::FirstChildElement() const 453 | { 454 | const TiXmlNode* node; 455 | 456 | for ( node = FirstChild(); 457 | node; 458 | node = node->NextSibling() ) 459 | { 460 | if ( node->ToElement() ) 461 | return node->ToElement(); 462 | } 463 | return 0; 464 | } 465 | 466 | 467 | const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const 468 | { 469 | const TiXmlNode* node; 470 | 471 | for ( node = FirstChild( _value ); 472 | node; 473 | node = node->NextSibling( _value ) ) 474 | { 475 | if ( node->ToElement() ) 476 | return node->ToElement(); 477 | } 478 | return 0; 479 | } 480 | 481 | 482 | const TiXmlElement* TiXmlNode::NextSiblingElement() const 483 | { 484 | const TiXmlNode* node; 485 | 486 | for ( node = NextSibling(); 487 | node; 488 | node = node->NextSibling() ) 489 | { 490 | if ( node->ToElement() ) 491 | return node->ToElement(); 492 | } 493 | return 0; 494 | } 495 | 496 | 497 | const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const 498 | { 499 | const TiXmlNode* node; 500 | 501 | for ( node = NextSibling( _value ); 502 | node; 503 | node = node->NextSibling( _value ) ) 504 | { 505 | if ( node->ToElement() ) 506 | return node->ToElement(); 507 | } 508 | return 0; 509 | } 510 | 511 | 512 | const TiXmlDocument* TiXmlNode::GetDocument() const 513 | { 514 | const TiXmlNode* node; 515 | 516 | for( node = this; node; node = node->parent ) 517 | { 518 | if ( node->ToDocument() ) 519 | return node->ToDocument(); 520 | } 521 | return 0; 522 | } 523 | 524 | 525 | TiXmlElement::TiXmlElement (const char * _value) 526 | : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) 527 | { 528 | firstChild = lastChild = 0; 529 | value = _value; 530 | } 531 | 532 | 533 | #ifdef TIXML_USE_STL 534 | TiXmlElement::TiXmlElement( const std::string& _value ) 535 | : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) 536 | { 537 | firstChild = lastChild = 0; 538 | value = _value; 539 | } 540 | #endif 541 | 542 | 543 | TiXmlElement::TiXmlElement( const TiXmlElement& copy) 544 | : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) 545 | { 546 | firstChild = lastChild = 0; 547 | copy.CopyTo( this ); 548 | } 549 | 550 | 551 | TiXmlElement& TiXmlElement::operator=( const TiXmlElement& base ) 552 | { 553 | ClearThis(); 554 | base.CopyTo( this ); 555 | return *this; 556 | } 557 | 558 | 559 | TiXmlElement::~TiXmlElement() 560 | { 561 | ClearThis(); 562 | } 563 | 564 | 565 | void TiXmlElement::ClearThis() 566 | { 567 | Clear(); 568 | while( attributeSet.First() ) 569 | { 570 | TiXmlAttribute* node = attributeSet.First(); 571 | attributeSet.Remove( node ); 572 | delete node; 573 | } 574 | } 575 | 576 | 577 | const char* TiXmlElement::Attribute( const char* name ) const 578 | { 579 | const TiXmlAttribute* node = attributeSet.Find( name ); 580 | if ( node ) 581 | return node->Value(); 582 | return 0; 583 | } 584 | 585 | 586 | #ifdef TIXML_USE_STL 587 | const std::string* TiXmlElement::Attribute( const std::string& name ) const 588 | { 589 | const TiXmlAttribute* attrib = attributeSet.Find( name ); 590 | if ( attrib ) 591 | return &attrib->ValueStr(); 592 | return 0; 593 | } 594 | #endif 595 | 596 | 597 | const char* TiXmlElement::Attribute( const char* name, int* i ) const 598 | { 599 | const TiXmlAttribute* attrib = attributeSet.Find( name ); 600 | const char* result = 0; 601 | 602 | if ( attrib ) { 603 | result = attrib->Value(); 604 | if ( i ) { 605 | attrib->QueryIntValue( i ); 606 | } 607 | } 608 | return result; 609 | } 610 | 611 | 612 | #ifdef TIXML_USE_STL 613 | const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const 614 | { 615 | const TiXmlAttribute* attrib = attributeSet.Find( name ); 616 | const std::string* result = 0; 617 | 618 | if ( attrib ) { 619 | result = &attrib->ValueStr(); 620 | if ( i ) { 621 | attrib->QueryIntValue( i ); 622 | } 623 | } 624 | return result; 625 | } 626 | #endif 627 | 628 | 629 | const char* TiXmlElement::Attribute( const char* name, double* d ) const 630 | { 631 | const TiXmlAttribute* attrib = attributeSet.Find( name ); 632 | const char* result = 0; 633 | 634 | if ( attrib ) { 635 | result = attrib->Value(); 636 | if ( d ) { 637 | attrib->QueryDoubleValue( d ); 638 | } 639 | } 640 | return result; 641 | } 642 | 643 | 644 | #ifdef TIXML_USE_STL 645 | const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const 646 | { 647 | const TiXmlAttribute* attrib = attributeSet.Find( name ); 648 | const std::string* result = 0; 649 | 650 | if ( attrib ) { 651 | result = &attrib->ValueStr(); 652 | if ( d ) { 653 | attrib->QueryDoubleValue( d ); 654 | } 655 | } 656 | return result; 657 | } 658 | #endif 659 | 660 | 661 | int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const 662 | { 663 | const TiXmlAttribute* attrib = attributeSet.Find( name ); 664 | if ( !attrib ) 665 | return TIXML_NO_ATTRIBUTE; 666 | return attrib->QueryIntValue( ival ); 667 | } 668 | 669 | 670 | int TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* value ) const 671 | { 672 | const TiXmlAttribute* node = attributeSet.Find( name ); 673 | if ( !node ) 674 | return TIXML_NO_ATTRIBUTE; 675 | 676 | int ival = 0; 677 | int result = node->QueryIntValue( &ival ); 678 | *value = (unsigned)ival; 679 | return result; 680 | } 681 | 682 | 683 | int TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const 684 | { 685 | const TiXmlAttribute* node = attributeSet.Find( name ); 686 | if ( !node ) 687 | return TIXML_NO_ATTRIBUTE; 688 | 689 | int result = TIXML_WRONG_TYPE; 690 | if ( StringEqual( node->Value(), "true", true, TIXML_ENCODING_UNKNOWN ) 691 | || StringEqual( node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN ) 692 | || StringEqual( node->Value(), "1", true, TIXML_ENCODING_UNKNOWN ) ) 693 | { 694 | *bval = true; 695 | result = TIXML_SUCCESS; 696 | } 697 | else if ( StringEqual( node->Value(), "false", true, TIXML_ENCODING_UNKNOWN ) 698 | || StringEqual( node->Value(), "no", true, TIXML_ENCODING_UNKNOWN ) 699 | || StringEqual( node->Value(), "0", true, TIXML_ENCODING_UNKNOWN ) ) 700 | { 701 | *bval = false; 702 | result = TIXML_SUCCESS; 703 | } 704 | return result; 705 | } 706 | 707 | 708 | 709 | #ifdef TIXML_USE_STL 710 | int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const 711 | { 712 | const TiXmlAttribute* attrib = attributeSet.Find( name ); 713 | if ( !attrib ) 714 | return TIXML_NO_ATTRIBUTE; 715 | return attrib->QueryIntValue( ival ); 716 | } 717 | #endif 718 | 719 | 720 | int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const 721 | { 722 | const TiXmlAttribute* attrib = attributeSet.Find( name ); 723 | if ( !attrib ) 724 | return TIXML_NO_ATTRIBUTE; 725 | return attrib->QueryDoubleValue( dval ); 726 | } 727 | 728 | 729 | #ifdef TIXML_USE_STL 730 | int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const 731 | { 732 | const TiXmlAttribute* attrib = attributeSet.Find( name ); 733 | if ( !attrib ) 734 | return TIXML_NO_ATTRIBUTE; 735 | return attrib->QueryDoubleValue( dval ); 736 | } 737 | #endif 738 | 739 | 740 | void TiXmlElement::SetAttribute( const char * name, int val ) 741 | { 742 | TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); 743 | if ( attrib ) { 744 | attrib->SetIntValue( val ); 745 | } 746 | } 747 | 748 | 749 | #ifdef TIXML_USE_STL 750 | void TiXmlElement::SetAttribute( const std::string& name, int val ) 751 | { 752 | TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); 753 | if ( attrib ) { 754 | attrib->SetIntValue( val ); 755 | } 756 | } 757 | #endif 758 | 759 | 760 | void TiXmlElement::SetDoubleAttribute( const char * name, double val ) 761 | { 762 | TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); 763 | if ( attrib ) { 764 | attrib->SetDoubleValue( val ); 765 | } 766 | } 767 | 768 | 769 | #ifdef TIXML_USE_STL 770 | void TiXmlElement::SetDoubleAttribute( const std::string& name, double val ) 771 | { 772 | TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); 773 | if ( attrib ) { 774 | attrib->SetDoubleValue( val ); 775 | } 776 | } 777 | #endif 778 | 779 | 780 | void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) 781 | { 782 | TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname ); 783 | if ( attrib ) { 784 | attrib->SetValue( cvalue ); 785 | } 786 | } 787 | 788 | 789 | #ifdef TIXML_USE_STL 790 | void TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value ) 791 | { 792 | TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name ); 793 | if ( attrib ) { 794 | attrib->SetValue( _value ); 795 | } 796 | } 797 | #endif 798 | 799 | 800 | void TiXmlElement::Print( FILE* cfile, int depth ) const 801 | { 802 | int i; 803 | assert( cfile ); 804 | for ( i=0; iNext() ) 812 | { 813 | fprintf( cfile, " " ); 814 | attrib->Print( cfile, depth ); 815 | } 816 | 817 | // There are 3 different formatting approaches: 818 | // 1) An element without children is printed as a node 819 | // 2) An element with only a text child is printed as text 820 | // 3) An element with children is printed on multiple lines. 821 | TiXmlNode* node; 822 | if ( !firstChild ) 823 | { 824 | fprintf( cfile, " />" ); 825 | } 826 | else if ( firstChild == lastChild && firstChild->ToText() ) 827 | { 828 | fprintf( cfile, ">" ); 829 | firstChild->Print( cfile, depth + 1 ); 830 | fprintf( cfile, "", value.c_str() ); 831 | } 832 | else 833 | { 834 | fprintf( cfile, ">" ); 835 | 836 | for ( node = firstChild; node; node=node->NextSibling() ) 837 | { 838 | if ( !node->ToText() ) 839 | { 840 | fprintf( cfile, "\n" ); 841 | } 842 | node->Print( cfile, depth+1 ); 843 | } 844 | fprintf( cfile, "\n" ); 845 | for( i=0; i", value.c_str() ); 849 | } 850 | } 851 | 852 | 853 | void TiXmlElement::CopyTo( TiXmlElement* target ) const 854 | { 855 | // superclass: 856 | TiXmlNode::CopyTo( target ); 857 | 858 | // Element class: 859 | // Clone the attributes, then clone the children. 860 | const TiXmlAttribute* attribute = 0; 861 | for( attribute = attributeSet.First(); 862 | attribute; 863 | attribute = attribute->Next() ) 864 | { 865 | target->SetAttribute( attribute->Name(), attribute->Value() ); 866 | } 867 | 868 | TiXmlNode* node = 0; 869 | for ( node = firstChild; node; node = node->NextSibling() ) 870 | { 871 | target->LinkEndChild( node->Clone() ); 872 | } 873 | } 874 | 875 | bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const 876 | { 877 | if ( visitor->VisitEnter( *this, attributeSet.First() ) ) 878 | { 879 | for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) 880 | { 881 | if ( !node->Accept( visitor ) ) 882 | break; 883 | } 884 | } 885 | return visitor->VisitExit( *this ); 886 | } 887 | 888 | 889 | TiXmlNode* TiXmlElement::Clone() const 890 | { 891 | TiXmlElement* clone = new TiXmlElement( Value() ); 892 | if ( !clone ) 893 | return 0; 894 | 895 | CopyTo( clone ); 896 | return clone; 897 | } 898 | 899 | 900 | const char* TiXmlElement::GetText() const 901 | { 902 | const TiXmlNode* child = this->FirstChild(); 903 | if ( child ) { 904 | const TiXmlText* childText = child->ToText(); 905 | if ( childText ) { 906 | return childText->Value(); 907 | } 908 | } 909 | return 0; 910 | } 911 | 912 | 913 | TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) 914 | { 915 | tabsize = 4; 916 | useMicrosoftBOM = false; 917 | ClearError(); 918 | } 919 | 920 | TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) 921 | { 922 | tabsize = 4; 923 | useMicrosoftBOM = false; 924 | value = documentName; 925 | ClearError(); 926 | } 927 | 928 | 929 | #ifdef TIXML_USE_STL 930 | TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) 931 | { 932 | tabsize = 4; 933 | useMicrosoftBOM = false; 934 | value = documentName; 935 | ClearError(); 936 | } 937 | #endif 938 | 939 | 940 | TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) 941 | { 942 | copy.CopyTo( this ); 943 | } 944 | 945 | 946 | TiXmlDocument& TiXmlDocument::operator=( const TiXmlDocument& copy ) 947 | { 948 | Clear(); 949 | copy.CopyTo( this ); 950 | return *this; 951 | } 952 | 953 | 954 | bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) 955 | { 956 | return LoadFile( Value(), encoding ); 957 | } 958 | 959 | 960 | bool TiXmlDocument::SaveFile() const 961 | { 962 | return SaveFile( Value() ); 963 | } 964 | 965 | bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) 966 | { 967 | TIXML_STRING filename( _filename ); 968 | value = filename; 969 | 970 | // reading in binary mode so that tinyxml can normalize the EOL 971 | FILE* file = TiXmlFOpen( value.c_str (), "rb" ); 972 | 973 | if ( file ) 974 | { 975 | bool result = LoadFile( file, encoding ); 976 | fclose( file ); 977 | return result; 978 | } 979 | else 980 | { 981 | SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); 982 | return false; 983 | } 984 | } 985 | 986 | bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) 987 | { 988 | if ( !file ) 989 | { 990 | SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); 991 | return false; 992 | } 993 | 994 | // Delete the existing data: 995 | Clear(); 996 | location.Clear(); 997 | 998 | // Get the file size, so we can pre-allocate the string. HUGE speed impact. 999 | long length = 0; 1000 | fseek( file, 0, SEEK_END ); 1001 | length = ftell( file ); 1002 | fseek( file, 0, SEEK_SET ); 1003 | 1004 | // Strange case, but good to handle up front. 1005 | if ( length <= 0 ) 1006 | { 1007 | SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); 1008 | return false; 1009 | } 1010 | 1011 | // Subtle bug here. TinyXml did use fgets. But from the XML spec: 1012 | // 2.11 End-of-Line Handling 1013 | // 1014 | // 1015 | // ...the XML processor MUST behave as if it normalized all line breaks in external 1016 | // parsed entities (including the document entity) on input, before parsing, by translating 1017 | // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to 1018 | // a single #xA character. 1019 | // 1020 | // 1021 | // It is not clear fgets does that, and certainly isn't clear it works cross platform. 1022 | // Generally, you expect fgets to translate from the convention of the OS to the c/unix 1023 | // convention, and not work generally. 1024 | 1025 | /* 1026 | while( fgets( buf, sizeof(buf), file ) ) 1027 | { 1028 | data += buf; 1029 | } 1030 | */ 1031 | 1032 | char* buf = new char[ length+1 ]; 1033 | buf[0] = 0; 1034 | 1035 | if ( fread( buf, length, 1, file ) != 1 ) { 1036 | delete [] buf; 1037 | SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); 1038 | return false; 1039 | } 1040 | 1041 | // Process the buffer in place to normalize new lines. (See comment above.) 1042 | // Copies from the 'p' to 'q' pointer, where p can advance faster if 1043 | // a newline-carriage return is hit. 1044 | // 1045 | // Wikipedia: 1046 | // Systems based on ASCII or a compatible character set use either LF (Line feed, '\n', 0x0A, 10 in decimal) or 1047 | // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)... 1048 | // * LF: Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others 1049 | // * CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, Microsoft Windows, Symbian OS 1050 | // * CR: Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9 1051 | 1052 | const char* p = buf; // the read head 1053 | char* q = buf; // the write head 1054 | const char CR = 0x0d; 1055 | const char LF = 0x0a; 1056 | 1057 | buf[length] = 0; 1058 | while( *p ) { 1059 | assert( p < (buf+length) ); 1060 | assert( q <= (buf+length) ); 1061 | assert( q <= p ); 1062 | 1063 | if ( *p == CR ) { 1064 | *q++ = LF; 1065 | p++; 1066 | if ( *p == LF ) { // check for CR+LF (and skip LF) 1067 | p++; 1068 | } 1069 | } 1070 | else { 1071 | *q++ = *p++; 1072 | } 1073 | } 1074 | assert( q <= (buf+length) ); 1075 | *q = 0; 1076 | 1077 | Parse( buf, 0, encoding ); 1078 | 1079 | delete [] buf; 1080 | return !Error(); 1081 | } 1082 | 1083 | 1084 | bool TiXmlDocument::SaveFile( const char * filename ) const 1085 | { 1086 | // The old c stuff lives on... 1087 | FILE* fp = TiXmlFOpen( filename, "w" ); 1088 | if ( fp ) 1089 | { 1090 | bool result = SaveFile( fp ); 1091 | fclose( fp ); 1092 | return result; 1093 | } 1094 | return false; 1095 | } 1096 | 1097 | 1098 | bool TiXmlDocument::SaveFile( FILE* fp ) const 1099 | { 1100 | if ( useMicrosoftBOM ) 1101 | { 1102 | const unsigned char TIXML_UTF_LEAD_0 = 0xefU; 1103 | const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; 1104 | const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; 1105 | 1106 | fputc( TIXML_UTF_LEAD_0, fp ); 1107 | fputc( TIXML_UTF_LEAD_1, fp ); 1108 | fputc( TIXML_UTF_LEAD_2, fp ); 1109 | } 1110 | Print( fp, 0 ); 1111 | return (ferror(fp) == 0); 1112 | } 1113 | 1114 | 1115 | void TiXmlDocument::CopyTo( TiXmlDocument* target ) const 1116 | { 1117 | TiXmlNode::CopyTo( target ); 1118 | 1119 | target->error = error; 1120 | target->errorId = errorId; 1121 | target->errorDesc = errorDesc; 1122 | target->tabsize = tabsize; 1123 | target->errorLocation = errorLocation; 1124 | target->useMicrosoftBOM = useMicrosoftBOM; 1125 | 1126 | TiXmlNode* node = 0; 1127 | for ( node = firstChild; node; node = node->NextSibling() ) 1128 | { 1129 | target->LinkEndChild( node->Clone() ); 1130 | } 1131 | } 1132 | 1133 | 1134 | TiXmlNode* TiXmlDocument::Clone() const 1135 | { 1136 | TiXmlDocument* clone = new TiXmlDocument(); 1137 | if ( !clone ) 1138 | return 0; 1139 | 1140 | CopyTo( clone ); 1141 | return clone; 1142 | } 1143 | 1144 | 1145 | void TiXmlDocument::Print( FILE* cfile, int depth ) const 1146 | { 1147 | assert( cfile ); 1148 | for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) 1149 | { 1150 | node->Print( cfile, depth ); 1151 | fprintf( cfile, "\n" ); 1152 | } 1153 | } 1154 | 1155 | 1156 | bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const 1157 | { 1158 | if ( visitor->VisitEnter( *this ) ) 1159 | { 1160 | for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) 1161 | { 1162 | if ( !node->Accept( visitor ) ) 1163 | break; 1164 | } 1165 | } 1166 | return visitor->VisitExit( *this ); 1167 | } 1168 | 1169 | 1170 | const TiXmlAttribute* TiXmlAttribute::Next() const 1171 | { 1172 | // We are using knowledge of the sentinel. The sentinel 1173 | // have a value or name. 1174 | if ( next->value.empty() && next->name.empty() ) 1175 | return 0; 1176 | return next; 1177 | } 1178 | 1179 | /* 1180 | TiXmlAttribute* TiXmlAttribute::Next() 1181 | { 1182 | // We are using knowledge of the sentinel. The sentinel 1183 | // have a value or name. 1184 | if ( next->value.empty() && next->name.empty() ) 1185 | return 0; 1186 | return next; 1187 | } 1188 | */ 1189 | 1190 | const TiXmlAttribute* TiXmlAttribute::Previous() const 1191 | { 1192 | // We are using knowledge of the sentinel. The sentinel 1193 | // have a value or name. 1194 | if ( prev->value.empty() && prev->name.empty() ) 1195 | return 0; 1196 | return prev; 1197 | } 1198 | 1199 | /* 1200 | TiXmlAttribute* TiXmlAttribute::Previous() 1201 | { 1202 | // We are using knowledge of the sentinel. The sentinel 1203 | // have a value or name. 1204 | if ( prev->value.empty() && prev->name.empty() ) 1205 | return 0; 1206 | return prev; 1207 | } 1208 | */ 1209 | 1210 | void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const 1211 | { 1212 | TIXML_STRING n, v; 1213 | 1214 | EncodeString( name, &n ); 1215 | EncodeString( value, &v ); 1216 | 1217 | if (value.find ('\"') == TIXML_STRING::npos) { 1218 | if ( cfile ) { 1219 | fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); 1220 | } 1221 | if ( str ) { 1222 | (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; 1223 | } 1224 | } 1225 | else { 1226 | if ( cfile ) { 1227 | fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); 1228 | } 1229 | if ( str ) { 1230 | (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; 1231 | } 1232 | } 1233 | } 1234 | 1235 | 1236 | int TiXmlAttribute::QueryIntValue( int* ival ) const 1237 | { 1238 | if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) 1239 | return TIXML_SUCCESS; 1240 | return TIXML_WRONG_TYPE; 1241 | } 1242 | 1243 | int TiXmlAttribute::QueryDoubleValue( double* dval ) const 1244 | { 1245 | if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) 1246 | return TIXML_SUCCESS; 1247 | return TIXML_WRONG_TYPE; 1248 | } 1249 | 1250 | void TiXmlAttribute::SetIntValue( int _value ) 1251 | { 1252 | char buf [64]; 1253 | #if defined(TIXML_SNPRINTF) 1254 | TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); 1255 | #else 1256 | sprintf (buf, "%d", _value); 1257 | #endif 1258 | SetValue (buf); 1259 | } 1260 | 1261 | void TiXmlAttribute::SetDoubleValue( double _value ) 1262 | { 1263 | char buf [256]; 1264 | #if defined(TIXML_SNPRINTF) 1265 | TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value); 1266 | #else 1267 | sprintf (buf, "%g", _value); 1268 | #endif 1269 | SetValue (buf); 1270 | } 1271 | 1272 | int TiXmlAttribute::IntValue() const 1273 | { 1274 | return atoi (value.c_str ()); 1275 | } 1276 | 1277 | double TiXmlAttribute::DoubleValue() const 1278 | { 1279 | return atof (value.c_str ()); 1280 | } 1281 | 1282 | 1283 | TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) 1284 | { 1285 | copy.CopyTo( this ); 1286 | } 1287 | 1288 | 1289 | TiXmlComment& TiXmlComment::operator=( const TiXmlComment& base ) 1290 | { 1291 | Clear(); 1292 | base.CopyTo( this ); 1293 | return *this; 1294 | } 1295 | 1296 | 1297 | void TiXmlComment::Print( FILE* cfile, int depth ) const 1298 | { 1299 | assert( cfile ); 1300 | for ( int i=0; i", value.c_str() ); 1305 | } 1306 | 1307 | 1308 | void TiXmlComment::CopyTo( TiXmlComment* target ) const 1309 | { 1310 | TiXmlNode::CopyTo( target ); 1311 | } 1312 | 1313 | 1314 | bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const 1315 | { 1316 | return visitor->Visit( *this ); 1317 | } 1318 | 1319 | 1320 | TiXmlNode* TiXmlComment::Clone() const 1321 | { 1322 | TiXmlComment* clone = new TiXmlComment(); 1323 | 1324 | if ( !clone ) 1325 | return 0; 1326 | 1327 | CopyTo( clone ); 1328 | return clone; 1329 | } 1330 | 1331 | 1332 | void TiXmlText::Print( FILE* cfile, int depth ) const 1333 | { 1334 | assert( cfile ); 1335 | if ( cdata ) 1336 | { 1337 | int i; 1338 | fprintf( cfile, "\n" ); 1339 | for ( i=0; i\n", value.c_str() ); // unformatted output 1343 | } 1344 | else 1345 | { 1346 | TIXML_STRING buffer; 1347 | EncodeString( value, &buffer ); 1348 | fprintf( cfile, "%s", buffer.c_str() ); 1349 | } 1350 | } 1351 | 1352 | 1353 | void TiXmlText::CopyTo( TiXmlText* target ) const 1354 | { 1355 | TiXmlNode::CopyTo( target ); 1356 | target->cdata = cdata; 1357 | } 1358 | 1359 | 1360 | bool TiXmlText::Accept( TiXmlVisitor* visitor ) const 1361 | { 1362 | return visitor->Visit( *this ); 1363 | } 1364 | 1365 | 1366 | TiXmlNode* TiXmlText::Clone() const 1367 | { 1368 | TiXmlText* clone = 0; 1369 | clone = new TiXmlText( "" ); 1370 | 1371 | if ( !clone ) 1372 | return 0; 1373 | 1374 | CopyTo( clone ); 1375 | return clone; 1376 | } 1377 | 1378 | 1379 | TiXmlDeclaration::TiXmlDeclaration( const char * _version, 1380 | const char * _encoding, 1381 | const char * _standalone ) 1382 | : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) 1383 | { 1384 | version = _version; 1385 | encoding = _encoding; 1386 | standalone = _standalone; 1387 | } 1388 | 1389 | 1390 | #ifdef TIXML_USE_STL 1391 | TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, 1392 | const std::string& _encoding, 1393 | const std::string& _standalone ) 1394 | : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) 1395 | { 1396 | version = _version; 1397 | encoding = _encoding; 1398 | standalone = _standalone; 1399 | } 1400 | #endif 1401 | 1402 | 1403 | TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) 1404 | : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) 1405 | { 1406 | copy.CopyTo( this ); 1407 | } 1408 | 1409 | 1410 | TiXmlDeclaration& TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) 1411 | { 1412 | Clear(); 1413 | copy.CopyTo( this ); 1414 | return *this; 1415 | } 1416 | 1417 | 1418 | void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const 1419 | { 1420 | if ( cfile ) fprintf( cfile, "" ); 1436 | if ( str ) (*str) += "?>"; 1437 | } 1438 | 1439 | 1440 | void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const 1441 | { 1442 | TiXmlNode::CopyTo( target ); 1443 | 1444 | target->version = version; 1445 | target->encoding = encoding; 1446 | target->standalone = standalone; 1447 | } 1448 | 1449 | 1450 | bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const 1451 | { 1452 | return visitor->Visit( *this ); 1453 | } 1454 | 1455 | 1456 | TiXmlNode* TiXmlDeclaration::Clone() const 1457 | { 1458 | TiXmlDeclaration* clone = new TiXmlDeclaration(); 1459 | 1460 | if ( !clone ) 1461 | return 0; 1462 | 1463 | CopyTo( clone ); 1464 | return clone; 1465 | } 1466 | 1467 | 1468 | void TiXmlUnknown::Print( FILE* cfile, int depth ) const 1469 | { 1470 | for ( int i=0; i", value.c_str() ); 1473 | } 1474 | 1475 | 1476 | void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const 1477 | { 1478 | TiXmlNode::CopyTo( target ); 1479 | } 1480 | 1481 | 1482 | bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const 1483 | { 1484 | return visitor->Visit( *this ); 1485 | } 1486 | 1487 | 1488 | TiXmlNode* TiXmlUnknown::Clone() const 1489 | { 1490 | TiXmlUnknown* clone = new TiXmlUnknown(); 1491 | 1492 | if ( !clone ) 1493 | return 0; 1494 | 1495 | CopyTo( clone ); 1496 | return clone; 1497 | } 1498 | 1499 | 1500 | TiXmlAttributeSet::TiXmlAttributeSet() 1501 | { 1502 | sentinel.next = &sentinel; 1503 | sentinel.prev = &sentinel; 1504 | } 1505 | 1506 | 1507 | TiXmlAttributeSet::~TiXmlAttributeSet() 1508 | { 1509 | assert( sentinel.next == &sentinel ); 1510 | assert( sentinel.prev == &sentinel ); 1511 | } 1512 | 1513 | 1514 | void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) 1515 | { 1516 | #ifdef TIXML_USE_STL 1517 | assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. 1518 | #else 1519 | assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. 1520 | #endif 1521 | 1522 | addMe->next = &sentinel; 1523 | addMe->prev = sentinel.prev; 1524 | 1525 | sentinel.prev->next = addMe; 1526 | sentinel.prev = addMe; 1527 | } 1528 | 1529 | void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) 1530 | { 1531 | TiXmlAttribute* node; 1532 | 1533 | for( node = sentinel.next; node != &sentinel; node = node->next ) 1534 | { 1535 | if ( node == removeMe ) 1536 | { 1537 | node->prev->next = node->next; 1538 | node->next->prev = node->prev; 1539 | node->next = 0; 1540 | node->prev = 0; 1541 | return; 1542 | } 1543 | } 1544 | assert( 0 ); // we tried to remove a non-linked attribute. 1545 | } 1546 | 1547 | 1548 | #ifdef TIXML_USE_STL 1549 | TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const 1550 | { 1551 | for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) 1552 | { 1553 | if ( node->name == name ) 1554 | return node; 1555 | } 1556 | return 0; 1557 | } 1558 | 1559 | TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name ) 1560 | { 1561 | TiXmlAttribute* attrib = Find( _name ); 1562 | if ( !attrib ) { 1563 | attrib = new TiXmlAttribute(); 1564 | Add( attrib ); 1565 | attrib->SetName( _name ); 1566 | } 1567 | return attrib; 1568 | } 1569 | #endif 1570 | 1571 | 1572 | TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const 1573 | { 1574 | for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) 1575 | { 1576 | if ( strcmp( node->name.c_str(), name ) == 0 ) 1577 | return node; 1578 | } 1579 | return 0; 1580 | } 1581 | 1582 | 1583 | TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name ) 1584 | { 1585 | TiXmlAttribute* attrib = Find( _name ); 1586 | if ( !attrib ) { 1587 | attrib = new TiXmlAttribute(); 1588 | Add( attrib ); 1589 | attrib->SetName( _name ); 1590 | } 1591 | return attrib; 1592 | } 1593 | 1594 | 1595 | #ifdef TIXML_USE_STL 1596 | std::istream& operator>> (std::istream & in, TiXmlNode & base) 1597 | { 1598 | TIXML_STRING tag; 1599 | tag.reserve( 8 * 1000 ); 1600 | base.StreamIn( &in, &tag ); 1601 | 1602 | base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); 1603 | return in; 1604 | } 1605 | #endif 1606 | 1607 | 1608 | #ifdef TIXML_USE_STL 1609 | std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) 1610 | { 1611 | TiXmlPrinter printer; 1612 | printer.SetStreamPrinting(); 1613 | base.Accept( &printer ); 1614 | out << printer.Str(); 1615 | 1616 | return out; 1617 | } 1618 | 1619 | 1620 | std::string& operator<< (std::string& out, const TiXmlNode& base ) 1621 | { 1622 | TiXmlPrinter printer; 1623 | printer.SetStreamPrinting(); 1624 | base.Accept( &printer ); 1625 | out.append( printer.Str() ); 1626 | 1627 | return out; 1628 | } 1629 | #endif 1630 | 1631 | 1632 | TiXmlHandle TiXmlHandle::FirstChild() const 1633 | { 1634 | if ( node ) 1635 | { 1636 | TiXmlNode* child = node->FirstChild(); 1637 | if ( child ) 1638 | return TiXmlHandle( child ); 1639 | } 1640 | return TiXmlHandle( 0 ); 1641 | } 1642 | 1643 | 1644 | TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const 1645 | { 1646 | if ( node ) 1647 | { 1648 | TiXmlNode* child = node->FirstChild( value ); 1649 | if ( child ) 1650 | return TiXmlHandle( child ); 1651 | } 1652 | return TiXmlHandle( 0 ); 1653 | } 1654 | 1655 | 1656 | TiXmlHandle TiXmlHandle::FirstChildElement() const 1657 | { 1658 | if ( node ) 1659 | { 1660 | TiXmlElement* child = node->FirstChildElement(); 1661 | if ( child ) 1662 | return TiXmlHandle( child ); 1663 | } 1664 | return TiXmlHandle( 0 ); 1665 | } 1666 | 1667 | 1668 | TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const 1669 | { 1670 | if ( node ) 1671 | { 1672 | TiXmlElement* child = node->FirstChildElement( value ); 1673 | if ( child ) 1674 | return TiXmlHandle( child ); 1675 | } 1676 | return TiXmlHandle( 0 ); 1677 | } 1678 | 1679 | 1680 | TiXmlHandle TiXmlHandle::Child( int count ) const 1681 | { 1682 | if ( node ) 1683 | { 1684 | int i; 1685 | TiXmlNode* child = node->FirstChild(); 1686 | for ( i=0; 1687 | child && iNextSibling(), ++i ) 1689 | { 1690 | // nothing 1691 | } 1692 | if ( child ) 1693 | return TiXmlHandle( child ); 1694 | } 1695 | return TiXmlHandle( 0 ); 1696 | } 1697 | 1698 | 1699 | TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const 1700 | { 1701 | if ( node ) 1702 | { 1703 | int i; 1704 | TiXmlNode* child = node->FirstChild( value ); 1705 | for ( i=0; 1706 | child && iNextSibling( value ), ++i ) 1708 | { 1709 | // nothing 1710 | } 1711 | if ( child ) 1712 | return TiXmlHandle( child ); 1713 | } 1714 | return TiXmlHandle( 0 ); 1715 | } 1716 | 1717 | 1718 | TiXmlHandle TiXmlHandle::ChildElement( int count ) const 1719 | { 1720 | if ( node ) 1721 | { 1722 | int i; 1723 | TiXmlElement* child = node->FirstChildElement(); 1724 | for ( i=0; 1725 | child && iNextSiblingElement(), ++i ) 1727 | { 1728 | // nothing 1729 | } 1730 | if ( child ) 1731 | return TiXmlHandle( child ); 1732 | } 1733 | return TiXmlHandle( 0 ); 1734 | } 1735 | 1736 | 1737 | TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const 1738 | { 1739 | if ( node ) 1740 | { 1741 | int i; 1742 | TiXmlElement* child = node->FirstChildElement( value ); 1743 | for ( i=0; 1744 | child && iNextSiblingElement( value ), ++i ) 1746 | { 1747 | // nothing 1748 | } 1749 | if ( child ) 1750 | return TiXmlHandle( child ); 1751 | } 1752 | return TiXmlHandle( 0 ); 1753 | } 1754 | 1755 | 1756 | bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) 1757 | { 1758 | return true; 1759 | } 1760 | 1761 | bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) 1762 | { 1763 | return true; 1764 | } 1765 | 1766 | bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) 1767 | { 1768 | DoIndent(); 1769 | buffer += "<"; 1770 | buffer += element.Value(); 1771 | 1772 | for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) 1773 | { 1774 | buffer += " "; 1775 | attrib->Print( 0, 0, &buffer ); 1776 | } 1777 | 1778 | if ( !element.FirstChild() ) 1779 | { 1780 | buffer += " />"; 1781 | DoLineBreak(); 1782 | } 1783 | else 1784 | { 1785 | buffer += ">"; 1786 | if ( element.FirstChild()->ToText() 1787 | && element.LastChild() == element.FirstChild() 1788 | && element.FirstChild()->ToText()->CDATA() == false ) 1789 | { 1790 | simpleTextPrint = true; 1791 | // no DoLineBreak()! 1792 | } 1793 | else 1794 | { 1795 | DoLineBreak(); 1796 | } 1797 | } 1798 | ++depth; 1799 | return true; 1800 | } 1801 | 1802 | 1803 | bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) 1804 | { 1805 | --depth; 1806 | if ( !element.FirstChild() ) 1807 | { 1808 | // nothing. 1809 | } 1810 | else 1811 | { 1812 | if ( simpleTextPrint ) 1813 | { 1814 | simpleTextPrint = false; 1815 | } 1816 | else 1817 | { 1818 | DoIndent(); 1819 | } 1820 | buffer += ""; 1823 | DoLineBreak(); 1824 | } 1825 | return true; 1826 | } 1827 | 1828 | 1829 | bool TiXmlPrinter::Visit( const TiXmlText& text ) 1830 | { 1831 | if ( text.CDATA() ) 1832 | { 1833 | DoIndent(); 1834 | buffer += ""; 1837 | DoLineBreak(); 1838 | } 1839 | else if ( simpleTextPrint ) 1840 | { 1841 | TIXML_STRING str; 1842 | TiXmlBase::EncodeString( text.ValueTStr(), &str ); 1843 | buffer += str; 1844 | } 1845 | else 1846 | { 1847 | DoIndent(); 1848 | TIXML_STRING str; 1849 | TiXmlBase::EncodeString( text.ValueTStr(), &str ); 1850 | buffer += str; 1851 | DoLineBreak(); 1852 | } 1853 | return true; 1854 | } 1855 | 1856 | 1857 | bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) 1858 | { 1859 | DoIndent(); 1860 | declaration.Print( 0, 0, &buffer ); 1861 | DoLineBreak(); 1862 | return true; 1863 | } 1864 | 1865 | 1866 | bool TiXmlPrinter::Visit( const TiXmlComment& comment ) 1867 | { 1868 | DoIndent(); 1869 | buffer += ""; 1872 | DoLineBreak(); 1873 | return true; 1874 | } 1875 | 1876 | 1877 | bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) 1878 | { 1879 | DoIndent(); 1880 | buffer += "<"; 1881 | buffer += unknown.Value(); 1882 | buffer += ">"; 1883 | DoLineBreak(); 1884 | return true; 1885 | } 1886 | 1887 | --------------------------------------------------------------------------------