blob: dcd4ca8b093c7ba41482dc796a973455ec89f0c0 [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"
Dees_Troy51a0e822012-09-05 15:24:24 -040017#include "../minuitwrp/minui.h"
Ethan Yonker63e414f2015-02-06 15:44:39 -060018#include "gui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040019}
20
21#include "rapidxml.hpp"
22#include "objects.hpp"
23
24#define TMP_RESOURCE_NAME "/tmp/extract.bin"
25
26Resource::Resource(xml_node<>* node, ZipArchive* pZip)
27{
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
Ethan Yonker63e414f2015-02-06 15:44:39 -060057void Resource::LoadImage(ZipArchive* pZip, std::string file, gr_surface* source)
58{
59 if (ExtractResource(pZip, "images", file, ".png", TMP_RESOURCE_NAME) == 0)
60 {
61 res_create_surface(TMP_RESOURCE_NAME, source);
62 unlink(TMP_RESOURCE_NAME);
63 }
64 else if (ExtractResource(pZip, "images", file, "", TMP_RESOURCE_NAME) == 0)
65 {
66 // JPG includes the .jpg extension in the filename so extension should be blank
67 res_create_surface(TMP_RESOURCE_NAME, source);
68 unlink(TMP_RESOURCE_NAME);
69 }
70 else if (!pZip)
71 {
72 // File name in xml may have included .png so try without adding .png
73 res_create_surface(file.c_str(), source);
74 }
75}
76
77void Resource::CheckAndScaleImage(gr_surface source, gr_surface* destination, int retain_aspect)
78{
79 if (!source) {
80 *destination = NULL;
81 return;
82 }
83 if (get_scale_w() != 0 && get_scale_h() != 0) {
84 float scale_w = get_scale_w(), scale_h = get_scale_h();
85 if (retain_aspect) {
86 if (scale_w < scale_h)
87 scale_h = scale_w;
88 else
89 scale_w = scale_h;
90 }
91 if (res_scale_surface(source, destination, scale_w, scale_h)) {
92 LOGINFO("Error scaling image, using regular size.\n");
93 *destination = source;
94 }
95 } else {
96 *destination = source;
97 }
98}
99
Dees_Troy51a0e822012-09-05 15:24:24 -0400100FontResource::FontResource(xml_node<>* node, ZipArchive* pZip)
101 : Resource(node, pZip)
102{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200103 std::string file;
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200104 xml_attribute<>* attr;
Dees_Troy51a0e822012-09-05 15:24:24 -0400105
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200106 mFont = NULL;
107 if (!node)
108 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400109
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200110 attr = node->first_attribute("filename");
111 if (!attr)
112 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400113
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200114 file = attr->value();
115
116#ifndef TW_DISABLE_TTF
117 if(file.size() >= 4 && file.compare(file.size()-4, 4, ".ttf") == 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200118 {
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200119 m_type = TYPE_TTF;
120
121 attr = node->first_attribute("size");
122 if(!attr)
123 return;
124
Ethan Yonker63e414f2015-02-06 15:44:39 -0600125 int size = scale_theme_min(atoi(attr->value()));
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200126 int dpi = 300;
127
128 attr = node->first_attribute("dpi");
129 if(attr)
130 dpi = atoi(attr->value());
131
132 if (ExtractResource(pZip, "fonts", file, "", TMP_RESOURCE_NAME) == 0)
133 {
134 mFont = gr_ttf_loadFont(TMP_RESOURCE_NAME, size, dpi);
135 unlink(TMP_RESOURCE_NAME);
136 }
137 else
138 {
Dees Troy3454ade2015-01-20 19:21:04 +0000139 file = std::string(TWRES "fonts/") + file;
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200140 mFont = gr_ttf_loadFont(file.c_str(), size, dpi);
141 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200142 }
143 else
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200144#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200145 {
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200146 m_type = TYPE_TWRP;
147
148 if(file.size() >= 4 && file.compare(file.size()-4, 4, ".ttf") == 0)
149 {
150 attr = node->first_attribute("fallback");
151 if (!attr)
152 return;
153
154 file = attr->value();
155 }
156
157 if (ExtractResource(pZip, "fonts", file, ".dat", TMP_RESOURCE_NAME) == 0)
158 {
159 mFont = gr_loadFont(TMP_RESOURCE_NAME);
160 unlink(TMP_RESOURCE_NAME);
161 }
162 else
163 {
164 mFont = gr_loadFont(file.c_str());
165 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200166 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400167}
168
169FontResource::~FontResource()
170{
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200171 if(mFont)
172 {
173#ifndef TW_DISABLE_TTF
174 if(m_type == TYPE_TTF)
175 gr_ttf_freeFont(mFont);
176 else
177#endif
178 gr_freeFont(mFont);
179 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400180}
181
Ethan Yonker63e414f2015-02-06 15:44:39 -0600182ImageResource::ImageResource(xml_node<>* node, ZipArchive* pZip, int retain_aspect)
Dees_Troy51a0e822012-09-05 15:24:24 -0400183 : Resource(node, pZip)
184{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200185 std::string file;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600186 gr_surface temp_surface = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400187
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200188 mSurface = NULL;
Ethan Yonker619a7212014-12-03 16:47:37 -0600189 if (!node) {
190 LOGERR("ImageResource node is NULL\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200191 return;
Ethan Yonker619a7212014-12-03 16:47:37 -0600192 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400193
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200194 if (node->first_attribute("filename"))
195 file = node->first_attribute("filename")->value();
Ethan Yonker63e414f2015-02-06 15:44:39 -0600196 else {
197 LOGERR("No filename specified for image resource.\n");
198 return;
199 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400200
Ethan Yonker63e414f2015-02-06 15:44:39 -0600201 LoadImage(pZip, file, &temp_surface);
202 CheckAndScaleImage(temp_surface, &mSurface, retain_aspect);
Dees_Troy51a0e822012-09-05 15:24:24 -0400203}
204
205ImageResource::~ImageResource()
206{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200207 if (mSurface)
208 res_free_surface(mSurface);
Dees_Troy51a0e822012-09-05 15:24:24 -0400209}
210
Ethan Yonker63e414f2015-02-06 15:44:39 -0600211AnimationResource::AnimationResource(xml_node<>* node, ZipArchive* pZip, int retain_aspect)
Dees_Troy51a0e822012-09-05 15:24:24 -0400212 : Resource(node, pZip)
213{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200214 std::string file;
215 int fileNum = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400216
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200217 if (!node)
218 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400219
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200220 if (node->first_attribute("filename"))
221 file = node->first_attribute("filename")->value();
Ethan Yonker63e414f2015-02-06 15:44:39 -0600222 else {
223 LOGERR("No filename specified for image resource.\n");
224 return;
225 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400226
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200227 for (;;)
228 {
229 std::ostringstream fileName;
230 fileName << file << std::setfill ('0') << std::setw (3) << fileNum;
Dees_Troy51a0e822012-09-05 15:24:24 -0400231
Ethan Yonker63e414f2015-02-06 15:44:39 -0600232 gr_surface surface, temp_surface = NULL;
233 LoadImage(pZip, fileName.str(), &temp_surface);
234 CheckAndScaleImage(temp_surface, &surface, retain_aspect);
235 if (surface) {
236 mSurfaces.push_back(surface);
237 fileNum++;
238 } else
239 break; // Done loading animation images
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200240 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400241}
242
243AnimationResource::~AnimationResource()
244{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200245 std::vector<gr_surface>::iterator it;
Dees_Troy51a0e822012-09-05 15:24:24 -0400246
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200247 for (it = mSurfaces.begin(); it != mSurfaces.end(); ++it)
248 res_free_surface(*it);
249
250 mSurfaces.clear();
Dees_Troy51a0e822012-09-05 15:24:24 -0400251}
252
that74ac6062015-03-04 22:39:34 +0100253FontResource* ResourceManager::FindFont(const std::string& name) const
Dees_Troy51a0e822012-09-05 15:24:24 -0400254{
that74ac6062015-03-04 22:39:34 +0100255 for (std::vector<FontResource*>::const_iterator it = mFonts.begin(); it != mFonts.end(); ++it)
256 if (name == (*it)->GetName())
257 return *it;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200258 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400259}
260
that74ac6062015-03-04 22:39:34 +0100261ImageResource* ResourceManager::FindImage(const std::string& name) const
Dees_Troy51a0e822012-09-05 15:24:24 -0400262{
that74ac6062015-03-04 22:39:34 +0100263 for (std::vector<ImageResource*>::const_iterator it = mImages.begin(); it != mImages.end(); ++it)
264 if (name == (*it)->GetName())
265 return *it;
266 return NULL;
267}
268
269AnimationResource* ResourceManager::FindAnimation(const std::string& name) const
270{
271 for (std::vector<AnimationResource*>::const_iterator it = mAnimations.begin(); it != mAnimations.end(); ++it)
272 if (name == (*it)->GetName())
273 return *it;
274 return NULL;
275}
276
thatb2e8f672015-03-05 20:25:39 +0100277std::string ResourceManager::FindString(const std::string& name) const
278{
279 std::map<std::string, std::string>::const_iterator it = mStrings.find(name);
280 if (it != mStrings.end())
281 return it->second;
282 return "[" + name + ("]");
283}
284
that74ac6062015-03-04 22:39:34 +0100285ResourceManager::ResourceManager()
286{
Ethan Yonker780cd392014-07-21 15:24:39 -0500287}
288
289void ResourceManager::LoadResources(xml_node<>* resList, ZipArchive* pZip)
290{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200291 if (!resList)
292 return;
that0f425062015-03-04 23:05:00 +0100293
294 for (xml_node<>* child = resList->first_node(); child; child = child->next_sibling())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200295 {
that0f425062015-03-04 23:05:00 +0100296 std::string type = child->name();
297 if (type == "resource") {
298 // legacy format : <resource type="...">
299 xml_attribute<>* attr = child->first_attribute("type");
300 type = attr ? attr->value() : "*unspecified*";
301 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400302
that74ac6062015-03-04 22:39:34 +0100303 bool error = false;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200304 if (type == "font")
305 {
that74ac6062015-03-04 22:39:34 +0100306 FontResource* res = new FontResource(child, pZip);
307 if (res->GetResource())
308 mFonts.push_back(res);
309 else {
310 error = true;
311 delete res;
312 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200313 }
314 else if (type == "image")
315 {
Ethan Yonker63e414f2015-02-06 15:44:39 -0600316 int retain = 0;
317 xml_attribute<>* retain_aspect_ratio = child->first_attribute("retainaspect");
318 if (retain_aspect_ratio)
319 retain = 1; // the value does not matter, if retainaspect is present, we assume that we want to retain it
that74ac6062015-03-04 22:39:34 +0100320 ImageResource* res = new ImageResource(child, pZip, retain);
321 if (res->GetResource())
322 mImages.push_back(res);
323 else {
324 error = true;
325 delete res;
326 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200327 }
328 else if (type == "animation")
329 {
Ethan Yonker63e414f2015-02-06 15:44:39 -0600330 int retain = 0;
331 xml_attribute<>* retain_aspect_ratio = child->first_attribute("retainaspect");
332 if (retain_aspect_ratio)
333 retain = 1; // the value does not matter, if retainaspect is present, we assume that we want to retain it
that74ac6062015-03-04 22:39:34 +0100334 AnimationResource* res = new AnimationResource(child, pZip, retain);
335 if (res->GetResourceCount())
336 mAnimations.push_back(res);
337 else {
338 error = true;
339 delete res;
340 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200341 }
thatb2e8f672015-03-05 20:25:39 +0100342 else if (type == "string")
343 {
344 if (xml_attribute<>* attr = child->first_attribute("name"))
345 mStrings[attr->value()] = child->value();
346 else
347 error = true;
348 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200349 else
350 {
351 LOGERR("Resource type (%s) not supported.\n", type.c_str());
that74ac6062015-03-04 22:39:34 +0100352 error = true;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200353 }
thatf6ed8fc2015-02-14 20:23:16 +0100354
that74ac6062015-03-04 22:39:34 +0100355 if (error)
thatf74ac872015-01-18 12:00:02 +0100356 {
357 std::string res_name;
358 if (child->first_attribute("name"))
359 res_name = child->first_attribute("name")->value();
360 if (res_name.empty() && child->first_attribute("filename"))
361 res_name = child->first_attribute("filename")->value();
362
363 if (!res_name.empty()) {
364 LOGERR("Resource (%s)-(%s) failed to load\n", type.c_str(), res_name.c_str());
365 } else
366 LOGERR("Resource type (%s) failed to load\n", type.c_str());
thatf74ac872015-01-18 12:00:02 +0100367 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200368 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400369}
370
371ResourceManager::~ResourceManager()
372{
that74ac6062015-03-04 22:39:34 +0100373 for (std::vector<FontResource*>::iterator it = mFonts.begin(); it != mFonts.end(); ++it)
374 delete *it;
Dees_Troy51a0e822012-09-05 15:24:24 -0400375
that74ac6062015-03-04 22:39:34 +0100376 for (std::vector<ImageResource*>::iterator it = mImages.begin(); it != mImages.end(); ++it)
377 delete *it;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200378
that74ac6062015-03-04 22:39:34 +0100379 for (std::vector<AnimationResource*>::iterator it = mAnimations.begin(); it != mAnimations.end(); ++it)
380 delete *it;
Dees_Troy51a0e822012-09-05 15:24:24 -0400381}