blob: 9c97dad1899844b423148d2fa9dcd8da5818c78d [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001// resource.cpp - Source to manage GUI resources
2
3#include <stdarg.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
Dees_Troy51a0e822012-09-05 15:24:24 -04007#include <unistd.h>
Dees_Troy51a0e822012-09-05 15:24:24 -04008
9#include <string>
10#include <sstream>
11#include <iostream>
12#include <iomanip>
13
thatb2e8f672015-03-05 20:25:39 +010014#include "../minzip/Zip.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040015extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000016#include "../twcommon.h"
Ethan Yonker63e414f2015-02-06 15:44:39 -060017#include "gui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040018}
Ethan Yonkerfbb43532015-12-28 21:54:50 +010019#include "../minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040020
21#include "rapidxml.hpp"
22#include "objects.hpp"
23
24#define TMP_RESOURCE_NAME "/tmp/extract.bin"
25
Ethan Yonkerd0514ba2015-10-22 14:17:47 -050026Resource::Resource(xml_node<>* node, ZipArchive* pZip __unused)
Dees_Troy51a0e822012-09-05 15:24:24 -040027{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020028 if (node && node->first_attribute("name"))
29 mName = node->first_attribute("name")->value();
Dees_Troy51a0e822012-09-05 15:24:24 -040030}
31
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020032int Resource::ExtractResource(ZipArchive* pZip, std::string folderName, std::string fileName, std::string fileExtn, std::string destFile)
Dees_Troy51a0e822012-09-05 15:24:24 -040033{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020034 if (!pZip)
35 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040036
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020037 std::string src = folderName + "/" + fileName + fileExtn;
Dees_Troy51a0e822012-09-05 15:24:24 -040038
39 const ZipEntry* binary = mzFindZipEntry(pZip, src.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020040 if (binary == NULL) {
41 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040042 }
43
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020044 unlink(destFile.c_str());
45 int fd = creat(destFile.c_str(), 0666);
46 if (fd < 0)
47 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040048
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020049 int ret = 0;
50 if (!mzExtractZipEntryToFile(pZip, binary, fd))
51 ret = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040052
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020053 close(fd);
54 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -040055}
56
thatb240f4a2016-03-14 01:21:38 +010057void Resource::LoadImage(ZipArchive* pZip, std::string file, gr_surface* surface)
Ethan Yonker63e414f2015-02-06 15:44:39 -060058{
thatb240f4a2016-03-14 01:21:38 +010059 int rc = 0;
Ethan Yonker63e414f2015-02-06 15:44:39 -060060 if (ExtractResource(pZip, "images", file, ".png", TMP_RESOURCE_NAME) == 0)
61 {
thatb240f4a2016-03-14 01:21:38 +010062 rc = res_create_surface(TMP_RESOURCE_NAME, surface);
Ethan Yonker63e414f2015-02-06 15:44:39 -060063 unlink(TMP_RESOURCE_NAME);
64 }
65 else if (ExtractResource(pZip, "images", file, "", TMP_RESOURCE_NAME) == 0)
66 {
67 // JPG includes the .jpg extension in the filename so extension should be blank
thatb240f4a2016-03-14 01:21:38 +010068 rc = res_create_surface(TMP_RESOURCE_NAME, surface);
Ethan Yonker63e414f2015-02-06 15:44:39 -060069 unlink(TMP_RESOURCE_NAME);
70 }
71 else if (!pZip)
72 {
73 // File name in xml may have included .png so try without adding .png
thatb240f4a2016-03-14 01:21:38 +010074 rc = res_create_surface(file.c_str(), surface);
Ethan Yonker63e414f2015-02-06 15:44:39 -060075 }
thatb240f4a2016-03-14 01:21:38 +010076 if (rc != 0)
77 LOGINFO("Failed to load image from %s%s, error %d\n", file.c_str(), pZip ? " (zip)" : "", rc);
Ethan Yonker63e414f2015-02-06 15:44:39 -060078}
79
80void Resource::CheckAndScaleImage(gr_surface source, gr_surface* destination, int retain_aspect)
81{
82 if (!source) {
83 *destination = NULL;
84 return;
85 }
86 if (get_scale_w() != 0 && get_scale_h() != 0) {
87 float scale_w = get_scale_w(), scale_h = get_scale_h();
88 if (retain_aspect) {
89 if (scale_w < scale_h)
90 scale_h = scale_w;
91 else
92 scale_w = scale_h;
93 }
94 if (res_scale_surface(source, destination, scale_w, scale_h)) {
95 LOGINFO("Error scaling image, using regular size.\n");
96 *destination = source;
97 }
98 } else {
99 *destination = source;
100 }
101}
102
Dees_Troy51a0e822012-09-05 15:24:24 -0400103FontResource::FontResource(xml_node<>* node, ZipArchive* pZip)
104 : Resource(node, pZip)
105{
Ethan Yonker74db1572015-10-28 12:44:49 -0500106 origFontSize = 0;
107 origFont = NULL;
108 LoadFont(node, pZip);
109}
110
111void FontResource::LoadFont(xml_node<>* node, ZipArchive* pZip)
112{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200113 std::string file;
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200114 xml_attribute<>* attr;
Dees_Troy51a0e822012-09-05 15:24:24 -0400115
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200116 mFont = NULL;
117 if (!node)
118 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400119
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200120 attr = node->first_attribute("filename");
121 if (!attr)
122 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400123
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200124 file = attr->value();
125
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200126 if(file.size() >= 4 && file.compare(file.size()-4, 4, ".ttf") == 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200127 {
Ethan Yonker74db1572015-10-28 12:44:49 -0500128 int font_size = 0;
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200129
Ethan Yonker74db1572015-10-28 12:44:49 -0500130 if (origFontSize != 0) {
131 attr = node->first_attribute("scale");
132 if (attr == NULL)
133 return;
134 font_size = origFontSize * atoi(attr->value()) / 100;
135 } else {
136 attr = node->first_attribute("size");
137 if (attr == NULL)
138 return;
139 font_size = scale_theme_min(atoi(attr->value()));
140 origFontSize = font_size;
141 }
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200142
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200143 int dpi = 300;
144
145 attr = node->first_attribute("dpi");
146 if(attr)
147 dpi = atoi(attr->value());
148
thatb240f4a2016-03-14 01:21:38 +0100149 // we can't use TMP_RESOURCE_NAME here because the ttf subsystem is caching the name and scaling needs to reload the font
150 std::string tmpname = "/tmp/" + file;
151 if (ExtractResource(pZip, "fonts", file, "", tmpname) == 0)
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200152 {
thatb240f4a2016-03-14 01:21:38 +0100153 mFont = gr_ttf_loadFont(tmpname.c_str(), font_size, dpi);
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200154 }
155 else
156 {
Dees Troy3454ade2015-01-20 19:21:04 +0000157 file = std::string(TWRES "fonts/") + file;
Ethan Yonker74db1572015-10-28 12:44:49 -0500158 mFont = gr_ttf_loadFont(file.c_str(), font_size, dpi);
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200159 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200160 }
161 else
162 {
Ethan Yonker88037f42015-10-04 22:09:08 -0500163 LOGERR("Non-TTF fonts are no longer supported.\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200164 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400165}
166
Ethan Yonker74db1572015-10-28 12:44:49 -0500167void FontResource::DeleteFont() {
168 if(mFont)
169 gr_ttf_freeFont(mFont);
170 mFont = NULL;
171 if(origFont)
172 gr_ttf_freeFont(origFont);
173 origFont = NULL;
174}
175
176void FontResource::Override(xml_node<>* node, ZipArchive* pZip) {
177 if (!origFont) {
178 origFont = mFont;
179 } else if (mFont) {
180 gr_ttf_freeFont(mFont);
181 mFont = NULL;
182 }
183 LoadFont(node, pZip);
184}
185
Dees_Troy51a0e822012-09-05 15:24:24 -0400186FontResource::~FontResource()
187{
Ethan Yonker74db1572015-10-28 12:44:49 -0500188 DeleteFont();
Dees_Troy51a0e822012-09-05 15:24:24 -0400189}
190
that5267a212015-05-06 23:45:57 +0200191ImageResource::ImageResource(xml_node<>* node, ZipArchive* pZip)
Dees_Troy51a0e822012-09-05 15:24:24 -0400192 : Resource(node, pZip)
193{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200194 std::string file;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600195 gr_surface temp_surface = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400196
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200197 mSurface = NULL;
Ethan Yonker619a7212014-12-03 16:47:37 -0600198 if (!node) {
199 LOGERR("ImageResource node is NULL\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200200 return;
Ethan Yonker619a7212014-12-03 16:47:37 -0600201 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400202
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200203 if (node->first_attribute("filename"))
204 file = node->first_attribute("filename")->value();
Ethan Yonker63e414f2015-02-06 15:44:39 -0600205 else {
206 LOGERR("No filename specified for image resource.\n");
207 return;
208 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400209
that5267a212015-05-06 23:45:57 +0200210 bool retain_aspect = (node->first_attribute("retainaspect") != NULL);
211 // the value does not matter, if retainaspect is present, we assume that we want to retain it
Ethan Yonker63e414f2015-02-06 15:44:39 -0600212 LoadImage(pZip, file, &temp_surface);
213 CheckAndScaleImage(temp_surface, &mSurface, retain_aspect);
Dees_Troy51a0e822012-09-05 15:24:24 -0400214}
215
216ImageResource::~ImageResource()
217{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200218 if (mSurface)
219 res_free_surface(mSurface);
Dees_Troy51a0e822012-09-05 15:24:24 -0400220}
221
that5267a212015-05-06 23:45:57 +0200222AnimationResource::AnimationResource(xml_node<>* node, ZipArchive* pZip)
Dees_Troy51a0e822012-09-05 15:24:24 -0400223 : Resource(node, pZip)
224{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200225 std::string file;
226 int fileNum = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400227
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200228 if (!node)
229 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400230
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200231 if (node->first_attribute("filename"))
232 file = node->first_attribute("filename")->value();
Ethan Yonker63e414f2015-02-06 15:44:39 -0600233 else {
234 LOGERR("No filename specified for image resource.\n");
235 return;
236 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400237
that5267a212015-05-06 23:45:57 +0200238 bool retain_aspect = (node->first_attribute("retainaspect") != NULL);
239 // the value does not matter, if retainaspect is present, we assume that we want to retain it
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200240 for (;;)
241 {
242 std::ostringstream fileName;
243 fileName << file << std::setfill ('0') << std::setw (3) << fileNum;
Dees_Troy51a0e822012-09-05 15:24:24 -0400244
Ethan Yonker63e414f2015-02-06 15:44:39 -0600245 gr_surface surface, temp_surface = NULL;
246 LoadImage(pZip, fileName.str(), &temp_surface);
247 CheckAndScaleImage(temp_surface, &surface, retain_aspect);
248 if (surface) {
249 mSurfaces.push_back(surface);
250 fileNum++;
251 } else
252 break; // Done loading animation images
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200253 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400254}
255
256AnimationResource::~AnimationResource()
257{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200258 std::vector<gr_surface>::iterator it;
Dees_Troy51a0e822012-09-05 15:24:24 -0400259
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200260 for (it = mSurfaces.begin(); it != mSurfaces.end(); ++it)
261 res_free_surface(*it);
262
263 mSurfaces.clear();
Dees_Troy51a0e822012-09-05 15:24:24 -0400264}
265
that74ac6062015-03-04 22:39:34 +0100266FontResource* ResourceManager::FindFont(const std::string& name) const
Dees_Troy51a0e822012-09-05 15:24:24 -0400267{
that74ac6062015-03-04 22:39:34 +0100268 for (std::vector<FontResource*>::const_iterator it = mFonts.begin(); it != mFonts.end(); ++it)
269 if (name == (*it)->GetName())
270 return *it;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200271 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400272}
273
that74ac6062015-03-04 22:39:34 +0100274ImageResource* ResourceManager::FindImage(const std::string& name) const
Dees_Troy51a0e822012-09-05 15:24:24 -0400275{
that74ac6062015-03-04 22:39:34 +0100276 for (std::vector<ImageResource*>::const_iterator it = mImages.begin(); it != mImages.end(); ++it)
277 if (name == (*it)->GetName())
278 return *it;
279 return NULL;
280}
281
282AnimationResource* ResourceManager::FindAnimation(const std::string& name) const
283{
284 for (std::vector<AnimationResource*>::const_iterator it = mAnimations.begin(); it != mAnimations.end(); ++it)
285 if (name == (*it)->GetName())
286 return *it;
287 return NULL;
288}
289
thatb2e8f672015-03-05 20:25:39 +0100290std::string ResourceManager::FindString(const std::string& name) const
291{
Ethan Yonker74db1572015-10-28 12:44:49 -0500292 if (this != NULL) {
293 std::map<std::string, string_resource_struct>::const_iterator it = mStrings.find(name);
294 if (it != mStrings.end())
295 return it->second.value;
296 LOGERR("String resource '%s' not found. No default value.\n", name.c_str());
297 PageManager::AddStringResource("NO DEFAULT", name, "[" + name + ("]"));
298 } else {
299 LOGINFO("String resources not loaded when looking for '%s'. No default value.\n", name.c_str());
300 }
thatb2e8f672015-03-05 20:25:39 +0100301 return "[" + name + ("]");
302}
303
Ethan Yonker74db1572015-10-28 12:44:49 -0500304std::string ResourceManager::FindString(const std::string& name, const std::string& default_string) const
305{
306 if (this != NULL) {
307 std::map<std::string, string_resource_struct>::const_iterator it = mStrings.find(name);
308 if (it != mStrings.end())
309 return it->second.value;
310 LOGERR("String resource '%s' not found. Using default value.\n", name.c_str());
311 PageManager::AddStringResource("DEFAULT", name, default_string);
312 } else {
313 LOGINFO("String resources not loaded when looking for '%s'. Using default value.\n", name.c_str());
314 }
315 return default_string;
316}
317
318void ResourceManager::DumpStrings() const
319{
320 if (this == NULL) {
321 gui_print("No string resources\n");
322 return;
323 }
324 std::map<std::string, string_resource_struct>::const_iterator it;
325 gui_print("Dumping all strings:\n");
326 for (it = mStrings.begin(); it != mStrings.end(); it++)
327 gui_print("source: %s: '%s' = '%s'\n", it->second.source.c_str(), it->first.c_str(), it->second.value.c_str());
328 gui_print("Done dumping strings\n");
329}
330
that74ac6062015-03-04 22:39:34 +0100331ResourceManager::ResourceManager()
332{
Ethan Yonker780cd392014-07-21 15:24:39 -0500333}
334
Ethan Yonker74db1572015-10-28 12:44:49 -0500335void ResourceManager::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
336{
337 string_resource_struct res;
338 res.source = resource_source;
339 res.value = value;
340 mStrings[resource_name] = res;
341}
342
343void ResourceManager::LoadResources(xml_node<>* resList, ZipArchive* pZip, std::string resource_source)
Ethan Yonker780cd392014-07-21 15:24:39 -0500344{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200345 if (!resList)
346 return;
that0f425062015-03-04 23:05:00 +0100347
348 for (xml_node<>* child = resList->first_node(); child; child = child->next_sibling())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200349 {
that0f425062015-03-04 23:05:00 +0100350 std::string type = child->name();
351 if (type == "resource") {
352 // legacy format : <resource type="...">
353 xml_attribute<>* attr = child->first_attribute("type");
354 type = attr ? attr->value() : "*unspecified*";
355 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400356
that74ac6062015-03-04 22:39:34 +0100357 bool error = false;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200358 if (type == "font")
359 {
that74ac6062015-03-04 22:39:34 +0100360 FontResource* res = new FontResource(child, pZip);
361 if (res->GetResource())
362 mFonts.push_back(res);
363 else {
364 error = true;
365 delete res;
366 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200367 }
Ethan Yonker74db1572015-10-28 12:44:49 -0500368 else if (type == "fontoverride")
369 {
370 if (mFonts.size() != 0 && child && child->first_attribute("name")) {
371 string FontName = child->first_attribute("name")->value();
372 size_t font_count = mFonts.size(), i;
373 bool found = false;
374
375 for (i = 0; i < font_count; i++) {
376 if (mFonts[i]->GetName() == FontName) {
377 mFonts[i]->Override(child, pZip);
378 found = true;
379 break;
380 }
381 }
382 if (!found) {
383 LOGERR("Unable to locate font '%s' for override.\n", FontName.c_str());
384 }
385 } else if (mFonts.size() != 0)
386 LOGERR("Unable to locate font name for type fontoverride.\n");
387 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200388 else if (type == "image")
389 {
that5267a212015-05-06 23:45:57 +0200390 ImageResource* res = new ImageResource(child, pZip);
that74ac6062015-03-04 22:39:34 +0100391 if (res->GetResource())
392 mImages.push_back(res);
393 else {
394 error = true;
395 delete res;
396 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200397 }
398 else if (type == "animation")
399 {
that5267a212015-05-06 23:45:57 +0200400 AnimationResource* res = new AnimationResource(child, pZip);
that74ac6062015-03-04 22:39:34 +0100401 if (res->GetResourceCount())
402 mAnimations.push_back(res);
403 else {
404 error = true;
405 delete res;
406 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200407 }
thatb2e8f672015-03-05 20:25:39 +0100408 else if (type == "string")
409 {
Ethan Yonker74db1572015-10-28 12:44:49 -0500410 if (xml_attribute<>* attr = child->first_attribute("name")) {
411 string_resource_struct res;
412 res.source = resource_source;
413 res.value = child->value();
414 mStrings[attr->value()] = res;
415 } else
thatb2e8f672015-03-05 20:25:39 +0100416 error = true;
417 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200418 else
419 {
420 LOGERR("Resource type (%s) not supported.\n", type.c_str());
that74ac6062015-03-04 22:39:34 +0100421 error = true;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200422 }
thatf6ed8fc2015-02-14 20:23:16 +0100423
that74ac6062015-03-04 22:39:34 +0100424 if (error)
thatf74ac872015-01-18 12:00:02 +0100425 {
426 std::string res_name;
427 if (child->first_attribute("name"))
428 res_name = child->first_attribute("name")->value();
429 if (res_name.empty() && child->first_attribute("filename"))
430 res_name = child->first_attribute("filename")->value();
431
432 if (!res_name.empty()) {
433 LOGERR("Resource (%s)-(%s) failed to load\n", type.c_str(), res_name.c_str());
434 } else
435 LOGERR("Resource type (%s) failed to load\n", type.c_str());
thatf74ac872015-01-18 12:00:02 +0100436 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200437 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400438}
439
440ResourceManager::~ResourceManager()
441{
that74ac6062015-03-04 22:39:34 +0100442 for (std::vector<FontResource*>::iterator it = mFonts.begin(); it != mFonts.end(); ++it)
443 delete *it;
Dees_Troy51a0e822012-09-05 15:24:24 -0400444
that74ac6062015-03-04 22:39:34 +0100445 for (std::vector<ImageResource*>::iterator it = mImages.begin(); it != mImages.end(); ++it)
446 delete *it;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200447
that74ac6062015-03-04 22:39:34 +0100448 for (std::vector<AnimationResource*>::iterator it = mAnimations.begin(); it != mAnimations.end(); ++it)
449 delete *it;
Dees_Troy51a0e822012-09-05 15:24:24 -0400450}