export.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. /*************************************************************************/
  2. /* export.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* http://www.godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
  9. /* */
  10. /* Permission is hereby granted, free of charge, to any person obtaining */
  11. /* a copy of this software and associated documentation files (the */
  12. /* "Software"), to deal in the Software without restriction, including */
  13. /* without limitation the rights to use, copy, modify, merge, publish, */
  14. /* distribute, sublicense, and/or sell copies of the Software, and to */
  15. /* permit persons to whom the Software is furnished to do so, subject to */
  16. /* the following conditions: */
  17. /* */
  18. /* The above copyright notice and this permission notice shall be */
  19. /* included in all copies or substantial portions of the Software. */
  20. /* */
  21. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  22. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  23. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  24. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  25. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  26. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  27. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  28. /*************************************************************************/
  29. #include "version.h"
  30. #include "export.h"
  31. #include "tools/editor/editor_settings.h"
  32. #include "tools/editor/editor_export.h"
  33. #include "tools/editor/editor_node.h"
  34. #include "io/zip_io.h"
  35. #include "io/marshalls.h"
  36. #include "io/resource_saver.h"
  37. #include "globals.h"
  38. #include "os/file_access.h"
  39. #include "os/os.h"
  40. #include "platform/osx/logo.h"
  41. #include "string.h"
  42. #if 0
  43. class EditorExportPlatformOSX : public EditorExportPlatform {
  44. GDCLASS( EditorExportPlatformOSX,EditorExportPlatform );
  45. String custom_release_package;
  46. String custom_debug_package;
  47. enum BitsMode {
  48. BITS_FAT,
  49. BITS_64,
  50. BITS_32
  51. };
  52. int version_code;
  53. String app_name;
  54. String info;
  55. String icon;
  56. String identifier;
  57. String short_version;
  58. String version;
  59. String signature;
  60. String copyright;
  61. BitsMode bits_mode;
  62. bool high_resolution;
  63. Ref<ImageTexture> logo;
  64. void _fix_plist(Vector<uint8_t>& plist, const String &p_binary);
  65. void _make_icon(const Image& p_icon,Vector<uint8_t>& data);
  66. protected:
  67. bool _set(const StringName& p_name, const Variant& p_value);
  68. bool _get(const StringName& p_name,Variant &r_ret) const;
  69. void _get_property_list( List<PropertyInfo> *p_list) const;
  70. public:
  71. virtual String get_name() const { return "Mac OSX"; }
  72. virtual ImageCompression get_image_compression() const { return IMAGE_COMPRESSION_BC; }
  73. virtual Ref<Texture> get_logo() const { return logo; }
  74. virtual bool poll_devices() { return false;}
  75. virtual int get_device_count() const { return 0; }
  76. virtual String get_device_name(int p_device) const { return String(); }
  77. virtual String get_device_info(int p_device) const { return String(); }
  78. virtual Error run(int p_device,int p_flags=0);
  79. virtual bool requires_password(bool p_debug) const { return false; }
  80. virtual String get_binary_extension() const { return "zip"; }
  81. virtual Error export_project(const String& p_path,bool p_debug,int p_flags=0);
  82. virtual bool can_export(String *r_error=NULL) const;
  83. EditorExportPlatformOSX();
  84. ~EditorExportPlatformOSX();
  85. };
  86. bool EditorExportPlatformOSX::_set(const StringName& p_name, const Variant& p_value) {
  87. String n=p_name;
  88. if (n=="custom_package/debug")
  89. custom_debug_package=p_value;
  90. else if (n=="custom_package/release")
  91. custom_release_package=p_value;
  92. else if (n=="application/name")
  93. app_name=p_value;
  94. else if (n=="application/info")
  95. info=p_value;
  96. else if (n=="application/icon")
  97. icon=p_value;
  98. else if (n=="application/identifier")
  99. identifier=p_value;
  100. else if (n=="application/signature")
  101. signature=p_value;
  102. else if (n=="application/short_version")
  103. short_version=p_value;
  104. else if (n=="application/version")
  105. version=p_value;
  106. else if (n=="application/copyright")
  107. copyright=p_value;
  108. else if (n=="application/bits_mode")
  109. bits_mode=BitsMode(int(p_value));
  110. else if (n=="display/high_res")
  111. high_resolution=p_value;
  112. else
  113. return false;
  114. return true;
  115. }
  116. bool EditorExportPlatformOSX::_get(const StringName& p_name,Variant &r_ret) const{
  117. String n=p_name;
  118. if (n=="custom_package/debug")
  119. r_ret=custom_debug_package;
  120. else if (n=="custom_package/release")
  121. r_ret=custom_release_package;
  122. else if (n=="application/name")
  123. r_ret=app_name;
  124. else if (n=="application/info")
  125. r_ret=info;
  126. else if (n=="application/icon")
  127. r_ret=icon;
  128. else if (n=="application/identifier")
  129. r_ret=identifier;
  130. else if (n=="application/signature")
  131. r_ret=signature;
  132. else if (n=="application/short_version")
  133. r_ret=short_version;
  134. else if (n=="application/version")
  135. r_ret=version;
  136. else if (n=="application/copyright")
  137. r_ret=copyright;
  138. else if (n=="application/bits_mode")
  139. r_ret=bits_mode;
  140. else if (n=="display/high_res")
  141. r_ret=high_resolution;
  142. else
  143. return false;
  144. return true;
  145. }
  146. void EditorExportPlatformOSX::_get_property_list( List<PropertyInfo> *p_list) const{
  147. p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE,"zip"));
  148. p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE,"zip"));
  149. p_list->push_back( PropertyInfo( Variant::STRING, "application/name") );
  150. p_list->push_back( PropertyInfo( Variant::STRING, "application/info") );
  151. p_list->push_back( PropertyInfo( Variant::STRING, "application/icon",PROPERTY_HINT_FILE,"png") );
  152. p_list->push_back( PropertyInfo( Variant::STRING, "application/identifier") );
  153. p_list->push_back( PropertyInfo( Variant::STRING, "application/signature") );
  154. p_list->push_back( PropertyInfo( Variant::STRING, "application/short_version") );
  155. p_list->push_back( PropertyInfo( Variant::STRING, "application/version") );
  156. p_list->push_back( PropertyInfo( Variant::STRING, "application/copyright") );
  157. p_list->push_back( PropertyInfo( Variant::INT, "application/bits_mode", PROPERTY_HINT_ENUM, "Fat (32 & 64 bits),64 bits,32 bits") );
  158. p_list->push_back( PropertyInfo( Variant::BOOL, "display/high_res") );
  159. }
  160. void EditorExportPlatformOSX::_make_icon(const Image& p_icon,Vector<uint8_t>& icon) {
  161. Ref<ImageTexture> it = memnew( ImageTexture );
  162. int size=512;
  163. Vector<uint8_t> data;
  164. data.resize(8);
  165. data[0]='i';
  166. data[1]='c';
  167. data[2]='n';
  168. data[3]='s';
  169. const char *name[]={"ic09","ic08","ic07","icp6","icp5","icp4"};
  170. int index=0;
  171. while(size>=16) {
  172. Image copy = p_icon;
  173. copy.convert(Image::FORMAT_RGBA8);
  174. copy.resize(size,size);
  175. it->create_from_image(copy);
  176. String path = EditorSettings::get_singleton()->get_settings_path()+"/tmp/icon.png";
  177. ResourceSaver::save(path,it);
  178. FileAccess *f = FileAccess::open(path,FileAccess::READ);
  179. ERR_FAIL_COND(!f);
  180. int ofs = data.size();
  181. uint32_t len = f->get_len();
  182. data.resize(data.size()+len+8);
  183. f->get_buffer(&data[ofs+8],len);
  184. memdelete(f);
  185. len+=8;
  186. len=BSWAP32(len);
  187. copymem(&data[ofs],name[index],4);
  188. encode_uint32(len,&data[ofs+4]);
  189. index++;
  190. size/=2;
  191. }
  192. uint32_t total_len = data.size();
  193. total_len = BSWAP32(total_len);
  194. encode_uint32(total_len,&data[4]);
  195. icon=data;
  196. }
  197. void EditorExportPlatformOSX::_fix_plist(Vector<uint8_t>& plist,const String& p_binary) {
  198. String str;
  199. String strnew;
  200. str.parse_utf8((const char*)plist.ptr(),plist.size());
  201. Vector<String> lines=str.split("\n");
  202. for(int i=0;i<lines.size();i++) {
  203. if (lines[i].find("$binary")!=-1) {
  204. strnew+=lines[i].replace("$binary",p_binary)+"\n";
  205. } else if (lines[i].find("$name")!=-1) {
  206. strnew+=lines[i].replace("$name",p_binary)+"\n";
  207. } else if (lines[i].find("$info")!=-1) {
  208. strnew+=lines[i].replace("$info",info)+"\n";
  209. } else if (lines[i].find("$identifier")!=-1) {
  210. strnew+=lines[i].replace("$identifier",identifier)+"\n";
  211. } else if (lines[i].find("$short_version")!=-1) {
  212. strnew+=lines[i].replace("$short_version",short_version)+"\n";
  213. } else if (lines[i].find("$version")!=-1) {
  214. strnew+=lines[i].replace("$version",version)+"\n";
  215. } else if (lines[i].find("$signature")!=-1) {
  216. strnew+=lines[i].replace("$signature",signature)+"\n";
  217. } else if (lines[i].find("$copyright")!=-1) {
  218. strnew+=lines[i].replace("$copyright",copyright)+"\n";
  219. } else if (lines[i].find("$highres")!=-1) {
  220. strnew+=lines[i].replace("$highres",high_resolution?"<true/>":"<false/>")+"\n";
  221. } else {
  222. strnew+=lines[i]+"\n";
  223. }
  224. }
  225. CharString cs = strnew.utf8();
  226. plist.resize(cs.size());
  227. for(int i=9;i<cs.size();i++) {
  228. plist[i]=cs[i];
  229. }
  230. }
  231. Error EditorExportPlatformOSX::export_project(const String& p_path, bool p_debug, int p_flags) {
  232. String src_pkg;
  233. EditorProgress ep("export","Exporting for OSX",104);
  234. if (p_debug)
  235. src_pkg=custom_debug_package;
  236. else
  237. src_pkg=custom_release_package;
  238. if (src_pkg=="") {
  239. String err;
  240. src_pkg=find_export_template("osx.zip", &err);
  241. if (src_pkg=="") {
  242. EditorNode::add_io_error(err);
  243. return ERR_FILE_NOT_FOUND;
  244. }
  245. }
  246. FileAccess *src_f=NULL;
  247. zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
  248. ep.step("Creating app",0);
  249. unzFile pkg = unzOpen2(src_pkg.utf8().get_data(), &io);
  250. if (!pkg) {
  251. EditorNode::add_io_error("Could not find template app to export:\n"+src_pkg);
  252. return ERR_FILE_NOT_FOUND;
  253. }
  254. ERR_FAIL_COND_V(!pkg, ERR_CANT_OPEN);
  255. int ret = unzGoToFirstFile(pkg);
  256. zlib_filefunc_def io2=io;
  257. FileAccess *dst_f=NULL;
  258. io2.opaque=&dst_f;
  259. zipFile dpkg=zipOpen2(p_path.utf8().get_data(),APPEND_STATUS_CREATE,NULL,&io2);
  260. String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + ".";
  261. binary_to_use += String(bits_mode==BITS_FAT ? "fat" : bits_mode==BITS_64 ? "64" : "32");
  262. print_line("binary: "+binary_to_use);
  263. String pkg_name;
  264. if (app_name!="")
  265. pkg_name=app_name;
  266. else if (String(GlobalConfig::get_singleton()->get("application/name"))!="")
  267. pkg_name=String(GlobalConfig::get_singleton()->get("application/name"));
  268. else
  269. pkg_name="Unnamed";
  270. bool found_binary = false;
  271. while(ret==UNZ_OK) {
  272. //get filename
  273. unz_file_info info;
  274. char fname[16384];
  275. ret = unzGetCurrentFileInfo(pkg,&info,fname,16384,NULL,0,NULL,0);
  276. String file=fname;
  277. print_line("READ: "+file);
  278. Vector<uint8_t> data;
  279. data.resize(info.uncompressed_size);
  280. //read
  281. unzOpenCurrentFile(pkg);
  282. unzReadCurrentFile(pkg,data.ptr(),data.size());
  283. unzCloseCurrentFile(pkg);
  284. //write
  285. file = file.replace_first("osx_template.app/","");
  286. if (file=="Contents/Info.plist") {
  287. print_line("parse plist");
  288. _fix_plist(data,pkg_name);
  289. }
  290. if (file.begins_with("Contents/MacOS/godot_")) {
  291. if (file!="Contents/MacOS/"+binary_to_use) {
  292. ret = unzGoToNextFile(pkg);
  293. continue; //ignore!
  294. }
  295. found_binary = true;
  296. file="Contents/MacOS/"+pkg_name;
  297. }
  298. if (file=="Contents/Resources/icon.icns") {
  299. //see if there is an icon
  300. String iconpath = GlobalConfig::get_singleton()->get("application/icon");
  301. print_line("icon? "+iconpath);
  302. if (iconpath!="") {
  303. Image icon;
  304. icon.load(iconpath);
  305. if (!icon.empty()) {
  306. print_line("loaded?");
  307. _make_icon(icon,data);
  308. }
  309. }
  310. //bleh?
  311. }
  312. file=pkg_name+".app/"+file;
  313. if (data.size()>0) {
  314. print_line("ADDING: "+file+" size: "+itos(data.size()));
  315. zip_fileinfo fi;
  316. fi.tmz_date.tm_hour=info.tmu_date.tm_hour;
  317. fi.tmz_date.tm_min=info.tmu_date.tm_min;
  318. fi.tmz_date.tm_sec=info.tmu_date.tm_sec;
  319. fi.tmz_date.tm_mon=info.tmu_date.tm_mon;
  320. fi.tmz_date.tm_mday=info.tmu_date.tm_mday;
  321. fi.tmz_date.tm_year=info.tmu_date.tm_year;
  322. fi.dosDate=info.dosDate;
  323. fi.internal_fa=info.internal_fa;
  324. fi.external_fa=info.external_fa;
  325. int err = zipOpenNewFileInZip(dpkg,
  326. file.utf8().get_data(),
  327. &fi,
  328. NULL,
  329. 0,
  330. NULL,
  331. 0,
  332. NULL,
  333. Z_DEFLATED,
  334. Z_DEFAULT_COMPRESSION);
  335. print_line("OPEN ERR: "+itos(err));
  336. err = zipWriteInFileInZip(dpkg,data.ptr(),data.size());
  337. print_line("WRITE ERR: "+itos(err));
  338. zipCloseFileInZip(dpkg);
  339. }
  340. ret = unzGoToNextFile(pkg);
  341. }
  342. if (!found_binary) {
  343. ERR_PRINTS("Requested template binary '"+binary_to_use+"' not found. It might be missing from your template archive.");
  344. zipClose(dpkg,NULL);
  345. unzClose(pkg);
  346. return ERR_FILE_NOT_FOUND;
  347. }
  348. ep.step("Making PKG",1);
  349. String pack_path=EditorSettings::get_singleton()->get_settings_path()+"/tmp/data.pck";
  350. FileAccess *pfs = FileAccess::open(pack_path,FileAccess::WRITE);
  351. Error err = save_pack(pfs);
  352. memdelete(pfs);
  353. if (err) {
  354. zipClose(dpkg,NULL);
  355. unzClose(pkg);
  356. return err;
  357. }
  358. {
  359. //write datapack
  360. zipOpenNewFileInZip(dpkg,
  361. (pkg_name+".app/Contents/Resources/data.pck").utf8().get_data(),
  362. NULL,
  363. NULL,
  364. 0,
  365. NULL,
  366. 0,
  367. NULL,
  368. Z_DEFLATED,
  369. Z_DEFAULT_COMPRESSION);
  370. FileAccess *pf = FileAccess::open(pack_path,FileAccess::READ);
  371. ERR_FAIL_COND_V(!pf,ERR_CANT_OPEN);
  372. const int BSIZE = 16384;
  373. uint8_t buf[BSIZE];
  374. while(true) {
  375. int r = pf->get_buffer(buf,BSIZE);
  376. if (r<=0)
  377. break;
  378. zipWriteInFileInZip(dpkg,buf,r);
  379. }
  380. zipCloseFileInZip(dpkg);
  381. memdelete(pf);
  382. }
  383. zipClose(dpkg,NULL);
  384. unzClose(pkg);
  385. return OK;
  386. }
  387. Error EditorExportPlatformOSX::run(int p_device, int p_flags) {
  388. return OK;
  389. }
  390. EditorExportPlatformOSX::EditorExportPlatformOSX() {
  391. Image img( _osx_logo );
  392. logo = Ref<ImageTexture>( memnew( ImageTexture ));
  393. logo->create_from_image(img);
  394. info="Made with Godot Engine";
  395. identifier="org.godotengine.macgame";
  396. signature="godotmacgame";
  397. short_version="1.0";
  398. version="1.0";
  399. bits_mode=BITS_FAT;
  400. high_resolution=false;
  401. }
  402. bool EditorExportPlatformOSX::can_export(String *r_error) const {
  403. bool valid=true;
  404. String err;
  405. if (!exists_export_template("osx.zip")) {
  406. valid=false;
  407. err+="No export templates found.\nDownload and install export templates.\n";
  408. }
  409. if (custom_debug_package!="" && !FileAccess::exists(custom_debug_package)) {
  410. valid=false;
  411. err+="Custom debug package not found.\n";
  412. }
  413. if (custom_release_package!="" && !FileAccess::exists(custom_release_package)) {
  414. valid=false;
  415. err+="Custom release package not found.\n";
  416. }
  417. if (r_error)
  418. *r_error=err;
  419. return valid;
  420. }
  421. EditorExportPlatformOSX::~EditorExportPlatformOSX() {
  422. }
  423. #endif
  424. void register_osx_exporter() {
  425. #if 0
  426. Ref<EditorExportPlatformOSX> exporter = Ref<EditorExportPlatformOSX>( memnew(EditorExportPlatformOSX) );
  427. EditorImportExport::get_singleton()->add_export_platform(exporter);
  428. #endif
  429. }