- °³¿ä
- XML.h
- XML.cpp
1 °³¿ä
- boost ³»ºÎÀûÀ¸·Î »ç¿ëÇÏ´Â tiny_xml ¸ðµâÀ» Âü°íÇØ¼ ¸¸µç ÃÖ¼ÒÇÑÀÇ DOM ÆÄ¼ÀÌ´Ù.
- ±âº»ÀûÀÎ °ýÈ£ üũ¿Í ³ëµå ½ÃÀÛ, ³ëµå ³¡ÀÇ À̸§ÀÌ ¼·Î ÀÏÄ¡ÇÏ´ÂÁö Á¤µµÀÇ Ã¼Å©´Â ÇÑ´Ù.
- ÃÖ¼ÒÇÑÀÇ ÆÄ¼À̹ǷΠDTD, XLS, ÀÎÄÚµù µîÀ» ±â´ëÇÏÁö ¸»Áö¾î´Ù.
- ÇãÁ¢Çϳª¸¶ ¹ÙÀ̳ʸ® ÆÄÀÏ·ÎÀÇ ÀÔÃâ·Â ±â´Éµµ µé¾îÀÖ´Ù. ÆÄ½Ì ¼Óµµ ¹®Á¦¸¦ ¾à°£Àº ÇØ°áÇÒ ¼ö ÀÖÀ»Áöµµ...
- Á¤ÅëÀû(?)ÀÎ ÆÄ¼¶ó±âº¸´Ù´Â, ¹º°¡ »ó´çÈ÷ ½ÃÇàÂø¿ÀÀûÀ¸·Î ¸¸µé¾îÁø ÆÄ¼¶ó, Á¦´ë·Î ÆÄ½Ì ¸ø ÇÏ´Â ±¸¹®ÀÌ ´Ù¼ö ÀÖÀ» ¼ö ÀÖ´Ù. ÀÏ´Ü ¾Ë°í ÀÖ´Â °ÍÀº ÁÖ¼® ¾È¿¡ ÁÖ¼®À» ³ÖÀ» °æ¿ì, Á¦´ë·Î 󸮵ÇÁö ¾Ê´Â´Ù´Â °Í.
2 XML.h
//////////////////////////////////////////////////////////////////////////////
/// \file XML.h
/// \author excel96
/// \date 2004.9.20
//////////////////////////////////////////////////////////////////////////////
#pragma once
#include <string>
#include <map>
#include <vector>
#include <cassert>
//////////////////////////////////////////////////////////////////////////////
/// \class XMLTree
/// \brief ÃÖ¼ÒÇÑÀÇ ±â´É¸¸À» Áý¾î³ÖÀº DOM Æ®¸® Ŭ·¡½º. ÀÎÄÚµù µûÀ§(?)´Â
/// Áö¿øÇÏÁö ¾ÊÀ¸¸ç, DTD, XLS µîÀº ¾î¸²µµ ¾ø´Ù.
//////////////////////////////////////////////////////////////////////////////
class XMLTree
{
public:
typedef std::map<std::string, std::string> ATTRIBUTES;
typedef std::vector<XMLTree*> CHILDREN;
// load, save ÇÔ¼ö¿¡¼ »ç¿ëÇÒ ÆÄÀÏÀÇ Á¾·ù
enum IOMode
{
IO_TEXT, ///< ÅØ½ºÆ® ÆÄÀÏ ÀÔÃâ·Â
IO_BINARY ///< ¹ÙÀ̳ʸ® ÆÄÀÏ ÀÔÃâ·Â
};
private:
class XMLUtil;
class XMLStream;
std::string m_Name; ///< ³ëµåÀÇ À̸§
std::string m_Text; ///< ³ëµå¿¡ ¼ÓÇÑ ÅØ½ºÆ®
XMLTree* m_pParent; ///< ºÎ¸ð ³ëµåÀÇ Æ÷ÀÎÅÍ
ATTRIBUTES m_Attributes; ///< °¡Áö°í ÀÖ´Â ¼Ó¼º°ªµé
CHILDREN m_Children; ///< ÀÚ½Ä ³ëµåµé
public:
/// \brief »ý¼ºÀÚ
/// \param name ³ëµåÀÇ À̸§
/// \param text ³ëµå¿¡ ¼ÓÇÑ ÅØ½ºÆ®
XMLTree(const std::string& name="", const std::string& text="");
/// \brief ¼Ò¸êÀÚ
virtual ~XMLTree();
public:
/// \brief ³ëµåÀÇ À̸§À» ¹ÝȯÇÑ´Ù.
/// \return const std::string& ³ëµåÀÇ À̸§
const std::string& getName() const { return m_Name; }
/// \brief ³ëµåÀÇ À̸§À» ¼³Á¤ÇÑ´Ù.
/// \param name ³ëµåÀÇ À̸§
void setName(const std::string& name) { m_Name = name; }
/// \brief ³ëµå¿¡ ÇÒ´çµÈ ÅØ½ºÆ®¸¦ ¹ÝȯÇÑ´Ù.
/// \return const std::string& ³ëµå¿¡ ÇÒ´çµÈ ÅØ½ºÆ®
const std::string& getText() const { return m_Text; }
/// \brief ³ëµå¿¡ ÇÒ´çÇÒ ÅØ½ºÆ®¸¦ ¼³Á¤ÇÑ´Ù.
/// \param text ³ëµå¿¡ ÇÒ´çÇÒ ÅØ½ºÆ®
void setText(const std::string& text) { m_Text = text; }
/// \brief ºÎ¸ð ³ëµå¸¦ ¹ÝȯÇÑ´Ù.
/// \return XMLTree* ºÎ¸ð ³ëµåÀÇ Æ÷ÀÎÅÍ
XMLTree* getParent() const { return m_pParent; }
/// \brief ºÎ¸ð ³ëµå¸¦ ¼³Á¤ÇÑ´Ù.
/// \param pParent ºÎ¸ð ³ëµå °´Ã¼
void setParent(XMLTree* pParent) { m_pParent = pParent; }
public:
/// \brief ³ëµå¿¡ ¼Ó¼ºÀ» Ãß°¡ÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param value ¼Ó¼º °ª
void setAttr(const std::string& name, int value) {
char buf[256] = {0,};
_snprintf(buf, sizeof(buf)-1, "%d", value);
buf[sizeof(buf)-1] = 0;
setAttr(name, std::string(buf));
}
void setAttr(const std::string& name, unsigned int value) {
char buf[256] = {0,};
_snprintf(buf, sizeof(buf)-1, "%d", value);
buf[sizeof(buf)-1] = 0;
setAttr(name, std::string(buf));
}
/// \brief ³ëµå¿¡ ¼Ó¼ºÀ» Ãß°¡ÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param value ¼Ó¼º °ª
void setAttr(const std::string& name, double value) {
char buf[256] = {0,};
_snprintf(buf, sizeof(buf)-1, "%f", value);
buf[sizeof(buf)-1] = 0;
setAttr(name, std::string(buf));
}
/// \brief ³ëµå¿¡ ¼Ó¼ºÀ» Ãß°¡ÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param value ¼Ó¼º °ª
void setAttr(const std::string& name, float value) {
char buf[256] = {0,};
_snprintf(buf, sizeof(buf)-1, "%f", value);
buf[sizeof(buf)-1] = 0;
setAttr(name, std::string(buf));
}
/// \brief ³ëµå¿¡ ¼Ó¼ºÀ» Ãß°¡ÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param value ¼Ó¼º °ª
void setAttr(const std::string& name, bool value) {
setAttr(name, value ? std::string("true") : std::string("false"));
}
/// \brief ³ëµå¿¡ ¼Ó¼ºÀ» Ãß°¡ÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param value ¼Ó¼º °ª
void setAttr(const std::string& name, const char* value) {
assert(!name.empty());
m_Attributes[name] = value;
}
/// \brief ³ëµå¿¡ ¼Ó¼ºÀ» Ãß°¡ÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param value ¼Ó¼º °ª
void setAttr(const std::string& name, const std::string& value) {
assert(!name.empty());
m_Attributes[name] = value;
}
public:
/// \brief ÇØ´çÇÏ´Â À̸§ÀÇ ¼Ó¼ºÀÇ Á¸Àç À¯¹Â¸¦ ¸®ÅÏÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \return bool ¼Ó¼º °ªÀÌ Á¸ÀçÇÏ´Â °æ¿ì true, Á¸ÀçÇÏÁö ¾Ê´Â´Ù¸é false
bool attrExist(const std::string& name) const {
return m_Attributes.find(name) != m_Attributes.end();
}
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» ¹®ÀÚ¿ ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \return std::string ¼Ó¼º °ª
std::string attrAsString(const std::string& name) const;
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» Á¤¼ö ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \return int ¼Ó¼º °ª
int attrAsInt(const std::string& name) const {
return atoi(attrAsString(name).c_str());
}
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» ½Ç¼ö ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \return double ¼Ó¼º °ª
double attrAsDouble(const std::string& name) const {
return atof(attrAsString(name).c_str());
}
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» ½Ç¼ö ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \return float ¼Ó¼º °ª
float attrAsFloat(const std::string& name) const {
return static_cast<float>(atof(attrAsString(name).c_str()));
}
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» ºÒ¸° ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \return bool ¼Ó¼º °ª
bool attrAsBool(const std::string& name) const {
return attrAsString(name) == "true";
}
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» ¹®ÀÚ¿ ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param default_value ÇØ´ç ¼Ó¼ºÀÌ Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì ¹ÝȯÇÒ °ª
/// \return std::string ¼Ó¼º °ª
std::string attrAsStringSafe(const std::string& name, const std::string& default_value="") const;
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» Á¤¼ö ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param default_value ÇØ´ç ¼Ó¼ºÀÌ Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì ¹ÝȯÇÒ °ª
/// \return int ¼Ó¼º °ª
int attrAsIntSafe(const std::string& name, int default_value=0) const;
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» ½Ç¼ö ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param default_value ÇØ´ç ¼Ó¼ºÀÌ Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì ¹ÝȯÇÒ °ª
/// \return double ¼Ó¼º °ª
double attrAsDoubleSafe(const std::string& name, double default_value=0.0) const;
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» ½Ç¼ö ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param default_value ÇØ´ç ¼Ó¼ºÀÌ Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì ¹ÝȯÇÒ °ª
/// \return float ¼Ó¼º °ª
float attrAsFloatSafe(const std::string& name, float default_value=0.0) const;
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» ºÒ¸° ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param default_value ÇØ´ç ¼Ó¼ºÀÌ Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì ¹ÝȯÇÒ °ª
/// \return bool ¼Ó¼º °ª
bool attrAsBoolSafe(const std::string& name, bool default_value=false) const;
/// \brief ¼Ó¼º Ä÷º¼ÇÀ» ¹ÝȯÇÑ´Ù.
/// \return const ATTRIBUTES& ¼Ó¼º Ä÷º¼Ç
const ATTRIBUTES& getAttributes() const { return m_Attributes; }
public:
/// \brief ÀÚ½Ä ³ëµå¸¦ Ãß°¡ÇÑ´Ù.
/// \param pTree ÀÚ½Ä ³ëµå °´Ã¼
void addChild(XMLTree* pTree)
{
m_Children.push_back(pTree);
pTree->setParent(this);
}
/// \brief ÀÚ½Ä ³ëµå¸¦ Ãß°¡ÇÑ´Ù.
/// \param name ÀÚ½Ä ³ëµåÀÇ À̸§
/// \param text ³ëµå¿¡ ¼ÓÇÑ ÅØ½ºÆ®
/// \return XMLTree* »õ·Î »ý¼ºÇÑ ÀÚ½Ä ³ëµå °´Ã¼
XMLTree* addChild(const std::string& name, const std::string& text="")
{
XMLTree* pChild = new XMLTree(name, text);
pChild->setParent(this);
m_Children.push_back(pChild);
return pChild;
}
/// \brief ÀÚ½Ä ³ëµåÀÇ ¼ýÀÚ¸¦ ¹Ýȯ.
/// \return size_t ÀÚ½Ä ³ëµåÀÇ °¹¼ö
size_t getChildCount() const { return m_Children.size(); }
/// \brief ÇØ´çÇÏ´Â À妽ºÀÇ ÀÚ½Ä ³ëµå¸¦ ¹Ýȯ.
/// \param index ÀÚ½Ä ³ëµå À妽º
/// \return XMLTree* ÀÚ½Ä ³ëµå °´Ã¼. À妽º°¡ ¹üÀ§¸¦ ³Ñ¾î°¡´Â °æ¿ì¿¡´Â
/// NULLÀ» ¹ÝȯÇÑ´Ù.
XMLTree* getChild(size_t index) const {
return index < m_Children.size() ? m_Children[index] : NULL;
}
/// \brief ÀÚ½Ä ³ëµå Áß¿¡ ÇØ´çÇÏ´Â À̸§À» °¡Áø Á¦ÀÏ Ã¹¹øÂ° ³ëµå¸¦ ¹Ýȯ.
/// \param name ÀÚ½Ä ³ëµåÀÇ À̸§
/// \return XMLTree* °°Àº À̸§À» °¡Áö´Â ÀÚ½Ä ³ëµåµé Áß¿¡¼ ù¹øÂ°·Î
/// ³ªÅ¸³ª´Â ³ëµå. ÇØ´çÇÏ´Â À̸§À» °¡Áö´Â ÀÚ½Ä ³ëµå°¡ Á¸ÀçÇÏÁö ¾Ê´Â
/// °æ¿ì¿¡´Â NULLÀ» ¹ÝȯÇÑ´Ù.
XMLTree* getChild(const std::string& name) const
{
for (size_t i=0; i<m_Children.size(); i++)
if (m_Children[i]->getName() == name) return m_Children[i];
return NULL;
}
/// \brief ÇØ´çÇÏ´Â À妽ºÀÇ ³ëµå¸¦ »èÁ¦ÇÑ´Ù.
/// \param index »èÁ¦ÇÒ ÀÚ½Ä ³ëµåÀÇ À妽º
/// \return XMLTree* ÄÁÅ×À̳ʿ¡¼ »èÁ¦ÇÑ ÈÄ, ÇØ´çÇÏ´Â ³ëµå¸¦ ¹ÝȯÇÑ´Ù.
/// À妽º°¡ À߸øµÈ °æ¿ì¿¡´Â NULLÀ» ¹ÝȯÇÑ´Ù.
XMLTree* removeChild(size_t index)
{
if (index >= m_Children.size()) return NULL;
XMLTree* pChild = m_Children[index];
m_Children.erase(m_Children.begin() + index);
return pChild;
}
/// \brief ¸ðµç ÀÚ½Ä ³ëµåµé°ú ¼Ó¼º°ªÀ» »èÁ¦ÇÑ´Ù.
void clear()
{
m_Attributes.clear();
for (size_t i=0; i<m_Children.size(); i++) { delete m_Children[i]; }
m_Children.clear();
}
public:
/// \brief XML ÆÄÀÏ¿¡¼ µ¥ÀÌÅ͸¦ Àоîµé¿© µ¥ÀÌÅ͸¦ ±¸¼ºÇÑ´Ù.
/// \param filename ÀоîµéÀÏ ÆÄÀÏÀÇ À̸§
/// \param mode ÀÔÃâ·Â ¸ðµå
/// \return bool ÆÄÀÏÀ» ¼º°øÀûÀ¸·Î ÀоîµéÀÎ °æ¿ì¿¡´Â false, ¹º°¡ ¿¡·¯°¡
/// »ý±ä °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇÑ´Ù.
bool load(const char* filename, IOMode mode=IO_TEXT);
/// \brief ÀڽŰú ÀÚ½Ä ³ëµå¿¡ °üÇÑ Á¤º¸¸¦ ÆÄÀÏ¿¡´Ù ÀúÀåÇÑ´Ù.
/// \param filename ¾µ ÆÄÀÏÀÇ À̸§
/// \param encoding XML ÆÄÀÏ ¾ÕºÎºÐ¿¡´Ù ºÙÀÏ ÀÎÄÚµù ¹®ÀÚ¿
/// \param mode ÀÔÃâ·Â ¸ðµå
/// \return bool ÆÄÀÏÀ» ¼º°øÀûÀ¸·Î ¾´ °æ¿ì¿¡´Â false, ¹º°¡ ¿¡·¯°¡ »ý±ä
/// °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
bool save(const char* filename, IOMode mode=IO_TEXT, const char* encoding="euc-kr");
private:
/// \brief ³»ºÎÀûÀ¸·Î »ç¿ëÇÏ´Â Àç±Í È£Ãâ¿ë ÆÄ½Ì ÇÔ¼ö
/// \param file XML µ¥ÀÌÅͰ¡ µé¾îÀÖ´Â ½ºÆ®¸² °´Ã¼
/// \param msg ÆÄ½Ì Áß ¿¡·¯°¡ ¹ß»ýÇßÀ» ¶§ Ãâ·ÂÇÒ ¸Þ½ÃÁö Çì´õ
void loadText(XMLStream& file, const std::string& msg);
/// \brief ³»ºÎÀûÀ¸·Î »ç¿ëÇÏ´Â Àç±Í È£Ãâ¿ë ÀúÀå ÇÔ¼ö
/// \param file ÆÄÀÏ ½ºÆ®¸²
/// \param indent µé¿©¾²±â ·¹º§
void saveText(std::ofstream& file, size_t indent);
/// \brief ³»ºÎÀûÀ¸·Î »ç¿ëÇÏ´Â Àç±Í È£Ãâ¿ë ÆÄ½Ì ÇÔ¼ö
/// \param file XML µ¥ÀÌÅͰ¡ µé¾îÀÖ´Â ½ºÆ®¸² °´Ã¼
/// \param msg ÆÄ½Ì Áß ¿¡·¯°¡ ¹ß»ýÇßÀ» ¶§ Ãâ·ÂÇÒ ¸Þ½ÃÁö Çì´õ
void loadBinary(std::ifstream& file, const std::string& msg);
/// \brief ³»ºÎÀûÀ¸·Î »ç¿ëÇÏ´Â Àç±Í È£Ãâ¿ë ÀúÀå ÇÔ¼ö
/// \param file ÆÄÀÏ ½ºÆ®¸²
void saveBinary(std::ofstream& file);
};
3 XML.cpp
//////////////////////////////////////////////////////////////////////////////
/// \file XML.cpp
/// \author excel96
/// \date 2004.9.20
//////////////////////////////////////////////////////////////////////////////
#include "XMLTree.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <fstream>
//////////////////////////////////////////////////////////////////////////////
// »ó¼ö ¼±¾ð
//////////////////////////////////////////////////////////////////////////////
static const char* XML_ERROR_FILENAME = "__XMLError.log";
static const std::string XML_OPERATORS = " \t\r\n\"\'<>!=/?!";
static const std::string XML_WHITESPACES = " \t\r\n";
static const std::string XML_LINEFEEDS = "\r\n";
static const std::string XML_ATTR_TOKENS = "\"\'";
static const char XML_LEFT_BRACKET = '<';
static const char XML_RIGHT_BRACKET = '>';
static const char XML_BANG = '!';
static const char XML_HYPHEN = '-';
static const char XML_EQUAL = '=';
static const char XML_DIVIDE = '/';
static const unsigned short XML_STRING_LENGTH_MAX = 1024;
//////////////////////////////////////////////////////////////////////////////
/// \class XMLUtil
/// \brief À¯Æ¿¸®Æ¼ ÇÔ¼öµé
//////////////////////////////////////////////////////////////////////////////
class XMLTree::XMLUtil
{
public:
/// \brief ÇØ´ç ij¸¯ÅͰ¡ °ø¹é ¹®ÀÚÀÎÁöÀÇ ¿©ºÎ¸¦ ¹ÝȯÇÑ´Ù.
/// \param c °Ë»çÇÒ Ä³¸¯ÅÍ
/// \return bool °ø¹é ¹®ÀÚÀÎ °æ¿ì true, ¾Æ´Ï¶ó¸é flase
static bool isWhitespace(char c) {
return XML_WHITESPACES.find_first_of(c) != std::string::npos;
}
/// \brief ÇØ´ç ij¸¯ÅͰ¡ ¶óÀÎÇÇµå ¹®ÀÚÀÎÁöÀÇ ¿©ºÎ¸¦ ¹ÝȯÇÑ´Ù.
/// \param c °Ë»çÇÒ Ä³¸¯ÅÍ
/// \return bool °ø¹é ¹®ÀÚÀÎ °æ¿ì true, ¾Æ´Ï¶ó¸é false
static bool isLinefeed(char c) {
return XML_LINEFEEDS.find_first_of(c) != std::string::npos;
}
/// \brief sprintf ÇÔ¼ö¿Í °°Àº ¹æ½ÄÀ¸·Î ¹®ÀÚ¿À» »ý¼ºÇؼ ¹ÝȯÇÑ´Ù.
/// \param fmt Æ÷¸Ë
/// \param ... °¡º¯ Àμö
/// \return std::string ¹®ÀÚ¿
static std::string sprintf(const char* fmt, ...)
{
assertPtr(fmt);
std::string formatted;
va_list args;
va_start(args, fmt);
formatted = XMLUtil::vsprintf(fmt, args);
va_end(args);
return formatted;
}
/// \brief sprintf ÇÔ¼ö¿Í °°Àº ¹æ½ÄÀ¸·Î ¹®ÀÚ¿À» »ý¼ºÇؼ ¹ÝȯÇÑ´Ù.
/// \param fmt Æ÷¸Ë
/// \param args ÀÎÀÚ
/// \return std::string »ý¼ºÇÑ ¹®ÀÚ¿
static std::string vsprintf(const char* fmt, va_list args)
{
assertPtr(fmt);
std::string formatted;
// ÀÏ´Ü ±âº» ½ºÅà ¹öÆÛ¸¦ °¡Áö°í ¹®ÀÚ¿ ¸¸µé±â¸¦ ½ÃµµÇÑ´Ù.
char stack_buf[512] = {0,};
int nchars = _vsnprintf(stack_buf, sizeof(stack_buf)-1, fmt, args);
if (0 < nchars || nchars < sizeof(stack_buf))
{
// ±âº» ½ºÅà ¹öÆÛ·Î ¹®ÀÚ¿ ¸¸µé±â¿¡ ¼º°øÇß´Ù. ÆÄÀÏ¿¡´Ù ·Î±×ÇÑ´Ù.
stack_buf[sizeof(stack_buf)-1] = 0;
formatted = stack_buf;
}
else
{
// ±âº» ½ºÅà ¹öÆÛ·Î´Â Å©±â°¡ ¸ðÀÚ¶ú´Ù. realloc ÇÔ¼ö¸¦ ÀÌ¿ëÇØ
// Èü ¹öÆÛÀÇ Å©±â¸¦ ´Ã·Á°¡¸ç, ¹®ÀÚ¿ ¸¸µé±â¸¦ ½ÃµµÇÑ´Ù.
int buflen = sizeof(stack_buf);
char* heap_buf = NULL;
do {
buflen = buflen * 2;
heap_buf = reinterpret_cast<char*>(::realloc(heap_buf, buflen));
memset(heap_buf, 0, buflen);
nchars = _vsnprintf(heap_buf, buflen, fmt, args);
} while (nchars < 0 || nchars >= buflen);
heap_buf[buflen-1] = 0;
formatted = heap_buf;
::free(heap_buf);
}
return formatted;
}
/// \brief ÆÄÀÏ¿¡´Ù ¿¡·¯¸¦ ·Î±×ÇÑ´Ù.
/// \param fmt Æ÷¸Ë
/// \param ... °¡º¯ Àμö
static void filelog(const char* fmt, ...)
{
assertPtr(fmt);
std::ofstream file(XML_ERROR_FILENAME, std::ios::out | std::ios::app);
if (file.is_open())
{
va_list args;
va_start(args, fmt);
file << XMLUtil::vsprintf(fmt, args) << std::endl;
va_end(args);
}
}
/// \brief ÆÄÀÏ¿¡¼ ¹®ÀÚ¿À» Àоîµé¿© ¹ÝȯÇÑ´Ù.
/// \param file ¹®ÀÚ¿À» ÀоîµéÀÏ ÆÄÀÏ °´Ã¼
/// \return std::string ÀоîµéÀÎ ¹®ÀÚ¿
static std::string readWORDString(std::ifstream& file)
{
assert(file.good());
unsigned short length = 0;
file.read(reinterpret_cast<char*>(&length), sizeof(length));
assert(length < XML_STRING_LENGTH_MAX);
if (length > 0)
{
char buf[XML_STRING_LENGTH_MAX] = {0,};
file.read(buf, length);
return buf;
}
return "";
}
/// \brief ÆÄÀÏ¿¡´Ù ¹®ÀÚ¿ÀÇ ±æÀ̸¦ 2¹ÙÀÌÆ®·Î ±â·ÏÇϰí, ±× ´ÙÀ½ ¹®ÀÚ¿
/// ³»¿ëÀ» ±â·ÏÇÑ´Ù.
/// \param file ±â·ÏÇÒ ÆÄÀÏ °´Ã¼
/// \param text ±â·ÏÇÒ ÅØ½ºÆ®
static void writeWORDString(std::ofstream& file, const std::string& text)
{
assert(file.good());
unsigned short length = static_cast<unsigned short>(text.size());
file.write(reinterpret_cast<const char*>(&length), sizeof(length));
if (length > 0)
file.write(text.c_str(), length);
}
};
//////////////////////////////////////////////////////////////////////////////
/// \class XMLTree::XMLStream
/// \brief ½ºÆ®¸² °´Ã¼
//////////////////////////////////////////////////////////////////////////////
class XMLTree::XMLStream
{
private:
std::istream& m_stream; ///< ½ºÆ®¸² °´Ã¼ ÂüÁ¶
int m_line; ///< ÇöÀç ¶óÀÎ
int m_column; ///< ÇöÀç Ä÷³
char m_prev; ///< ¸¶Áö¸·À¸·Î ÀоîµéÀÎ ±ÛÀÚ
public:
/// \brief »ý¼ºÀÚ
/// \param stream ¿øº» ½ºÆ®¸² °´Ã¼
XMLStream(std::istream& stream)
: m_stream(stream), m_line(1), m_column(1), m_prev(0) {}
/// \brief ¼Ò¸êÀÚ
~XMLStream() {}
public:
/// \brief ½ºÆ®¸²¿¡¼ ij¸¯ÅÍ Çϳª¸¦ »Ì¾Æ³½´Ù.
/// \return char ½ºÆ®¸²¿¡¼ »Ì¾Æ³½ ij¸¯ÅÍ. ½ºÆ®¸²¿¡¼ ´õ ÀÌ»óÀÇ Ä³¸¯Å͸¦
/// »Ì¾Æ³¾ ¼ö ¾ø´Â °æ¿ì, ¿¹¿Ü¸¦ ´øÁø´Ù.
char get()
{
char c = 0;
if (!m_stream.get(c))
{
throw XMLUtil::sprintf(
"unexpected eof at %d line %d column", m_line, m_column);
}
if (XMLUtil::isLinefeed(c) && !XMLUtil::isLinefeed(m_prev))
{
m_line++;
m_column = 0;
}
m_prev = c;
m_column++;
return c;
}
/// \brief ½ºÆ®¸²¿¡¼ ij¸¯ÅÍ Çϳª¸¦ »Ì¾Æ³½´Ù.
/// \return char ½ºÆ®¸²¿¡¼ »Ì¾Æ³½ ij¸¯ÅÍ. ½ºÆ®¸²¿¡¼ ´õ ÀÌ»óÀÇ
/// ij¸¯Å͸¦ »Ì¾Æ³¾ ¼ö ¾ø´Â °æ¿ì¿¡´Â 0À» ¹ÝȯÇÑ´Ù.
char getRaw()
{
char c = 0;
if (!m_stream.get(c)) return 0;
if (XMLUtil::isLinefeed(c) && !XMLUtil::isLinefeed(m_prev))
{
m_line++;
m_column = 0;
}
m_prev = c;
m_column++;
return c;
}
/// \brief ´ÙÀ½¿¡ ÀоîµéÀÏ Ä³¸¯Å͸¦ °Ë»çÇÑ´Ù.
/// \return char ½ºÆ®¸²¿¡ µé¾îÀִ ij¸¯ÅÍ.
char peek() const { return (char)m_stream.peek(); }
/// \brief ÇöÀç ó¸® ÁßÀÎ ¶óÀÎ ¹øÈ£¸¦ ¹ÝȯÇÑ´Ù.
/// \return int ÇöÀç ó¸® ÁßÀÎ ¶óÀÎ ¹øÈ£
int getCurrentLine() const { return m_line; }
/// \brief ÇöÀç ó¸® ÁßÀÎ Ä÷³ ¹øÈ£¸¦ ¹ÝȯÇÑ´Ù.
/// \return int ÇöÀç ó¸®ÁßÀÎ Ä÷³ ¹øÈ£
int getCurrentColumn() const { return m_column; }
public:
/// \brief ½ºÆ®¸²¿¡¼ °ø¹é ¹®ÀÚ ¹× ÁÖ¼®À» °Ç³Ê¶Ú´Ù.
/// \param c °ø¹é ¹®ÀÚ¸¦ ´Ù °Ç³Ê¶Ú ´ÙÀ½¿¡ ³ª¿À´Â ±ÛÀÚ.
void eatWhitespace(char& c)
{
do
{
while (XMLUtil::isWhitespace(c))
c = get();
if (c == XML_LEFT_BRACKET && peek() == XML_BANG)
{
c = get();
do {
c = get();
} while(!(c == XML_HYPHEN && peek() == XML_RIGHT_BRACKET));
// eat last '>' and next char
c = get();
c = get();
}
while (XMLUtil::isWhitespace(c))
c = get();
} while (c == '<' && peek() == XML_BANG);
}
/// \brief ½ºÆ®¸²¿¡¼ °ø¹é ¹®ÀÚµéÀ» °Ç³Ê¶Ú ÈÄ, ³ª¿À´Â ±ÛÀÚ°¡ ÁÖ¾îÁø
/// ±¸ºÐÀÚÀÎÁö¸¦ °Ë»çÇÏ°í °Ç³Ê¶Ú´Ù.
/// \param c °ø¹é ¹®ÀÚ¸¦ ´Ù °Ç³Ê¶Ú ´ÙÀ½¿¡ ³ª¿À´Â ±ÛÀÚ.
/// \param delim ³ª¿Í¾ßÇÏ´Â ¹®ÀÚ
/// \param msg ¿¡·¯°¡ ¹ß»ýÇßÀ» ¶§ Ãâ·ÂÇÒ ¸Þ½ÃÁö Çì´õ
void eatDelim(char& c, const char delim, const std::string& msg)
{
eatWhitespace(c);
if (c != delim)
{
throw XMLUtil::sprintf(
"%s: syntax error at %d line %d column, expect '%c' but '%c'",
msg.c_str(), m_line, m_column, delim, c);
}
c = getRaw();
}
/// \brief ½ºÆ®¸²¿¡¼ °ø¹é ¹®ÀÚµéÀ» °Ç³Ê¶Ú ÈÄ, ³ª¿À´Â ±ÛÀÚ°¡ ¼Ó¼º°ªÀÇ
/// ½ÃÀÛ ¹®ÀÚ(' ¶Ç´Â ")ÀÎÁö¸¦ °Ë»çÇÏ°í °Ç³Ê¶Ú´Ù.
/// ±¸ºÐÀÚÀÎÁö¸¦ °Ë»çÇϰí
/// \param c °ø¹é ¹®ÀÚ¸¦ ´Ù °Ç³Ê¶Ú ´ÙÀ½¿¡ ³ª¿À´Â ±ÛÀÚ.
/// \param msg ¿¡·¯°¡ ¹ß»ýÇßÀ» ¶§ Ãâ·ÂÇÒ ¸Þ½ÃÁö Çì´õ
void eatAttributeDelim(char& c, const std::string& msg)
{
eatWhitespace(c);
if (XML_ATTR_TOKENS.find_first_of(c) == std::string::npos)
{
throw XMLUtil::sprintf(
"%s: syntax error at %d line %d column, expect '%s' but '%c'",
msg.c_str(), m_line, m_column, XML_ATTR_TOKENS.c_str(), c);
}
c = getRaw();
}
/// \brief ½ºÆ®¸²¿¡¼ XML Çì´õ¸¦ °Ç³Ê¶Ú´Ù.
void eatHeader()
{
char c = 0;
do
{
c = get();
} while (c != XML_RIGHT_BRACKET);
c = get();
eatWhitespace(c);
}
/// \brief ½ºÆ®¸²¿¡¼ ¼Ó¼º À̸§ ¹®ÀÚ¿À» Àо¾î ¹ÝȯÇÑ´Ù.
///
/// <sample name="somevalue">...
/// ^^^^^^ ^^^^
///
/// \param c À̸§ ¹®ÀÚ¿ ³¡¿¡ ³ª¿À´Â ±ÛÀÚ
/// \return std::string À̸§ ¹®ÀÚ¿
std::string extractName(char& c)
{
std::string result;
eatWhitespace(c);
while (XML_OPERATORS.find_first_of(c) == std::string::npos)
{
result += c;
c = get();
}
return result;
}
/// \brief ½ºÆ®¸²¿¡¼ ¼Ó¼º °ª ¹®ÀÚ¿À» Àо¾î ¹ÝȯÇÑ´Ù.
///
/// <sample name="somevalue">...
/// ^^^^^^^^^
///
/// \param c °ª ¹®ÀÚ¿ ³¡¿¡ ³ª¿À´Â ±ÛÀÚ
/// \return std::string °ª ¹®ÀÚ¿
std::string extractValue(char& c)
{
std::string result;
while (XML_ATTR_TOKENS.find_first_of(c) == std::string::npos)
{
result += c;
c = get();
}
c = get();
return result;
}
private:
// º¹»ç ¹× ´ëÀÔ ¿¬»ê ¹æÁö
XMLStream(const XMLStream& other) : m_stream(other.m_stream) {}
const XMLStream& operator = (const XMLStream&) { return *this; }
};
//////////////////////////////////////////////////////////////////////////////
/// \brief »ý¼ºÀÚ
/// \param name ³ëµåÀÇ À̸§
/// \param text ³ëµå¿¡ ¼ÓÇÑ ÅØ½ºÆ®
//////////////////////////////////////////////////////////////////////////////
XMLTree::XMLTree(const std::string& name, const std::string& text)
: m_Name(name), m_Text(text), m_pParent(NULL)
{
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ¼Ò¸êÀÚ
//////////////////////////////////////////////////////////////////////////////
XMLTree::~XMLTree()
{
clear();
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» ¹®ÀÚ¿ ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \return std::string ¼Ó¼º °ª
//////////////////////////////////////////////////////////////////////////////
std::string XMLTree::attrAsString(const std::string& name) const
{
assert(!name.empty());
ATTRIBUTES::const_iterator itr = m_Attributes.find(name);
if (itr == m_Attributes.end())
{
XMLUtil::filelog("specified attr '%s' does not exist in node '%s'",
name.c_str(), m_Name.c_str());
assert(false && "specified attr does not exist");
return "";
}
return itr->second;
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» ¹®ÀÚ¿ ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \return std::string ¼Ó¼º °ª
//////////////////////////////////////////////////////////////////////////////
std::string XMLTree::attrAsStringSafe(const std::string& name,
const std::string& default_value) const
{
assert(!name.empty());
ATTRIBUTES::const_iterator itr = m_Attributes.find(name);
return itr != m_Attributes.end() ? itr->second : default_value;
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» Á¤¼ö ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param default_value ÇØ´ç ¼Ó¼ºÀÌ Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì ¹ÝȯÇÒ °ª
/// \return int ¼Ó¼º °ª
//////////////////////////////////////////////////////////////////////////////
int XMLTree::attrAsIntSafe(const std::string& name, int default_value) const
{
assert(!name.empty());
ATTRIBUTES::const_iterator itr = m_Attributes.find(name);
return itr != m_Attributes.end() ?
atoi(itr->second.c_str()) : default_value;
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» ½Ç¼ö ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param default_value ÇØ´ç ¼Ó¼ºÀÌ Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì ¹ÝȯÇÒ °ª
/// \return double ¼Ó¼º °ª
//////////////////////////////////////////////////////////////////////////////
double XMLTree::attrAsDoubleSafe(const std::string& name,
double default_value) const
{
assert(!name.empty());
ATTRIBUTES::const_iterator itr = m_Attributes.find(name);
return itr != m_Attributes.end() ?
atof(itr->second.c_str()) : default_value;
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» ½Ç¼ö ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param default_value ÇØ´ç ¼Ó¼ºÀÌ Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì ¹ÝȯÇÒ °ª
/// \return float ¼Ó¼º °ª
//////////////////////////////////////////////////////////////////////////////
float XMLTree::attrAsFloatSafe(const std::string& name,
float default_value) const
{
assert(!name.empty());
ATTRIBUTES::const_iterator itr = m_Attributes.find(name);
return itr != m_Attributes.end() ?
static_cast<float>(atof(itr->second.c_str())) : default_value;
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ÇØ´ç ¼Ó¼ºÀÇ °ªÀ» ºÒ¸° ÇüÅ·Π¹ÝȯÇÑ´Ù.
/// \param name ¼Ó¼º À̸§
/// \param default_value ÇØ´ç ¼Ó¼ºÀÌ Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì ¹ÝȯÇÒ °ª
/// \return bool ¼Ó¼º °ª
//////////////////////////////////////////////////////////////////////////////
bool XMLTree::attrAsBoolSafe(const std::string& name,
bool default_value) const
{
assert(!name.empty());
ATTRIBUTES::const_iterator itr = m_Attributes.find(name);
return itr != m_Attributes.end() ? itr->second == "true" : default_value;
}
//////////////////////////////////////////////////////////////////////////////
/// \brief XML ÆÄÀÏ¿¡¼ µ¥ÀÌÅ͸¦ Àоîµé¿© µ¥ÀÌÅ͸¦ ±¸¼ºÇÑ´Ù.
/// \param filename ÀоîµéÀÏ ÆÄÀÏÀÇ À̸§
/// \param mode ÀÔÃâ·Â ¸ðµå
/// \return bool ÆÄÀÏÀ» ¼º°øÀûÀ¸·Î ÀоîµéÀÎ °æ¿ì¿¡´Â false, ¹º°¡ ¿¡·¯°¡
/// »ý±ä °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇÑ´Ù.
//////////////////////////////////////////////////////////////////////////////
bool XMLTree::load(const char* filename, IOMode mode)
{
if (mode == IO_TEXT)
{
std::ifstream file(filename, std::ios::in);
if (!file)
{
XMLUtil::filelog(
"cannot open specified file for read - %s", filename);
return true;
}
bool rvalue = false;
XMLStream stream(file);
stream.eatHeader();
try
{
loadText(stream, filename);
}
catch (std::string& e)
{
XMLUtil::filelog("%s", e.c_str());
assert(false && "xml parsing error");
rvalue = true;
}
return rvalue;
}
else if (mode == IO_BINARY)
{
std::ifstream file(filename, std::ios::in | std::ios::binary);
if (!file)
{
XMLUtil::filelog(
"cannot open specified file for read - %s", filename);
return true;
}
XMLUtil::readWORDString(file); // Çì´õ¸¦ ÀоîµéÀδÙ.
loadBinary(file, filename);
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ÀڽŰú ÀÚ½Ä ³ëµå¿¡ °üÇÑ Á¤º¸¸¦ ÆÄÀÏ¿¡´Ù ÀúÀåÇÑ´Ù.
/// \param filename ¾µ ÆÄÀÏÀÇ À̸§
/// \param encoding XML ÆÄÀÏ ¾ÕºÎºÐ¿¡´Ù ºÙÀÏ ÀÎÄÚµù ¹®ÀÚ¿
/// \param mode ÀÔÃâ·Â ¸ðµå
/// \return bool ÆÄÀÏÀ» ¼º°øÀûÀ¸·Î ¾´ °æ¿ì¿¡´Â false, ¹º°¡ ¿¡·¯°¡ »ý±ä
/// °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
//////////////////////////////////////////////////////////////////////////////
bool XMLTree::save(const char* filename, IOMode mode, const char* encoding)
{
if (mode == IO_TEXT)
{
std::ofstream file(filename, std::ios::out | std::ios::trunc);
if (!file)
{
XMLUtil::filelog(
"cannot open specified file for write - %s", filename);
return true;
}
file << XMLUtil::sprintf(
"<?xml version=\"1.0\" encoding=\"%s\"?>", encoding) << std::endl;
saveText(file, 0);
return false;
}
else if (mode == IO_BINARY)
{
std::ofstream file(filename, std::ios::out | std::ios::binary | std::ios::trunc);
if (!file)
{
XMLUtil::filelog(
"cannot open specified file for write - %s", filename);
return true;
}
XMLUtil::writeWORDString( file, XMLUtil::sprintf(
"<?xml version=\"1.0\" encoding=\"%s\"?>", encoding) );
saveBinary(file);
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ³»ºÎÀûÀ¸·Î »ç¿ëÇÏ´Â Àç±Í È£Ãâ¿ë ÆÄ½Ì ÇÔ¼ö
/// \param file XML µ¥ÀÌÅͰ¡ µé¾îÀÖ´Â ½ºÆ®¸² °´Ã¼
/// \param msg ÆÄ½Ì Áß ¿¡·¯°¡ ¹ß»ýÇßÀ» ¶§ Ãâ·ÂÇÒ ¸Þ½ÃÁö Çì´õ
//////////////////////////////////////////////////////////////////////////////
void XMLTree::loadText(XMLStream& file, const std::string& msg)
{
char c = file.get();
if (c == XML_LEFT_BRACKET)
{
c = file.get();
}
setName(file.extractName(c));
file.eatWhitespace(c);
// attributes
while (c != XML_RIGHT_BRACKET)
{
if (c == XML_DIVIDE && file.peek() == XML_RIGHT_BRACKET)
{
c = file.get(); // next XML_RIGHT_BRACKET
return;
}
std::string attrname = file.extractName(c);
file.eatDelim(c, XML_EQUAL, msg);
file.eatAttributeDelim(c, msg);
std::string attrvalue = file.extractValue(c);
setAttr(attrname, attrvalue);
file.eatWhitespace(c);
}
c = file.get(); // next after XML_RIGHT_BRACKET
file.eatWhitespace(c);
// sub-elements
while (c == XML_LEFT_BRACKET)
{
if (file.peek() == XML_DIVIDE) break;
XMLTree* pChild = new XMLTree;
assertPtr(pChild);
pChild->setParent(this);
pChild->loadText(file, msg);
addChild(pChild);
c = file.get(); // next after XML_RIGHT_BRACKET
file.eatWhitespace(c);
}
// content
if (c != XML_LEFT_BRACKET)
{
std::string content;
content += '\n';
while (c != XML_LEFT_BRACKET)
{
content += c;
c = file.get();
}
setText(content);
}
assert(c == XML_LEFT_BRACKET);
c = file.get(); // next after XML_LEFT_BRACKET
file.eatDelim(c, XML_DIVIDE, msg);
std::string end_name(file.extractName(c));
if (getName() != end_name)
{
throw XMLUtil::sprintf(
"syntax error at %d line %d column - beginning name '%s' does not match end name '%s'",
file.getCurrentLine(), file.getCurrentColumn(),
getName().c_str(), end_name.c_str());
}
file.eatDelim(c, XML_RIGHT_BRACKET, msg);
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ³»ºÎÀûÀ¸·Î »ç¿ëÇÏ´Â Àç±Í È£Ãâ¿ë ÀúÀå ÇÔ¼ö
/// \param file ÆÄÀÏ ½ºÆ®¸²
/// \param indent µé¿©¾²±â ·¹º§
//////////////////////////////////////////////////////////////////////////////
void XMLTree::saveText(std::ofstream& file, size_t indent)
{
for (size_t i=0; i<indent; i++) file << "\t";
file << "<" << m_Name;
for (ATTRIBUTES::const_iterator itr = m_Attributes.begin();
itr != m_Attributes.end(); itr++)
{
file << " " << itr->first << "=\"" << itr->second << "\"";
}
// ÇÒ´çµÈ ÅØ½ºÆ® ¹× ÀÚ½Ä ³ëµå°¡ Á¸ÀçÇÏÁö ¾Ê´Â´Ù¸é,
// <nodename/>
// Çü½ÄÀ¸·Î ±â·ÏÇÏ´Â °ÍÀÌ º¸±â ÁÁ´Ù.
if (m_Text.empty() && m_Children.empty())
{
file << "/>" << std::endl;
}
// ÇÒ´çµÈ ÅØ½ºÆ®°¡ Àְųª, ÀÚ½Ä ³ëµå°¡ ÀÖ´Ù¸é,
// <nodename>text...<childnode>...</childnode>...</nodename>
// ÀÌ·± ½ÄÀ¸·Î ÇØ¾ßÇÑ´Ù.
else
{
file << ">" << m_Text << std::endl;
for (CHILDREN::const_iterator itr = m_Children.begin();
itr != m_Children.end(); itr++)
{
(*itr)->saveText(file, indent + 1);
}
for (size_t i=0; i<indent; i++) file << "\t";
file << "</" << m_Name << ">" << std::endl;
}
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ³»ºÎÀûÀ¸·Î »ç¿ëÇÏ´Â Àç±Í È£Ãâ¿ë ÆÄ½Ì ÇÔ¼ö
/// \param file XML µ¥ÀÌÅͰ¡ µé¾îÀÖ´Â ½ºÆ®¸² °´Ã¼
/// \param msg ÆÄ½Ì Áß ¿¡·¯°¡ ¹ß»ýÇßÀ» ¶§ Ãâ·ÂÇÒ ¸Þ½ÃÁö Çì´õ
//////////////////////////////////////////////////////////////////////////////
void XMLTree::loadBinary(std::ifstream& file, const std::string& msg)
{
assert(file.good());
// ÀÚ½ÅÀÇ À̸§À» ÀоîµéÀδÙ.
m_Name = XMLUtil::readWORDString(file);
// ÀÚ½ÅÀÇ ÅØ½ºÆ®¸¦ ÀоîµéÀδÙ.
m_Text = XMLUtil::readWORDString(file);
// ¼Ó¼ºÀÇ °¹¼ö¸¦ ÀоîµéÀδÙ.
unsigned short attrcount = 0;
file.read(reinterpret_cast<char*>(&attrcount), sizeof(attrcount));
// ¼Ó¼ºµéÀ» ÀоîµéÀδÙ.
for (unsigned short i=0; i<attrcount; ++i)
{
std::string attrname = XMLUtil::readWORDString(file);
std::string attrvalue = XMLUtil::readWORDString(file);
setAttr(attrname, attrvalue);
}
// ÀÚ½ÄÀÇ °¹¼ö¸¦ ÀоîµéÀδÙ.
unsigned short childcount = 0;
file.read(reinterpret_cast<char*>(&childcount), sizeof(childcount));
// ÀÚ½ÄÀ» ÀоîµéÀδÙ.
for (unsigned short i=0; i<childcount; i++)
{
XMLTree* pChild = new XMLTree();
assertPtr(pChild);
pChild->setParent(this);
pChild->loadBinary(file, msg);
addChild(pChild);
}
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ³»ºÎÀûÀ¸·Î »ç¿ëÇÏ´Â Àç±Í È£Ãâ¿ë ÀúÀå ÇÔ¼ö
/// \param file ÆÄÀÏ ½ºÆ®¸²
//////////////////////////////////////////////////////////////////////////////
void XMLTree::saveBinary(std::ofstream& file)
{
assert(file.good());
// ÀÚ½ÅÀÇ À̸§À» ÀúÀåÇÑ´Ù.
XMLUtil::writeWORDString(file, m_Name);
// ÀÚ½ÅÀÇ ÅØ½ºÆ®¸¦ ±â·ÏÇÑ´Ù.
XMLUtil::writeWORDString(file, m_Text);
// ¼Ó¼ºÀÇ °¹¼ö¸¦ ÀúÀåÇÑ´Ù.
unsigned short attrcount = static_cast<unsigned short>(m_Attributes.size());
file.write(reinterpret_cast<const char*>(&attrcount), sizeof(attrcount));
// ¸ðµç ¼Ó¼ºÀ» ÀúÀåÇÑ´Ù.
for (ATTRIBUTES::const_iterator itr(m_Attributes.begin());
itr != m_Attributes.end(); ++itr)
{
XMLUtil::writeWORDString(file, itr->first);
XMLUtil::writeWORDString(file, itr->second);
}
// ÀÚ½ÄÀÇ °¹¼ö¸¦ ÀúÀåÇÑ´Ù.
unsigned short childcount = static_cast<unsigned short>(m_Children.size());
file.write(reinterpret_cast<const char*>(&childcount), sizeof(childcount));
// ÀÚ½Ä ³ëµå¸¦ ÀúÀåÇÑ´Ù.
for (CHILDREN::const_iterator itr(m_Children.begin());
itr != m_Children.end(); ++itr)
{
(*itr)->saveBinary(file);
}
}
SeriousMoin v1 (koMoinMoin 1.0a4 Modified)