fix a warning.
[Rockbox.git] / rbutil / rbutil.cpp
bloba36d1a0b94d275f03673b8a8e4ee60a49fdd45d7
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * Module: rbutil
9 * File: rbutil.cpp
11 * Copyright (C) 2005 Christi Alice Scarborough
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
21 #include "rbutil.h"
22 #include "installlog.h"
24 /* this function gets a Bitmap from embedded memory */
25 wxBitmap wxGetBitmapFromMemory(const unsigned char *data,int length)
27 wxMemoryInputStream istream( data,length);
28 return wxBitmap(wxImage(istream, wxBITMAP_TYPE_ANY, -1), -1);
31 // This class allows us to return directories as well as files to
32 // wxDir::Traverse
33 class wxDirTraverserIncludeDirs : public wxDirTraverser
35 public:
36 wxDirTraverserIncludeDirs(wxArrayString& files) : m_files(files) { }
38 virtual wxDirTraverseResult OnFile(const wxString& filename)
40 m_files.Add(filename);
41 return wxDIR_CONTINUE;
44 virtual wxDirTraverseResult OnDir(const wxString& dirname)
46 m_files.Add(dirname);
47 return wxDIR_CONTINUE;
50 private:
51 wxArrayString& m_files;
54 wxDEFINE_SCOPED_PTR_TYPE(wxZipEntry);
56 const wxChar* _rootmatch[] = {
57 wxT("rockbox.*"),
58 wxT("ajbrec.ajz"),
59 wxT("archos.mod"),
60 wxT(".scrobbler.*"),
61 wxT("battery_bench.txt"),
62 wxT("battery.dummy"),
64 const wxArrayString* rootmatch = new wxArrayString(
65 (size_t) (sizeof(_rootmatch) / sizeof(wxChar*)), _rootmatch);
67 bool InstallTheme(wxString Themesrc)
69 wxString dest,src,err;
71 int pos = Themesrc.Find('/',true);
72 wxString themename = Themesrc.SubString(pos+1,Themesrc.Length());
74 src = gv->themes_url + wxT("/") + Themesrc;
75 dest = gv->stdpaths->GetUserDataDir()
76 + wxT("" PATH_SEP "download" PATH_SEP) + themename;
77 if( DownloadURL(src, dest) )
79 wxRemoveFile(dest);
80 ERR_DIALOG(wxT("Unable to download ") + src, wxT("Install Theme"));
81 return false;
84 if(!checkZip(dest))
86 ERR_DIALOG(wxT("The Zip ") + dest
87 + wxT(" does not contain the correct dir structure"),
88 wxT("Install Theme"));
89 return false;
92 if(UnzipFile(dest,gv->curdestdir, true))
94 ERR_DIALOG(wxT("Unable to unzip ") + dest + wxT(" to ")
95 + gv->curdestdir, wxT("Install Theme"));
96 return false;
99 return true;
102 bool checkZip(wxString zipname)
104 wxZipEntryPtr entry;
106 wxFFileInputStream* in_file = new wxFFileInputStream(zipname);
107 wxZipInputStream* in_zip = new wxZipInputStream(*in_file);
109 entry.reset(in_zip->GetNextEntry());
111 wxString name = entry->GetName();
112 if(entry->IsDir())
114 if(name.Contains(wxT(".rockbox")))
116 return true;
119 return false;
122 int DownloadURL(wxString src, wxString dest)
124 int input, errnum = 0, success = false;
125 wxString buf, errstr;
126 wxLogVerbose(wxT("=== begin DownloadURL(%s,%s)"), src.c_str(),
127 dest.c_str());
129 buf = wxT("Fetching ") + src;
130 wxProgressDialog* progress = new wxProgressDialog(wxT("Downloading"),
131 buf, 100, NULL, wxPD_APP_MODAL |
132 wxPD_AUTO_HIDE | wxPD_SMOOTH | wxPD_ELAPSED_TIME |
133 wxPD_REMAINING_TIME | wxPD_CAN_ABORT);
134 progress->SetSize(500,200);
135 progress->Update(0);
138 input = true;
139 wxURL* in_http = new wxURL(src);
141 if(gv->proxy_url != wxT(""))
142 in_http->SetProxy(gv->proxy_url);
144 if (in_http->GetError() == wxURL_NOERR)
147 wxFFileOutputStream* os = new wxFFileOutputStream(dest);
148 input = false;
149 if (os->IsOk())
151 wxInputStream* is = in_http->GetInputStream();
152 input = true;
153 if (is)
155 size_t filesize = is->GetSize();
156 input = true;
157 if (is->IsOk())
159 char buffer[FILE_BUFFER_SIZE + 1];
160 size_t current = 0;
162 while (! is->Eof())
164 is->Read(buffer, FILE_BUFFER_SIZE);
165 input = true;
166 if (is->LastRead() )
168 os->Write(buffer, is->LastRead());
169 input = false;
170 if (os->IsOk())
172 current += os->LastWrite();
173 if (!progress->Update(current * 100 / filesize))
175 errstr = wxT("Download aborted by user");
176 errnum = 1000;
177 break;
180 } else
182 errnum = os->GetLastError();
183 errstr = wxT("Can't write to output stream (")
184 + stream_err_str(errnum) + wxT(")");
186 break;
189 } else
191 errnum = is->GetLastError();
192 if (errnum == wxSTREAM_EOF)
194 errnum = 0;
195 break;
197 errstr = wxT("Can't read from input stream (")
198 + stream_err_str(errnum) + wxT(")");
202 os->Close();
203 if (! errnum)
205 errnum = os->GetLastError();
206 errstr = wxT("Can't close output file (")
207 + stream_err_str(errnum) + wxT(")");
209 input = false;
212 if (! errnum) success = true;
214 } else
216 errnum = is->GetLastError();
217 errstr = wxT("Can't get input stream size (")
218 + stream_err_str(errnum) + wxT(")");
220 } else
222 errnum = in_http->GetError();
223 errstr.Printf(wxT("Can't get input stream (%d)"), errnum);
225 delete is;
226 } else
228 errnum = os->GetLastError();
229 errstr = wxT("Can't create output stream (")
230 + stream_err_str(errnum) + wxT(")");
232 delete os;
233 } else
235 errstr.Printf(wxT("Can't open URL %s (%d)"), src.c_str(),
236 in_http->GetError() );
237 errnum = 100;
240 delete in_http;
241 delete progress;
243 if (!success)
245 if (errnum == 0) errnum = 999;
246 if (input)
248 ERR_DIALOG(errstr + wxT(" reading\n") + src, wxT("Download URL"));
249 } else
251 ERR_DIALOG(errstr + wxT("writing to download\n/") + dest,
252 wxT("Download URL"));
257 wxLogVerbose(wxT("=== end DownloadURL"));
258 return errnum;
261 int UnzipFile(wxString src, wxString destdir, bool isInstall)
263 wxZipEntryPtr entry;
264 wxString in_str, progress_msg, buf;
265 int errnum = 0, curfile = 0, totalfiles = 0;
266 InstallLog* log = NULL;
268 wxLogVerbose(wxT("===begin UnzipFile(%s,%s,%i)"),
269 src.c_str(), destdir.c_str(), isInstall);
271 wxFFileInputStream* in_file = new wxFFileInputStream(src);
272 wxZipInputStream* in_zip = new wxZipInputStream(*in_file);
273 if (in_file->Ok() )
275 if (! in_zip->IsOk() )
277 errnum = in_zip->GetLastError();
278 ERR_DIALOG(wxT("Can't open ZIP stream ") + src
279 + wxT(" for reading (") + stream_err_str(errnum)
280 + wxT(")"), wxT("Unzip File") );
281 delete in_zip;
282 delete in_file;
283 return true;
286 totalfiles = in_zip->GetTotalEntries();
287 if (! in_zip->IsOk() )
289 errnum = in_zip->GetLastError();
290 ERR_DIALOG( wxT("Error Getting total ZIP entries for ")
291 + src + wxT(" (") + stream_err_str(errnum) + wxT(")"),
292 wxT("Unzip File") );
293 delete in_zip;
294 delete in_file;
295 return true;
297 } else
299 errnum = in_file->GetLastError();
300 ERR_DIALOG(wxT("Can't open ") + src + wxT(" (")
301 + stream_err_str(errnum) + wxT(")"), wxT("Unzip File") );
302 delete in_zip;
303 delete in_file;
304 return true;
307 wxProgressDialog* progress = new wxProgressDialog(wxT("Unpacking archive"),
308 wxT("Preparing to unpack the downloaded files to your audio"
309 "device"), totalfiles, NULL, wxPD_APP_MODAL |
310 wxPD_AUTO_HIDE | wxPD_SMOOTH | wxPD_ELAPSED_TIME |
311 wxPD_REMAINING_TIME | wxPD_CAN_ABORT);
312 progress->Update(0);
314 // We're not overly worried if the logging fails
315 if (isInstall)
317 log = new InstallLog(destdir + wxT("" PATH_SEP UNINSTALL_FILE));
320 while (! errnum &&
321 (entry.reset(in_zip->GetNextEntry()), entry.get() != NULL) )
324 curfile++;
325 wxString name = entry->GetName();
326 progress_msg = wxT("Unpacking ") + name;
327 if (! progress->Update(curfile, progress_msg) ) {
328 MESG_DIALOG(wxT("Unpacking cancelled by user"));
329 errnum = 1000;
330 break;
333 in_str = destdir + wxT("" PATH_SEP) + name;
335 if (entry->IsDir() ) {
336 if (!wxDirExists(in_str) ) {
337 if (! wxMkdir(in_str, 0777) ) {
338 buf = wxT("Unable to create directory ") + in_str;
339 errnum = 100;
340 break;
343 log->WriteFile(name, true); // Directory
344 continue;
347 wxFFileOutputStream* out = new wxFFileOutputStream(in_str);
348 if (! out->IsOk() )
350 buf = wxT("Can't open file ") + in_str + wxT(" for writing");
351 delete out;
352 return 100;
353 } else if (isInstall)
355 log->WriteFile(name);
358 in_zip->Read(*out);
359 if (! out->IsOk()) {
360 buf.Printf(wxT("Can't write to %s (%d)"), in_str.c_str(),
361 errnum = out->GetLastError() );
364 if (!in_zip->IsOk() && ! in_file->GetLastError() == wxSTREAM_EOF)
366 buf.Printf(wxT("Can't read from %s (%d)"), src.c_str(),
367 errnum = in_file->GetLastError() );
370 if (! out->Close() && errnum == 0)
372 buf.Printf(wxT("Unable to close %s (%d)"), in_str.c_str(),
373 errnum = out->GetLastError() );
377 delete out;
381 delete in_zip; delete in_file; delete progress;
383 if (errnum)
385 ERR_DIALOG(buf, wxT("Unzip File"));
388 if (log) delete log;
389 wxLogVerbose(wxT("=== end UnzipFile"));
390 return(errnum);
393 int Uninstall(const wxString dir, bool isFullUninstall) {
394 wxString buf, uninst;
395 unsigned int i;
396 bool errflag = false;
397 InstallLog *log = NULL;
398 wxArrayString* FilesToRemove = NULL;
400 wxLogVerbose(wxT("=== begin Uninstall(%s,%i)"), dir.c_str(), isFullUninstall);
402 wxProgressDialog* progress = new wxProgressDialog(wxT("Uninstalling"),
403 wxT("Reading uninstall data from jukebox"), 100, NULL,
404 wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_SMOOTH |
405 wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME | wxPD_CAN_ABORT);
406 progress->Update(0);
408 if (! isFullUninstall)
411 buf = dir + wxT("" PATH_SEP UNINSTALL_FILE);
412 log = new InstallLog(buf, false); // Don't create the log
413 FilesToRemove = log->GetInstalledFiles();
414 if (log) delete log;
416 if (FilesToRemove == NULL || FilesToRemove->GetCount() < 1) {
417 wxLogNull lognull;
418 if ( wxMessageDialog(NULL,
419 wxT("Rockbox Utility can't find any uninstall data on this "
420 "jukebox.\n"
421 "Would you like to attempt a full uninstall?\n"
422 "(WARNING: A full uninstall removes all files in your Rockbox "
423 "folder)"),
424 wxT("Standard uninstall not possible"),
425 wxICON_EXCLAMATION | wxYES_NO | wxNO_DEFAULT).ShowModal()
426 == wxID_YES)
428 isFullUninstall = true;
430 else {
431 MESG_DIALOG(wxT("Uninstall cancelled by user"));
432 delete progress;
433 return 1000;
438 if (isFullUninstall )
440 buf = dir + wxT("" PATH_SEP ".rockbox");
441 if (rm_rf(buf) )
443 WARN_DIALOG(wxT("Unable to completely remove Rockbox directory"),
444 wxT("Full uninstall") );
445 errflag = true;
448 wxDir* root = new wxDir(dir);
449 wxArrayString* special = new wxArrayString();
450 // Search for files for deletion in the jukebox root
451 for (i = 0; i < rootmatch->GetCount(); i++)
453 const wxString match = (*rootmatch)[i];
454 root->GetAllFiles(dir, special, match, wxDIR_FILES);
456 delete root;
458 // Sort in reverse order so we get directories last
459 special->Sort(true);
461 for (i = 0; i < special->GetCount(); i++)
464 if (wxDirExists((*special)[i]) )
466 // We don't check the return code since we don't want non
467 // empty dirs disappearing.
468 wxRmdir((*special)[i]);
470 } else if (wxFileExists((*special)[i]) )
472 if (! wxRemoveFile((*special)[i]) )
474 WARN_DIALOG(wxT("Can't delete ") + (*special)[i],
475 wxT("Full uninstall"));
476 errflag = true;
479 // Otherwise there isn't anything there, so we don't have to worry.
481 delete special;
482 } else
484 wxString instplat, this_path_sep;
485 unsigned int totalfiles, rc;
486 totalfiles = FilesToRemove->GetCount();
487 FilesToRemove->Sort(true); // Reverse alphabetical ie dirs after files
489 for (i = 0; i < totalfiles; i++)
491 // If we're running on the device, let's not delete our own
492 // installation, eh?
493 if (gv->portable &&
494 FilesToRemove->Item(i).StartsWith(PATH_SEP
495 wxT("RockboxUtility")) )
497 continue;
500 wxString* buf2 = new wxString;
501 buf = dir + FilesToRemove->Item(i);
502 buf2->Format(wxT("Deleting %s"), buf.c_str());
504 if (! progress->Update((i + 1) * 100 / totalfiles, *buf2) )
506 WARN_DIALOG(wxT("Cancelled by user"), wxT("Normal Uninstall"));
507 delete progress;
508 return true;
511 if (wxDirExists(buf) )
513 // If we're about to attempt to remove .rockbox. delete
514 // install data first
515 *buf2 = dir + wxT("" PATH_SEP ".rockbox");
516 if ( buf.IsSameAs(buf2->c_str()) )
518 *buf2 = dir +wxT("" PATH_SEP UNINSTALL_FILE);
519 wxRemoveFile(*buf2);
522 if ( (rc = ! wxRmdir(buf)) )
524 buf = buf.Format(wxT("Can't remove directory %s"),
525 buf.c_str());
526 errflag = true;
527 WARN_DIALOG(buf.c_str(), wxT("Standard uninstall"));
529 } else if (wxFileExists(buf) )
531 if ( (rc = ! wxRemoveFile(buf)) )
533 buf = buf.Format(wxT("Can't delete file %s"),
534 buf.c_str());
535 errflag = true;
536 WARN_DIALOG(buf.c_str(), wxT("Standard uninstall"));
538 } else
540 errflag = true;
541 buf = buf.Format(wxT("Can't find file or directory %s"),
542 buf.c_str() );
543 WARN_DIALOG(buf.c_str(), wxT("Standard uninstall") );
546 uninst = uninst.AfterFirst('\n');
548 if (errflag)
550 ERR_DIALOG(wxT("Unable to remove some files"),
551 wxT("Standard uninstall")) ;
554 if (FilesToRemove != NULL) delete FilesToRemove;
557 delete progress;
558 wxLogVerbose(wxT("=== end Uninstall"));
559 return errflag;
563 wxString stream_err_str(int errnum)
565 wxString out;
567 switch (errnum) {
568 case wxSTREAM_NO_ERROR:
569 out = wxT("wxSTREAM_NO_ERROR");
570 break;
571 case wxSTREAM_EOF:
572 out = wxT("wxSTREAM_EOF");
573 break;
574 case wxSTREAM_WRITE_ERROR:
575 out = wxT("wxSTREAM_WRITE_ERROR");
576 break;
577 case wxSTREAM_READ_ERROR:
578 out = wxT("wxSTREAM_READ_ERROR");
579 break;
580 default:
581 out = wxT("UNKNOWN");
582 break;
584 return out;
587 bool InstallRbutil(wxString dest)
589 wxArrayString filestocopy;
590 wxString str, buf, dstr, localpath, destdir;
591 unsigned int i;
592 wxDir dir;
593 bool copied_exe = false, made_rbdir = false;
594 InstallLog* log;
596 buf = dest + wxT("" PATH_SEP ".rockbox");
598 if (! wxDirExists(buf) )
600 wxMkdir(buf);
601 made_rbdir = true;
604 buf = dest + wxT("" PATH_SEP UNINSTALL_FILE);
605 log = new InstallLog(buf);
606 if (made_rbdir) log->WriteFile(wxT(".rockbox"), true);
608 destdir = dest + wxT("" PATH_SEP "RockboxUtility");
609 if (! wxDirExists(destdir) )
611 if (! wxMkdir(destdir, 0777) )
613 WARN_DIALOG( wxT("Unable to create directory for installer (")
614 + destdir + wxT(")"), wxT("Portable install") );
615 return false;
617 log->WriteFile(wxT("RockboxUtility"), true);
620 dir.GetAllFiles(gv->ResourceDir, &filestocopy, wxT("*"),
621 wxDIR_FILES);
622 if (filestocopy.GetCount() < 1)
624 WARN_DIALOG(wxT("No files to copy"), wxT("Portable install") );
625 return false;
628 // Copy the contents of the program directory
629 for (i = 0; i < filestocopy.GetCount(); i++)
631 if (filestocopy[i].AfterLast(PATH_SEP_CHR) == EXE_NAME)
633 copied_exe = true;
636 dstr = destdir + wxT("" PATH_SEP)
637 + filestocopy[i].AfterLast(PATH_SEP_CHR);
638 if (! wxCopyFile(filestocopy[i], dstr) )
640 WARN_DIALOG( wxT("Error copying file (")
641 + filestocopy[i].c_str() + wxT(" -> ")
642 + dstr + wxT(")"), wxT("Portable Install") );
643 return false;
645 buf = dstr;
646 buf.Replace(dest, wxEmptyString, false);
647 log->WriteFile(buf);
650 if (! copied_exe)
652 str = gv->AppDir + wxT("" PATH_SEP EXE_NAME);
653 dstr = destdir + wxT("" PATH_SEP EXE_NAME);
654 if (! wxCopyFile(str, dstr) )
656 WARN_DIALOG(wxT("Can't copy program binary ")
657 + str + wxT(" -> ") + dstr, wxT("Portable Install") );
658 return false;
660 buf = dstr;
661 buf.Replace(dest, wxEmptyString, false);
662 log->WriteFile(buf);
665 // Copy the local ini file so that it knows that it's a portable copy
666 gv->UserConfig->Flush();
667 dstr = destdir + wxT("" PATH_SEP "RockboxUtility.cfg");
668 if (! wxCopyFile(gv->UserConfigFile, dstr) )
670 WARN_DIALOG(wxT("Unable to install user config file (")
671 + gv->UserConfigFile + wxT(" -> ") + dstr + wxT(")"),
672 wxT("Portable Install") );
673 return false;
675 buf = dstr;
676 buf.Replace(dest, wxEmptyString, false);
677 log->WriteFile(buf);
679 delete log;
680 return true;
683 bool rm_rf(wxString file)
685 wxLogVerbose(wxT("=== begin rm-rf(%s)"), file.c_str() );
687 wxString buf;
688 wxArrayString selected;
689 wxDirTraverserIncludeDirs wxdtid(selected);
690 unsigned int rc = 0, i;
691 bool errflag = false;
693 if (wxFileExists(file) )
695 rc = ! wxRemoveFile(file);
696 } else if (wxDirExists(file) )
698 wxDir* dir = new wxDir(file);;
699 dir->Traverse(wxdtid);
700 delete dir;
701 // Sort into reverse alphabetical order for deletion in correct order
702 // (directories after files)
703 selected.Sort(true);
704 selected.Add(file);
706 wxProgressDialog* progress = new wxProgressDialog(wxT("Removing files"),
707 wxT("Deleting files"), selected.GetCount(), NULL,
708 wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_SMOOTH |
709 wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME | wxPD_CAN_ABORT);
711 for (i = 0; i < selected.GetCount(); i++)
713 wxLogVerbose(selected[i]);
714 if (progress != NULL)
716 buf = wxT("Deleting ") + selected[i];
717 if (! progress->Update(i, buf))
719 WARN_DIALOG(wxT("Cancelled by user"), wxT("Erase Files"));
720 delete progress;
721 return true;
725 if (wxDirExists(selected[i]) )
727 if ((rc = ! wxRmdir(selected[i])) )
729 errflag = true;
730 WARN_DIALOG(wxT("Can't remove directory ") + selected[i],
731 wxT("Erase files"));
733 } else if ((rc = ! wxRemoveFile(selected[i])) )
735 errflag = true;
736 WARN_DIALOG(wxT("Error deleting file ") + selected[i],
737 wxT("Erase files"));
740 delete progress;
741 } else
743 WARN_DIALOG(wxT("Can't find expected file ") + file,
744 wxT("Erase files"));
745 return true;
748 wxLogVerbose(wxT("=== end rm-rf"));
749 return rc ? true : false;