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 static void xmlErrorCb(void* pstrFilename
, const char* msg
, ...)
26 const std::string
* filename
= (const std::string
*)pstrFilename
;
31 snprintf(buf
, sizeof(buf
)-1, msg
, va_arg(ap
, char*));
32 Log::err(*filename
, buf
);
36 Resourcer::Resourcer(GameWindow
* window
, ClientValues
* conf
)
37 : window(window
), z(NULL
), conf(conf
)
41 Resourcer::~Resourcer()
43 if (z
&& zip_close(z
))
45 std::string("closing : ") + zip_strerror(z
));
48 bool Resourcer::init()
51 z
= zip_open(conf
->world
.c_str(), 0x0, &err
);
54 zip_error_to_str(buf
, sizeof(buf
), err
, errno
);
55 Log::err(conf
->world
, buf
);
61 ImageRef
Resourcer::getImage(const std::string
& name
)
63 if (conf
->cache_enabled
) {
64 ImageRefMap::iterator entry
= images
.find(name
);
65 if (entry
!= images
.end())
69 BufferPtr
buffer(read(name
));
73 Gosu::loadImageFile(bitmap
, buffer
->frontReader());
74 ImageRef
result(new Gosu::Image(window
->graphics(), bitmap
, false));
75 if (conf
->cache_enabled
)
76 images
[name
] = result
;
80 void Resourcer::getBitmap(Gosu::Bitmap
& bitmap
, const std::string
& name
)
82 BufferPtr
buffer(read(name
));
85 return Gosu::loadImageFile(bitmap
, buffer
->frontReader());
88 Gosu::Image
* Resourcer::bitmapSection(const Gosu::Bitmap
& src
,
89 unsigned x
, unsigned y
, unsigned w
, unsigned h
, bool tileable
)
91 return new Gosu::Image(window
->graphics(), src
, x
, y
, w
, h
, tileable
);
95 * We use Gosu::Sample for music because Gosu::Song's SDL implementation
96 * doesn't support loading from a memory buffer at the moment.
98 SampleRef
Resourcer::getSample(const std::string
& name
)
100 if (conf
->cache_enabled
) {
101 SampleRefMap::iterator entry
= samples
.find(name
);
102 if (entry
!= samples
.end())
103 return entry
->second
;
106 BufferPtr
buffer(read(name
));
109 SampleRef
result(new Gosu::Sample(buffer
->frontReader()));
110 if (conf
->cache_enabled
)
111 samples
[name
] = result
;
115 XMLDocRef
Resourcer::getXMLDoc(const std::string
& name
, const std::string
& dtdPath
)
117 if (conf
->cache_enabled
) {
118 XMLMap::iterator entry
= xmls
.find(name
);
119 if (entry
!= xmls
.end())
120 return entry
->second
;
123 XMLDocRef
result(readXMLDocFromDisk(name
, dtdPath
));
124 if (conf
->cache_enabled
)
129 // use RAII to ensure doc is freed
130 // boost::shared_ptr<void> alwaysFreeTheDoc(doc, xmlFreeDoc);
131 xmlDoc
* Resourcer::readXMLDocFromDisk(const std::string
& name
, const std::string
& dtdPath
)
133 const std::string docStr
= readStringFromDisk(name
);
137 xmlParserCtxt
* pc
= xmlNewParserCtxt();
138 const std::string pathname
= path(name
);
139 pc
->vctxt
.userData
= (void*)&pathname
;
140 pc
->vctxt
.error
= xmlErrorCb
;
142 // Parse the XML. Hand over our error callback fn.
143 xmlDoc
* doc
= xmlCtxtReadMemory(pc
, docStr
.c_str(),
144 (int)docStr
.size(), NULL
, NULL
,
147 xmlFreeParserCtxt(pc
);
149 Log::err(pathname
, "Could not parse file");
153 // Load up a Document Type Definition for validating the document.
154 xmlDtd
* dtd
= xmlParseDTD(NULL
, (const xmlChar
*)dtdPath
.c_str());
156 Log::err(dtdPath
, "file not found");
160 // Assert the document is sane here and now so we don't have to have a
161 // billion if-else statements while traversing the document tree.
162 xmlValidCtxt
* vc
= xmlNewValidCtxt();
163 int valid
= xmlValidateDtd(vc
, doc
, dtd
);
164 xmlFreeValidCtxt(vc
);
168 Log::err(pathname
, "XML document does not follow DTD");
175 std::string
Resourcer::readStringFromDisk(const std::string
& name
)
177 struct zip_stat stat
;
183 if (zip_stat(z
, name
.c_str(), 0x0, &stat
)) {
184 Log::err(path(name
), "file missing");
188 size
= (int)stat
.size
;
189 buf
= new char[size
+ 1];
192 zf
= zip_fopen(z
, name
.c_str(), 0x0);
195 std::string("opening : ") + zip_strerror(z
));
199 if (zip_fread(zf
, buf
, size
) != size
) {
200 Log::err(path(name
), "reading didn't complete");
212 Gosu::Buffer
* Resourcer::read(const std::string
& name
)
214 struct zip_stat stat
;
218 if (zip_stat(z
, name
.c_str(), 0x0, &stat
)) {
219 Log::err(path(name
), "file missing");
223 size
= (int)stat
.size
;
225 if (!(zf
= zip_fopen(z
, name
.c_str(), 0x0))) {
227 std::string("opening : ") + zip_strerror(z
));
231 Gosu::Buffer
* buffer
= new Gosu::Buffer
;
232 buffer
->resize(size
);
233 if (zip_fread(zf
, buffer
->data(), size
) != size
) {
234 Log::err(path(name
), "reading didn't complete");
244 std::string
Resourcer::path(const std::string
& entry_name
) const
246 return conf
->world
+ "/" + entry_name
;