1 /******************************
2 ** Tsunagari Tile Engine **
4 ** Copyright 2011 OmegaSDG **
5 ******************************/
10 #include <boost/scoped_ptr.hpp>
11 #include <boost/shared_ptr.hpp>
12 #include <Gosu/Audio.hpp>
13 #include <Gosu/Bitmap.hpp>
14 #include <Gosu/Image.hpp>
15 #include <Gosu/IO.hpp>
21 #include "resourcer.h"
24 #ifndef LIBXML_TREE_ENABLED
25 #error Tree must be enabled in libxml2
28 static void xmlErrorCb(void* pstrFilename
, const char* msg
, ...)
30 const std::string
* filename
= (const std::string
*)pstrFilename
;
35 snprintf(buf
, sizeof(buf
)-1, msg
, va_arg(ap
, char*));
36 Log::err(*filename
, buf
);
40 Resourcer::Resourcer(GameWindow
* window
, ClientValues
* conf
)
41 : window(window
), z(NULL
), conf(conf
)
45 Resourcer::~Resourcer()
47 if (z
&& zip_close(z
))
49 std::string("closing : ") + zip_strerror(z
));
52 bool Resourcer::init()
55 z
= zip_open(conf
->world
.c_str(), 0x0, &err
);
58 zip_error_to_str(buf
, sizeof(buf
), err
, errno
);
59 Log::err(conf
->world
, buf
);
65 ImageRef
Resourcer::getImage(const std::string
& name
)
67 if (conf
->cache_enabled
) {
68 ImageRefMap::iterator entry
= images
.find(name
);
69 if (entry
!= images
.end())
73 BufferPtr
buffer(read(name
));
77 Gosu::loadImageFile(bitmap
, buffer
->frontReader());
78 ImageRef
result(new Gosu::Image(window
->graphics(), bitmap
, false));
79 if (conf
->cache_enabled
)
80 images
[name
] = result
;
84 bool Resourcer::getBitmap(Gosu::Bitmap
& bitmap
, const std::string
& name
)
86 BufferPtr
buffer(read(name
));
88 Gosu::loadImageFile(bitmap
, buffer
->frontReader());
92 Gosu::Image
* Resourcer::bitmapSection(const Gosu::Bitmap
& src
,
93 unsigned x
, unsigned y
, unsigned w
, unsigned h
, bool tileable
)
95 return new Gosu::Image(window
->graphics(), src
, x
, y
, w
, h
, tileable
);
99 * We use Gosu::Sample for music because Gosu::Song's SDL implementation
100 * doesn't support loading from a memory buffer at the moment.
102 SampleRef
Resourcer::getSample(const std::string
& name
)
104 if (conf
->cache_enabled
) {
105 SampleRefMap::iterator entry
= samples
.find(name
);
106 if (entry
!= samples
.end())
107 return entry
->second
;
110 BufferPtr
buffer(read(name
));
113 SampleRef
result(new Gosu::Sample(buffer
->frontReader()));
114 if (conf
->cache_enabled
)
115 samples
[name
] = result
;
119 XMLDocRef
Resourcer::getXMLDoc(const std::string
& name
, const std::string
& dtdPath
)
121 if (conf
->cache_enabled
) {
122 XMLMap::iterator entry
= xmls
.find(name
);
123 if (entry
!= xmls
.end())
124 return entry
->second
;
127 XMLDocRef
result(readXMLDocFromDisk(name
, dtdPath
));
128 if (conf
->cache_enabled
)
133 // use RAII to ensure doc is freed
134 // boost::shared_ptr<void> alwaysFreeTheDoc(doc, xmlFreeDoc);
135 xmlDoc
* Resourcer::readXMLDocFromDisk(const std::string
& name
, const std::string
& dtdPath
)
137 const std::string docStr
= readStringFromDisk(name
);
141 xmlParserCtxt
* pc
= xmlNewParserCtxt();
142 const std::string pathname
= path(name
);
143 pc
->vctxt
.userData
= (void*)&pathname
;
144 pc
->vctxt
.error
= xmlErrorCb
;
146 // Parse the XML. Hand over our error callback fn.
147 xmlDoc
* doc
= xmlCtxtReadMemory(pc
, docStr
.c_str(),
148 (int)docStr
.size(), NULL
, NULL
,
151 xmlFreeParserCtxt(pc
);
153 Log::err(pathname
, "Could not parse file");
157 // Load up a Document Type Definition for validating the document.
158 xmlDtd
* dtd
= xmlParseDTD(NULL
, (const xmlChar
*)dtdPath
.c_str());
160 Log::err(dtdPath
, "file not found");
164 // Assert the document is sane here and now so we don't have to have a
165 // billion if-else statements while traversing the document tree.
166 xmlValidCtxt
* vc
= xmlNewValidCtxt();
167 int valid
= xmlValidateDtd(vc
, doc
, dtd
);
168 xmlFreeValidCtxt(vc
);
172 Log::err(pathname
, "XML document does not follow DTD");
179 std::string
Resourcer::readStringFromDisk(const std::string
& name
)
181 struct zip_stat stat
;
187 if (zip_stat(z
, name
.c_str(), 0x0, &stat
)) {
188 Log::err(path(name
), "file missing");
192 size
= (int)stat
.size
;
193 buf
= new char[size
+ 1];
196 zf
= zip_fopen(z
, name
.c_str(), 0x0);
199 std::string("opening : ") + zip_strerror(z
));
203 if (zip_fread(zf
, buf
, size
) != size
) {
204 Log::err(path(name
), "reading didn't complete");
216 Gosu::Buffer
* Resourcer::read(const std::string
& name
)
218 struct zip_stat stat
;
222 if (zip_stat(z
, name
.c_str(), 0x0, &stat
)) {
223 Log::err(path(name
), "file missing");
227 size
= (int)stat
.size
;
229 if (!(zf
= zip_fopen(z
, name
.c_str(), 0x0))) {
231 std::string("opening : ") + zip_strerror(z
));
235 Gosu::Buffer
* buffer
= new Gosu::Buffer
;
236 buffer
->resize(size
);
237 if (zip_fread(zf
, buffer
->data(), size
) != size
) {
238 Log::err(path(name
), "reading didn't complete");
248 std::string
Resourcer::path(const std::string
& entry_name
) const
250 return conf
->world
+ "/" + entry_name
;