1 /* 2014, Copyright © Intel Coporation, license APACHE-2.0, see LICENSE file */
2 // Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3 // Use of this source code is governed by a apache 2.0 license that can be
4 // found in the LICENSE file.
6 #include "wgt/step/step_generate_xml.h"
8 #include <boost/filesystem/path.hpp>
9 #include <boost/system/error_code.hpp>
11 #include <common/utils/file_util.h>
12 #include <common/utils/glist_range.h>
14 #include <libxml/parser.h>
15 #include <libxml/xmlreader.h>
16 #include <pkgmgr-info.h>
17 #include <pkgmgr_parser.h>
18 #include <tzplatform_config.h>
26 namespace bs = boost::system;
27 namespace bf = boost::filesystem;
31 void WriteUIApplicationAttributes(
32 xmlTextWriterPtr writer, application_x *app) {
33 xmlTextWriterWriteAttribute(writer, BAD_CAST "taskmanage",
36 xmlTextWriterWriteAttribute(writer, BAD_CAST "nodisplay",
37 BAD_CAST app->nodisplay);
39 xmlTextWriterWriteAttribute(writer, BAD_CAST "multiple",
40 BAD_CAST app->multiple);
41 if (app->launch_mode && strlen(app->launch_mode))
42 xmlTextWriterWriteAttribute(writer, BAD_CAST "launch_mode",
43 BAD_CAST app->launch_mode);
44 if (app->ui_gadget && strlen(app->ui_gadget))
45 xmlTextWriterWriteAttribute(writer, BAD_CAST "ui-gadget",
46 BAD_CAST app->ui_gadget);
47 if (app->submode && strlen(app->submode))
48 xmlTextWriterWriteAttribute(writer, BAD_CAST "submode",
49 BAD_CAST app->submode);
50 if (app->submode_mainid && strlen(app->submode_mainid))
51 xmlTextWriterWriteAttribute(writer, BAD_CAST "submode-mainid",
52 BAD_CAST app->submode_mainid);
53 if (app->indicatordisplay && strlen(app->indicatordisplay))
54 xmlTextWriterWriteAttribute(writer, BAD_CAST "indicatordisplay",
55 BAD_CAST app->indicatordisplay);
56 if (app->portraitimg && strlen(app->portraitimg))
57 xmlTextWriterWriteAttribute(writer, BAD_CAST "portrait-effectimage",
58 BAD_CAST app->portraitimg);
59 if (app->landscapeimg && strlen(app->landscapeimg))
60 xmlTextWriterWriteAttribute(writer, BAD_CAST "landscape-effectimage",
61 BAD_CAST app->landscapeimg);
62 if (app->effectimage_type && strlen(app->effectimage_type))
63 xmlTextWriterWriteAttribute(writer, BAD_CAST "effectimage-type",
64 BAD_CAST app->effectimage_type);
65 if (app->hwacceleration && strlen(app->hwacceleration))
66 xmlTextWriterWriteAttribute(writer, BAD_CAST "hwacceleration",
67 BAD_CAST app->hwacceleration);
70 void WriteServiceApplicationAttributes(
71 xmlTextWriterPtr writer, application_x *app) {
72 xmlTextWriterWriteAttribute(writer, BAD_CAST "auto-restart",
73 BAD_CAST(app->autorestart ? app->autorestart : "false"));
74 xmlTextWriterWriteAttribute(writer, BAD_CAST "on-boot",
75 BAD_CAST(app->onboot ? app->onboot : "false"));
76 xmlTextWriterWriteAttribute(writer, BAD_CAST "taskmanage",
80 void WriteWidgetApplicationAttributes(
81 xmlTextWriterPtr writer, application_x *app) {
83 xmlTextWriterWriteAttribute(writer, BAD_CAST "nodisplay",
84 BAD_CAST app->nodisplay);
86 xmlTextWriterWriteAttribute(writer, BAD_CAST "multiple",
87 BAD_CAST app->multiple);
95 common_installer::Step::Status StepGenerateXml::GenerateApplicationCommonXml(
96 application_x* app, xmlTextWriterPtr writer, AppCompType type) {
97 xmlTextWriterWriteAttribute(writer, BAD_CAST "appid", BAD_CAST app->appid);
99 // binary is a symbolic link named <appid> and is located in <pkgid>/<appid>
100 bf::path exec_path = context_->pkg_path.get()
101 / bf::path("bin") / bf::path(app->appid);
102 xmlTextWriterWriteAttribute(writer, BAD_CAST "exec",
103 BAD_CAST exec_path.string().c_str());
105 xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST app->type);
107 xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST "capp");
109 if (app->process_pool && strlen(app->process_pool))
110 xmlTextWriterWriteAttribute(writer, BAD_CAST "process-pool",
111 BAD_CAST app->process_pool);
112 // app-specific attributes
114 case AppCompType::UIAPP:
115 WriteServiceApplicationAttributes(writer, app);
117 case AppCompType::SVCAPP:
118 WriteUIApplicationAttributes(writer, app);
120 case AppCompType::WIDGETAPP:
121 WriteWidgetApplicationAttributes(writer, app);
125 for (label_x* label : GListRange<label_x*>(app->label)) {
126 xmlTextWriterStartElement(writer, BAD_CAST "label");
127 if (label->lang && strcmp(DEFAULT_LOCALE, label->lang) != 0) {
128 xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang",
129 BAD_CAST label->lang);
131 xmlTextWriterWriteString(writer, BAD_CAST label->name);
132 xmlTextWriterEndElement(writer);
135 // icon is renamed to <appid.png>
137 icon_x* iconx = reinterpret_cast<icon_x*>(app->icon->data);
138 bf::path app_icon = context_->pkg_path.get();
139 // TODO(t.iwanek): type should not be used here
140 if (context_->pkg_type.get() == "wgt") {
141 app_icon /= "res/wgt";
143 app_icon /= "shared/res";
145 app_icon /= iconx->text;
146 bf::path icon = app->appid;
147 if (app_icon.has_extension())
148 icon += app_icon.extension();
150 icon += bf::path(".png");
152 if (bf::exists(app_icon)) {
153 xmlTextWriterWriteFormatElement(writer, BAD_CAST "icon",
154 "%s", BAD_CAST icon.c_str());
157 // Default icon setting is role of the platform
158 LOG(DEBUG) << "Icon was not found in package";
161 for (image_x* image : GListRange<image_x*>(app->image)) {
162 xmlTextWriterStartElement(writer, BAD_CAST "image");
163 xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
164 BAD_CAST image->name);
165 if (image->lang && strcmp(DEFAULT_LOCALE, image->lang) != 0) {
166 xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang",
168 BAD_CAST image->lang);
171 xmlTextWriterWriteAttribute(writer, BAD_CAST "section",
172 BAD_CAST image->section);
173 xmlTextWriterEndElement(writer);
176 for (appcontrol_x* appc : GListRange<appcontrol_x*>(app->appcontrol)) {
177 xmlTextWriterStartElement(writer, BAD_CAST "app-control");
179 if (appc->operation) {
180 xmlTextWriterStartElement(writer, BAD_CAST "operation");
181 xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
182 BAD_CAST appc->operation);
183 xmlTextWriterEndElement(writer);
187 xmlTextWriterStartElement(writer, BAD_CAST "uri");
188 xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
190 xmlTextWriterEndElement(writer);
194 xmlTextWriterStartElement(writer, BAD_CAST "mime");
195 xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
196 BAD_CAST appc->mime);
197 xmlTextWriterEndElement(writer);
200 xmlTextWriterEndElement(writer);
203 for (datacontrol_x* datacontrol :
204 GListRange<datacontrol_x*>(app->datacontrol)) {
205 xmlTextWriterStartElement(writer, BAD_CAST "datacontrol");
206 if (datacontrol->access) {
207 xmlTextWriterWriteAttribute(writer, BAD_CAST "access",
208 BAD_CAST datacontrol->access);
210 if (datacontrol->providerid) {
211 xmlTextWriterWriteAttribute(writer, BAD_CAST "providerid",
212 BAD_CAST datacontrol->providerid);
214 if (datacontrol->type) {
215 xmlTextWriterWriteAttribute(writer, BAD_CAST "type",
216 BAD_CAST datacontrol->type);
218 xmlTextWriterEndElement(writer);
221 for (metadata_x* meta : GListRange<metadata_x*>(app->metadata)) {
222 xmlTextWriterStartElement(writer, BAD_CAST "metadata");
223 xmlTextWriterWriteAttribute(writer, BAD_CAST "key",
226 xmlTextWriterWriteAttribute(writer, BAD_CAST "value",
227 BAD_CAST meta->value);
228 xmlTextWriterEndElement(writer);
231 for (const char* category : GListRange<char*>(app->category)) {
232 xmlTextWriterStartElement(writer, BAD_CAST "category");
233 xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST category);
234 xmlTextWriterEndElement(writer);
237 for (const char* background_category : GListRange<char*>(
238 app->background_category)) {
239 xmlTextWriterStartElement(writer, BAD_CAST "background-category");
240 xmlTextWriterWriteAttribute(writer, BAD_CAST "value",
241 BAD_CAST background_category);
242 xmlTextWriterEndElement(writer);
245 return Step::Status::OK;
248 common_installer::Step::Status StepGenerateXml::precheck() {
249 if (!context_->manifest_data.get()) {
250 LOG(ERROR) << "manifest_data attribute is empty";
251 return Step::Status::INVALID_VALUE;
253 if (context_->pkgid.get().empty()) {
254 LOG(ERROR) << "pkgid attribute is empty";
255 return Step::Status::PACKAGE_NOT_FOUND; }
257 if (!context_->manifest_data.get()->application) {
258 LOG(ERROR) << "No application in package";
259 return Step::Status::INVALID_VALUE;
261 // TODO(p.sikorski) check context_->uid.get()
263 return Step::Status::OK;
266 common_installer::Step::Status StepGenerateXml::process() {
267 bf::path xml_path = bf::path(getUserManifestPath(context_->uid.get()))
268 / bf::path(context_->pkgid.get());
270 context_->xml_path.set(xml_path.string());
272 bs::error_code error;
273 if (!bf::exists(xml_path.parent_path(), error)) {
274 if (!common_installer::CreateDir(xml_path.parent_path())) {
276 "Directory for manifest xml is missing and cannot be created";
277 return Status::MANIFEST_ERROR;
281 xmlTextWriterPtr writer;
283 writer = xmlNewTextWriterFilename(context_->xml_path.get().c_str(), 0);
285 LOG(ERROR) << "Failed to create new file";
286 return Step::Status::MANIFEST_ERROR;
289 xmlTextWriterStartDocument(writer, nullptr, nullptr, nullptr);
291 xmlTextWriterSetIndent(writer, 1);
293 // add manifest Element
294 xmlTextWriterStartElement(writer, BAD_CAST "manifest");
296 xmlTextWriterWriteAttribute(writer, BAD_CAST "xmlns",
297 BAD_CAST "http://tizen.org/ns/packages");
298 xmlTextWriterWriteAttribute(writer, BAD_CAST "package",
299 BAD_CAST context_->manifest_data.get()->package);
300 xmlTextWriterWriteAttribute(writer, BAD_CAST "type",
301 BAD_CAST context_->manifest_data.get()->type);
302 xmlTextWriterWriteAttribute(writer, BAD_CAST "version",
303 BAD_CAST context_->manifest_data.get()->version);
304 xmlTextWriterWriteAttribute(writer, BAD_CAST "api-version",
305 BAD_CAST context_->manifest_data.get()->api_version);
306 xmlTextWriterWriteAttribute(writer, BAD_CAST "nodisplay-setting",
307 BAD_CAST context_->manifest_data.get()->nodisplay_setting);
309 for (label_x* label :
310 GListRange<label_x*>(context_->manifest_data.get()->label)) {
311 xmlTextWriterStartElement(writer, BAD_CAST "label");
312 if (label->lang && strcmp(DEFAULT_LOCALE, label->lang) != 0) {
313 xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang",
314 BAD_CAST label->lang);
316 xmlTextWriterWriteString(writer, BAD_CAST label->name);
317 xmlTextWriterEndElement(writer);
320 for (author_x* author :
321 GListRange<author_x*>(context_->manifest_data.get()->author)) {
322 xmlTextWriterStartElement(writer, BAD_CAST "author");
323 if (author->email && strlen(author->email)) {
324 xmlTextWriterWriteAttribute(writer, BAD_CAST "email",
325 BAD_CAST author->email);
327 if (author->href && strlen(author->href)) {
328 xmlTextWriterWriteAttribute(writer, BAD_CAST "href",
329 BAD_CAST author->href);
331 xmlTextWriterWriteString(writer, BAD_CAST author->text);
332 xmlTextWriterEndElement(writer);
335 for (description_x* description :
336 GListRange<description_x*>(context_->manifest_data.get()->description)) {
337 xmlTextWriterStartElement(writer, BAD_CAST "description");
338 if (description->lang && strcmp(DEFAULT_LOCALE, description->lang) != 0) {
339 xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang",
340 BAD_CAST description->lang);
342 xmlTextWriterWriteString(writer, BAD_CAST description->text);
343 xmlTextWriterEndElement(writer);
347 for (application_x* app :
348 GListRange<application_x*>(context_->manifest_data.get()->application)) {
350 if (strcmp(app->component_type, "uiapp") == 0) {
351 type = AppCompType::UIAPP;
352 xmlTextWriterStartElement(writer, BAD_CAST "ui-application");
353 } else if (strcmp(app->component_type, "svcapp") == 0) {
354 type = AppCompType::SVCAPP;
355 xmlTextWriterStartElement(writer, BAD_CAST "service-application");
356 } else if (strcmp(app->component_type, "widgetapp") == 0) {
357 type = AppCompType::WIDGETAPP;
358 xmlTextWriterStartElement(writer, BAD_CAST "widget-application");
360 LOG(ERROR) << "Unknown application component_type";
361 xmlFreeTextWriter(writer);
362 return Status::ERROR;
364 GenerateApplicationCommonXml(app, writer, type);
365 xmlTextWriterEndElement(writer);
368 // add privilege element
369 if (context_->manifest_data.get()->privileges) {
370 xmlTextWriterStartElement(writer, BAD_CAST "privileges");
371 for (const char* priv :
372 GListRange<char*>(context_->manifest_data.get()->privileges)) {
373 xmlTextWriterWriteFormatElement(writer, BAD_CAST "privilege",
374 "%s", BAD_CAST priv);
376 xmlTextWriterEndElement(writer);
379 const auto& accounts =
380 context_->manifest_plugins_data.get().account_info.get().accounts();
381 if (!accounts.empty()) {
382 xmlTextWriterStartElement(writer, BAD_CAST "account");
384 for (auto& account : accounts) {
385 xmlTextWriterStartElement(writer, BAD_CAST "account-provider");
387 xmlTextWriterWriteAttribute(writer, BAD_CAST "appid",
388 BAD_CAST account.appid.c_str());
390 if (!account.providerid.empty())
391 xmlTextWriterWriteAttribute(writer, BAD_CAST "providerid",
392 BAD_CAST account.providerid.c_str());
394 if (account.multiple_account_support)
395 xmlTextWriterWriteAttribute(writer,
396 BAD_CAST "multiple-accounts-support",
398 for (auto& icon_pair : account.icon_paths) {
399 xmlTextWriterStartElement(writer, BAD_CAST "icon");
400 if (icon_pair.first == "AccountSmall")
401 xmlTextWriterWriteAttribute(writer, BAD_CAST "section",
402 BAD_CAST "account-small");
404 xmlTextWriterWriteAttribute(writer, BAD_CAST "section",
406 xmlTextWriterWriteString(writer, BAD_CAST icon_pair.second.c_str());
407 xmlTextWriterEndElement(writer);
410 for (auto& name_pair : account.names) {
411 xmlTextWriterStartElement(writer, BAD_CAST "label");
412 if (!name_pair.second.empty())
413 xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang",
414 BAD_CAST name_pair.second.c_str());
415 xmlTextWriterWriteString(writer, BAD_CAST name_pair.first.c_str());
416 xmlTextWriterEndElement(writer);
419 for (auto& capability : account.capabilities) {
420 xmlTextWriterWriteFormatElement(writer, BAD_CAST "capability",
421 "%s", BAD_CAST capability.c_str());
424 xmlTextWriterEndElement(writer);
426 xmlTextWriterEndElement(writer);
429 for (const char* profile :
430 GListRange<char*>(context_->manifest_data.get()->deviceprofile)) {
431 xmlTextWriterStartElement(writer, BAD_CAST "profile");
432 xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
434 xmlTextWriterEndElement(writer);
437 const auto& shortcuts =
438 context_->manifest_plugins_data.get().shortcut_info.get();
439 if (!shortcuts.empty()) {
440 xmlTextWriterStartElement(writer, BAD_CAST "shortcut-list");
441 for (auto& shortcut : shortcuts) {
442 xmlTextWriterStartElement(writer, BAD_CAST "shortcut");
443 if (!shortcut.app_id.empty())
444 xmlTextWriterWriteAttribute(writer, BAD_CAST "appid",
445 BAD_CAST shortcut.app_id.c_str());
446 if (!shortcut.app_id.empty())
447 xmlTextWriterWriteAttribute(writer, BAD_CAST "extra_data",
448 BAD_CAST shortcut.extra_data.c_str());
449 if (!shortcut.app_id.empty())
450 xmlTextWriterWriteAttribute(writer, BAD_CAST "extra_key",
451 BAD_CAST shortcut.extra_key.c_str());
452 if (!shortcut.icon.empty()) {
453 xmlTextWriterStartElement(writer, BAD_CAST "icon");
454 xmlTextWriterWriteString(writer, BAD_CAST shortcut.icon.c_str());
455 xmlTextWriterEndElement(writer);
457 for (auto& label : shortcut.labels) {
458 xmlTextWriterStartElement(writer, BAD_CAST "label");
459 if (!label.first.empty())
460 xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang",
461 BAD_CAST label.first.c_str());
462 xmlTextWriterWriteString(writer, BAD_CAST label.second.c_str());
463 xmlTextWriterEndElement(writer);
465 xmlTextWriterEndElement(writer);
467 xmlTextWriterEndElement(writer);
470 xmlTextWriterEndElement(writer);
472 xmlTextWriterEndDocument(writer);
473 xmlFreeTextWriter(writer);
475 if (pkgmgr_parser_check_manifest_validation(
476 context_->xml_path.get().c_str()) != 0) {
477 LOG(ERROR) << "Manifest is not valid";
478 return Step::Status::MANIFEST_ERROR;
481 LOG(DEBUG) << "Successfully create manifest xml "
482 << context_->xml_path.get();
486 common_installer::Step::Status StepGenerateXml::undo() {
487 bs::error_code error;
488 if (bf::exists(context_->xml_path.get()))
489 bf::remove_all(context_->xml_path.get(), error);
493 } // namespace pkgmgr