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 images
[name
] = result
;
79 void Resourcer::getBitmap(Gosu::Bitmap
& bitmap
, const std::string
& name
)
81 BufferPtr
buffer(read(name
));
84 return Gosu::loadImageFile(bitmap
, buffer
->frontReader());
87 Gosu::Image
* Resourcer::bitmapSection(const Gosu::Bitmap
& src
,
88 unsigned x
, unsigned y
, unsigned w
, unsigned h
, bool tileable
)
90 return new Gosu::Image(window
->graphics(), src
, x
, y
, w
, h
, tileable
);
93 XMLDocRef
Resourcer::getXMLDoc(const std::string
& name
)
95 if (conf
->cache_enabled
) {
96 XMLMap::iterator entry
= xmls
.find(name
);
97 if (entry
!= xmls
.end())
101 XMLDocRef
result(getXMLDocFromDisk(name
));
106 // use RAII to ensure doc is freed
107 // boost::shared_ptr<void> alwaysFreeTheDoc(doc, xmlFreeDoc);
108 xmlDoc
* Resourcer::getXMLDocFromDisk(const std::string
& name
)
110 const std::string docStr
= getString(name
);
114 xmlParserCtxt
* ctxt
= xmlNewParserCtxt();
115 const std::string pathname
= path(name
);
116 ctxt
->vctxt
.userData
= (void*)&pathname
;
117 ctxt
->vctxt
.error
= xmlErrorCb
;
118 boost::shared_ptr
<void> ctxtDeleter(ctxt
, xmlFreeParserCtxt
);
120 xmlDoc
* doc
= xmlCtxtReadMemory(ctxt
, docStr
.c_str(),
121 (int)docStr
.size(), NULL
, NULL
,
126 Log::err(pathname
, "Could not parse file");
129 else if (!ctxt
->valid
) {
130 Log::err(pathname
, "XML document does not follow DTD");
138 * We use Gosu::Sample for music because Gosu::Song's SDL implementation
139 * doesn't support loading from a memory buffer at the moment.
141 SampleRef
Resourcer::getSample(const std::string
& name
)
143 if (conf
->cache_enabled
) {
144 SampleRefMap::iterator entry
= samples
.find(name
);
145 if (entry
!= samples
.end())
146 return entry
->second
;
149 BufferPtr
buffer(read(name
));
152 SampleRef
result(new Gosu::Sample(buffer
->frontReader()));
153 samples
[name
] = result
;
157 std::string
Resourcer::getString(const std::string
& name
)
159 StringMap::iterator entry
= strings
.find(name
);
160 if (entry
!= strings
.end())
161 return entry
->second
;
163 std::string result
= getStringFromDisk(name
);
165 strings
[name
] = result
;
169 std::string
Resourcer::getStringFromDisk(const std::string
& name
)
171 struct zip_stat stat
;
177 if (zip_stat(z
, name
.c_str(), 0x0, &stat
)) {
178 Log::err(path(name
), "file missing");
182 size
= (int)stat
.size
;
183 buf
= new char[size
+ 1];
186 zf
= zip_fopen(z
, name
.c_str(), 0x0);
189 std::string("opening : ") + zip_strerror(z
));
193 if (zip_fread(zf
, buf
, size
) != size
) {
194 Log::err(path(name
), "reading didn't complete");
206 Gosu::Buffer
* Resourcer::read(const std::string
& name
)
208 struct zip_stat stat
;
212 if (zip_stat(z
, name
.c_str(), 0x0, &stat
)) {
213 Log::err(path(name
), "file missing");
217 size
= (int)stat
.size
;
219 if (!(zf
= zip_fopen(z
, name
.c_str(), 0x0))) {
221 std::string("opening : ") + zip_strerror(z
));
225 Gosu::Buffer
* buffer
= new Gosu::Buffer
;
226 buffer
->resize(size
);
227 if (zip_fread(zf
, buffer
->data(), size
) != size
) {
228 Log::err(path(name
), "reading didn't complete");
238 std::string
Resourcer::path(const std::string
& entry_name
) const
240 return conf
->world
+ "/" + entry_name
;