Update the Swedish translation.
[kugel-rb.git] / rbutil / rbutil.cpp
blobe778cf404ef5df12fc3364d4487dfba951552be7
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"
25 // This class allows us to return directories as well as files to
26 // wxDir::Traverse
27 class wxDirTraverserIncludeDirs : public wxDirTraverser
29 public:
30 wxDirTraverserIncludeDirs(wxArrayString& files) : m_files(files) { }
32 virtual wxDirTraverseResult OnFile(const wxString& filename)
34 m_files.Add(filename);
35 return wxDIR_CONTINUE;
38 virtual wxDirTraverseResult OnDir(const wxString& dirname)
40 m_files.Add(dirname);
41 return wxDIR_CONTINUE;
44 private:
45 wxArrayString& m_files;
48 wxDEFINE_SCOPED_PTR_TYPE(wxZipEntry);
50 const wxChar* _rootmatch[] = {
51 wxT("rockbox.*"),
52 wxT("ajbrec.ajz"),
53 wxT("archos.mod"),
54 wxT(".scrobbler.*"),
55 wxT("battery_bench.txt"),
56 wxT("battery.dummy"),
58 const wxArrayString* rootmatch = new wxArrayString(
59 (size_t) (sizeof(_rootmatch) / sizeof(wxChar*)), _rootmatch);
61 bool InstallTheme(wxString Themesrc)
63 wxString dest,src,err;
65 int pos = Themesrc.Find('/',true);
66 wxString themename = Themesrc.SubString(pos+1,Themesrc.Length());
68 src.Printf(wxT("%s/%s"), gv->themes_url.c_str(),Themesrc.c_str());
69 dest.Printf(wxT("%s" PATH_SEP "download" PATH_SEP "%s"),
70 gv->stdpaths->GetUserDataDir().c_str(),themename.c_str());
71 if( DownloadURL(src, dest) )
73 wxRemoveFile(dest);
74 err.Printf(wxT("Unable to download %s"), src.c_str() );
75 ERR_DIALOG(err, wxT("Install Theme"));
76 return false;
79 if(!checkZip(dest))
81 err.Printf(wxT("The Zip %s does not contain the correct dir structure"), dest.c_str());
82 ERR_DIALOG(err, wxT("Install Theme"));
83 return false;
86 if(UnzipFile(dest,gv->curdestdir, true))
88 err.Printf(wxT("Unable to unzip %s to %s"), dest.c_str(), gv->curdestdir.c_str());
89 ERR_DIALOG(err, wxT("Install Theme"));
90 return false;
93 return true;
96 bool checkZip(wxString zipname)
98 wxZipEntryPtr entry;
100 wxFFileInputStream* in_file = new wxFFileInputStream(zipname);
101 wxZipInputStream* in_zip = new wxZipInputStream(*in_file);
103 entry.reset(in_zip->GetNextEntry());
105 wxString name = entry->GetName();
106 if(entry->IsDir())
108 if(name.Contains(wxT(".rockbox")))
110 return true;
113 return false;
116 int DownloadURL(wxString src, wxString dest)
118 int input, errnum = 0, success = false;
119 wxString buf, errstr;
120 wxLogVerbose(wxT("=== begin DownloadURL(%s,%s)"), src.c_str(),
121 dest.c_str());
123 buf.Printf(wxT("Fetching %s"), src.c_str());
124 wxProgressDialog* progress = new wxProgressDialog(wxT("Downloading"),
125 buf, 100, NULL, wxPD_APP_MODAL |
126 wxPD_AUTO_HIDE | wxPD_SMOOTH | wxPD_ELAPSED_TIME |
127 wxPD_REMAINING_TIME | wxPD_CAN_ABORT);
128 progress->SetSize(500,200);
129 progress->Update(0);
132 input = true;
133 wxURL* in_http = new wxURL(src);
135 if(gv->proxy_url != wxT(""))
136 in_http->SetProxy(gv->proxy_url);
138 if (in_http->GetError() == wxURL_NOERR)
141 wxFFileOutputStream* os = new wxFFileOutputStream(dest);
142 input = false;
143 if (os->IsOk())
145 wxInputStream* is = in_http->GetInputStream();
146 input = true;
147 if (is)
149 size_t filesize = is->GetSize();
150 input = true;
151 if (is->IsOk())
153 char buffer[FILE_BUFFER_SIZE + 1];
154 size_t current = 0;
156 while (! is->Eof())
158 is->Read(buffer, FILE_BUFFER_SIZE);
159 input = true;
160 if (is->LastRead() )
162 os->Write(buffer, is->LastRead());
163 input = false;
164 if (os->IsOk())
166 current += os->LastWrite();
167 if (!progress->Update(current * 100 / filesize))
169 errstr = wxT("Download aborted by user");
170 errnum = 1000;
171 break;
174 } else
176 errnum = os->GetLastError();
177 errstr.Printf(wxT("Can't write to output stream (%s)"),
178 stream_err_str(errnum).c_str() );
180 break;
183 } else
185 errnum = is->GetLastError();
186 if (errnum == wxSTREAM_EOF)
188 errnum = 0;
189 break;
191 errstr.Printf(wxT("Can't read from input stream (%s)"),
192 stream_err_str(errnum).c_str() );
196 os->Close();
197 if (! errnum)
199 errnum = os->GetLastError();
200 errstr.Printf(wxT("Can't close output file (%s)"),
201 stream_err_str(errnum).c_str() );
203 input = false;
206 if (! errnum) success = true;
208 } else
210 errnum = is->GetLastError();
211 errstr.Printf(wxT("Can't get input stream size (%s)"),
212 stream_err_str(errnum).c_str() );
215 } else
217 errnum = in_http->GetError();
218 errstr.Printf(wxT("Can't get input stream (%d)"), errnum);
220 delete is;
221 } else
223 errnum = os->GetLastError();
224 errstr.Printf(wxT("Can't create output stream (%s)"),
225 stream_err_str(errnum).c_str() );
227 delete os;
228 } else
230 errstr.Printf(wxT("Can't open URL %s (%d)"), src.c_str(),
231 in_http->GetError() );
232 errnum = 100;
235 delete in_http;
236 delete progress;
238 if (!success)
240 if (errnum == 0) errnum = 999;
241 if (input)
243 buf.Printf(wxT("%s reading\n%s"),
244 errstr.c_str(), src.c_str());
245 ERR_DIALOG(buf, wxT("Download URL"));
246 } else
248 buf.Printf(wxT("%s writing to download\n/%s"),
249 errstr.c_str(), dest.c_str());
250 ERR_DIALOG(buf, wxT("Download URL"));
255 wxLogVerbose(wxT("=== end DownloadURL"));
256 return errnum;
259 int UnzipFile(wxString src, wxString destdir, bool isInstall)
261 wxZipEntryPtr entry;
262 wxString in_str, progress_msg, buf;
263 int errnum = 0, curfile = 0, totalfiles = 0;
264 InstallLog* log = NULL;
266 wxLogVerbose(wxT("===begin UnzipFile(%s,%s,%i)"),
267 src.c_str(), destdir.c_str(), isInstall);
269 wxFFileInputStream* in_file = new wxFFileInputStream(src);
270 wxZipInputStream* in_zip = new wxZipInputStream(*in_file);
271 if (in_file->Ok() )
273 if (! in_zip->IsOk() )
275 errnum = in_zip->GetLastError();
276 buf.Printf(wxT("Can't open ZIP stream %s for reading (%s)"),
277 src.c_str(), stream_err_str(errnum).c_str() );
278 ERR_DIALOG(buf, wxT("Unzip File") );
279 delete in_zip;
280 delete in_file;
281 return true;
284 totalfiles = in_zip->GetTotalEntries();
285 if (! in_zip->IsOk() )
287 errnum = in_zip->GetLastError();
288 buf.Printf(wxT("Error Getting total ZIP entries for %s (%s)"),
289 src.c_str(), stream_err_str(errnum).c_str() );
290 ERR_DIALOG(buf, wxT("Unzip File") );
291 delete in_zip;
292 delete in_file;
293 return true;
295 } else
297 errnum = in_file->GetLastError();
298 buf.Printf(wxT("Can't open %s (%s)"), src.c_str(),
299 stream_err_str(errnum).c_str() );
300 ERR_DIALOG(buf, wxT("Unzip File") );
301 delete in_zip;
302 delete in_file;
303 return true;
306 wxProgressDialog* progress = new wxProgressDialog(wxT("Unpacking archive"),
307 wxT("Preparing to unpack the downloaded files to your audio"
308 "device"), totalfiles, NULL, wxPD_APP_MODAL |
309 wxPD_AUTO_HIDE | wxPD_SMOOTH | wxPD_ELAPSED_TIME |
310 wxPD_REMAINING_TIME | wxPD_CAN_ABORT);
311 progress->Update(0);
313 // We're not overly worried if the logging fails
314 if (isInstall)
316 buf.Printf(wxT("%s" PATH_SEP UNINSTALL_FILE), destdir.c_str());
317 log = new InstallLog(buf);
320 while (! errnum &&
321 (entry.reset(in_zip->GetNextEntry()), entry.get() != NULL) )
324 curfile++;
325 wxString name = entry->GetName();
326 progress_msg.Printf(wxT("Unpacking %s"), name.c_str());
327 if (! progress->Update(curfile, progress_msg) ) {
328 buf.Printf(wxT("Unpacking cancelled by user"));
329 MESG_DIALOG(buf);
330 errnum = 1000;
331 break;
334 in_str.Printf(wxT("%s" PATH_SEP "%s"), destdir.c_str(), name.c_str());
336 if (entry->IsDir() ) {
337 if (!wxDirExists(in_str) ) {
338 if (! wxMkdir(in_str, 0777) ) {
339 buf.Printf(wxT("Unable to create directory %s"),
340 in_str.c_str() );
341 errnum = 100;
342 break;
345 log->WriteFile(name, true); // Directory
346 continue;
349 wxFFileOutputStream* out = new wxFFileOutputStream(in_str);
350 if (! out->IsOk() )
352 buf.Printf(wxT("Can't open file %s for writing"), in_str.c_str() );
353 delete out;
354 return 100;
355 } else if (isInstall)
357 log->WriteFile(name);
360 in_zip->Read(*out);
361 if (! out->IsOk()) {
362 buf.Printf(wxT("Can't write to %s (%d)"), in_str.c_str(),
363 errnum = out->GetLastError() );
366 if (!in_zip->IsOk() && ! in_file->GetLastError() == wxSTREAM_EOF)
368 buf.Printf(wxT("Can't read from %s (%d)"), src.c_str(),
369 errnum = in_file->GetLastError() );
372 if (! out->Close() && errnum == 0)
374 buf.Printf(wxT("Unable to close %s (%d)"), in_str.c_str(),
375 errnum = out->GetLastError() );
379 delete out;
383 delete in_zip; delete in_file; delete progress;
385 if (errnum)
387 ERR_DIALOG(buf, wxT("Unzip File"));
390 if (log) delete log;
391 wxLogVerbose(wxT("=== end UnzipFile"));
392 return(errnum);
395 int Uninstall(const wxString dir, bool isFullUninstall) {
396 wxString buf, uninst;
397 unsigned int i;
398 bool errflag = false;
399 InstallLog *log = NULL;
400 wxArrayString* FilesToRemove = NULL;
402 wxLogVerbose(wxT("=== begin Uninstall(%s,%i)"), dir.c_str(), isFullUninstall);
404 wxProgressDialog* progress = new wxProgressDialog(wxT("Uninstalling"),
405 wxT("Reading uninstall data from jukebox"), 100, NULL,
406 wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_SMOOTH |
407 wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME | wxPD_CAN_ABORT);
408 progress->Update(0);
410 if (! isFullUninstall)
413 buf.Printf(wxT("%s" PATH_SEP UNINSTALL_FILE), dir.c_str());
414 log = new InstallLog(buf, false); // Don't create the log
415 FilesToRemove = log->GetInstalledFiles();
416 if (log) delete log;
418 if (FilesToRemove == NULL || FilesToRemove->GetCount() < 1) {
419 wxLogNull lognull;
420 if ( wxMessageDialog(NULL,
421 wxT("Rockbox Utility can't find any uninstall data on this "
422 "jukebox.\n"
423 "Would you like to attempt a full uninstall?\n"
424 "(WARNING: A full uninstall removes all files in your Rockbox "
425 "folder)"),
426 wxT("Standard uninstall not possible"),
427 wxICON_EXCLAMATION | wxYES_NO | wxNO_DEFAULT).ShowModal()
428 == wxID_YES)
430 isFullUninstall = true;
432 else {
433 MESG_DIALOG(wxT("Uninstall cancelled by user"));
434 delete progress;
435 return 1000;
440 if (isFullUninstall )
442 buf.Printf(wxT("%s" PATH_SEP ".rockbox"), dir.c_str());
443 if (rm_rf(buf) )
445 WARN_DIALOG(wxT("Unable to completely remove Rockbox directory"),
446 wxT("Full uninstall") );
447 errflag = true;
450 wxDir* root = new wxDir(dir);
451 wxArrayString* special = new wxArrayString();
452 // Search for files for deletion in the jukebox root
453 for (i = 0; i < rootmatch->GetCount(); i++)
455 const wxString match = (*rootmatch)[i];
456 root->GetAllFiles(dir, special, match, wxDIR_FILES);
458 delete root;
460 // Sort in reverse order so we get directories last
461 special->Sort(true);
463 for (i = 0; i < special->GetCount(); i++)
466 if (wxDirExists((*special)[i]) )
468 // We don't check the return code since we don't want non
469 // empty dirs disappearing.
470 wxRmdir((*special)[i]);
472 } else if (wxFileExists((*special)[i]) )
474 if (! wxRemoveFile((*special)[i]) )
476 buf.Printf(wxT("Can't delete %s"), (*special)[i].c_str());
477 WARN_DIALOG(buf.c_str(), wxT("Full uninstall"));
478 errflag = true;
481 // Otherwise there isn't anything there, so we don't have to worry.
483 delete special;
484 } else
486 wxString instplat, this_path_sep;
487 unsigned int totalfiles, rc;
488 totalfiles = FilesToRemove->GetCount();
489 FilesToRemove->Sort(true); // Reverse alphabetical ie dirs after files
491 for (i = 0; i < totalfiles; i++)
493 // If we're running on the device, let's not delete our own
494 // installation, eh?
495 if (gv->portable &&
496 FilesToRemove->Item(i).StartsWith(PATH_SEP
497 wxT("RockboxUtility")) )
499 continue;
502 wxString* buf2 = new wxString;
503 buf.Printf(wxT("%s%s"), dir.c_str() , FilesToRemove->Item(i).c_str() );
504 buf2->Format(wxT("Deleting %s"), buf.c_str());
506 if (! progress->Update((i + 1) * 100 / totalfiles, *buf2) )
508 WARN_DIALOG(wxT("Cancelled by user"), wxT("Normal Uninstall"));
509 delete progress;
510 return true;
513 if (wxDirExists(buf) )
515 // If we're about to attempt to remove .rockbox. delete
516 // install data first
517 buf2->Printf(wxT("%s" PATH_SEP ".rockbox"), dir.c_str() );
518 if ( buf.IsSameAs(buf2->c_str()) )
520 buf2->Printf(wxT("%s" PATH_SEP UNINSTALL_FILE), dir.c_str());
521 wxRemoveFile(*buf2);
524 if ( (rc = ! wxRmdir(buf)) )
526 buf = buf.Format(wxT("Can't remove directory %s"),
527 buf.c_str());
528 errflag = true;
529 WARN_DIALOG(buf.c_str(), wxT("Standard uninstall"));
531 } else if (wxFileExists(buf) )
533 if ( (rc = ! wxRemoveFile(buf)) )
535 buf = buf.Format(wxT("Can't delete file %s"),
536 buf.c_str());
537 errflag = true;
538 WARN_DIALOG(buf.c_str(), wxT("Standard uninstall"));
540 } else
542 errflag = true;
543 buf = buf.Format(wxT("Can't find file or directory %s"),
544 buf.c_str() );
545 WARN_DIALOG(buf.c_str(), wxT("Standard uninstall") );
548 uninst = uninst.AfterFirst('\n');
550 if (errflag)
552 ERR_DIALOG(wxT("Unable to remove some files"),
553 wxT("Standard uninstall")) ;
556 if (FilesToRemove != NULL) delete FilesToRemove;
559 delete progress;
560 wxLogVerbose(wxT("=== end Uninstall"));
561 return errflag;
565 wxString stream_err_str(int errnum)
567 wxString out;
569 switch (errnum) {
570 case wxSTREAM_NO_ERROR:
571 out = wxT("wxSTREAM_NO_ERROR");
572 break;
573 case wxSTREAM_EOF:
574 out = wxT("wxSTREAM_EOF");
575 break;
576 case wxSTREAM_WRITE_ERROR:
577 out = wxT("wxSTREAM_WRITE_ERROR");
578 break;
579 case wxSTREAM_READ_ERROR:
580 out = wxT("wxSTREAM_READ_ERROR");
581 break;
582 default:
583 out = wxT("UNKNOWN");
584 break;
586 return out;
589 bool InstallRbutil(wxString dest)
591 wxArrayString filestocopy;
592 wxString str, buf, dstr, localpath, destdir;
593 unsigned int i;
594 wxDir dir;
595 bool copied_exe = false, made_rbdir = false;
596 InstallLog* log;
598 buf.Printf(wxT("%s" PATH_SEP ".rockbox"), dest.c_str() );
600 if (! wxDirExists(buf) )
602 wxMkdir(buf);
603 made_rbdir = true;
606 buf.Printf(wxT("%s" PATH_SEP UNINSTALL_FILE), dest.c_str() );
607 log = new InstallLog(buf);
608 if (made_rbdir) log->WriteFile(wxT(".rockbox"), true);
610 destdir.Printf(wxT("%s" PATH_SEP "RockboxUtility"), dest.c_str());
611 if (! wxDirExists(destdir) )
613 if (! wxMkdir(destdir, 0777) )
615 buf.Printf(wxT("%s (%s)"),
616 wxT("Unable to create directory for installer"), destdir.c_str());
617 WARN_DIALOG(buf , wxT("Portable install") );
618 return false;
620 log->WriteFile(wxT("RockboxUtility"), true);
623 dir.GetAllFiles(gv->ResourceDir, &filestocopy, wxT("*"),
624 wxDIR_FILES);
625 if (filestocopy.GetCount() < 1)
627 WARN_DIALOG(wxT("No files to copy"), wxT("Portable install") );
628 return false;
631 // Copy the contents of the program directory
632 for (i = 0; i < filestocopy.GetCount(); i++)
634 if (filestocopy[i].AfterLast(PATH_SEP_CHR) == EXE_NAME)
636 copied_exe = true;
639 dstr.Printf(wxT("%s" PATH_SEP "%s"), destdir.c_str(),
640 filestocopy[i].AfterLast(PATH_SEP_CHR).c_str());
641 if (! wxCopyFile(filestocopy[i], dstr) )
643 buf.Printf(wxT("%s (%s -> %s)"),
644 wxT("Error copying file"), filestocopy[i].c_str(), dstr.c_str());
645 WARN_DIALOG(buf, wxT("Portable Install") );
646 return false;
648 buf = dstr;
649 buf.Replace(dest, wxEmptyString, false);
650 log->WriteFile(buf);
653 if (! copied_exe)
655 str.Printf(wxT("%s" PATH_SEP EXE_NAME), gv->AppDir.c_str());
656 dstr.Printf(wxT("%s" PATH_SEP EXE_NAME), destdir.c_str());
657 if (! wxCopyFile(str, dstr) )
659 buf.Printf(wxT("Can't copy program binary %s -> %s"),
660 str.c_str(), dstr.c_str() );
661 WARN_DIALOG(buf, wxT("Portable Install") );
662 return false;
664 buf = dstr;
665 buf.Replace(dest, wxEmptyString, false);
666 log->WriteFile(buf);
669 // Copy the local ini file so that it knows that it's a portable copy
670 gv->UserConfig->Flush();
671 dstr.Printf(wxT("%s" PATH_SEP "RockboxUtility.cfg"), destdir.c_str());
672 if (! wxCopyFile(gv->UserConfigFile, dstr) )
674 buf.Printf(wxT("%s (%s -> %s)"),
675 wxT("Unable to install user config file"), gv->UserConfigFile.c_str(),
676 dstr.c_str() );
677 WARN_DIALOG(buf, wxT("Portable Install") );
678 return false;
680 buf = dstr;
681 buf.Replace(dest, wxEmptyString, false);
682 log->WriteFile(buf);
684 delete log;
685 return true;
688 bool rm_rf(wxString file)
690 wxLogVerbose(wxT("=== begin rm-rf(%s)"), file.c_str() );
692 wxString buf;
693 wxArrayString selected;
694 wxDirTraverserIncludeDirs wxdtid(selected);
695 unsigned int rc = 0, i;
696 bool errflag = false;
698 if (wxFileExists(file) )
700 rc = ! wxRemoveFile(file);
701 } else if (wxDirExists(file) )
703 wxDir* dir = new wxDir(file);;
704 dir->Traverse(wxdtid);
705 delete dir;
706 // Sort into reverse alphabetical order for deletion in correct order
707 // (directories after files)
708 selected.Sort(true);
709 selected.Add(file);
711 wxProgressDialog* progress = new wxProgressDialog(wxT("Removing files"),
712 wxT("Deleting files"), selected.GetCount(), NULL,
713 wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_SMOOTH |
714 wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME | wxPD_CAN_ABORT);
716 for (i = 0; i < selected.GetCount(); i++)
718 wxLogVerbose(selected[i]);
719 if (progress != NULL)
721 buf.Printf(wxT("Deleting %s"), selected[i].c_str() );
722 if (! progress->Update(i, buf))
724 WARN_DIALOG(wxT("Cancelled by user"), wxT("Erase Files"));
725 delete progress;
726 return true;
730 if (wxDirExists(selected[i]) )
732 if ((rc = ! wxRmdir(selected[i])) )
734 buf.Printf(wxT("Can't remove directory %s"),
735 selected[i].c_str());
736 errflag = true;
737 WARN_DIALOG(buf.c_str(), wxT("Erase files"));
739 } else if ((rc = ! wxRemoveFile(selected[i])) )
741 buf.Printf(wxT("Error deleting file %s"), selected[i].c_str() );
742 errflag = true;
743 WARN_DIALOG(buf.c_str(),wxT("Erase files"));
746 delete progress;
747 } else
749 buf.Printf(wxT("Can't find expected file %s"), file.c_str());
750 WARN_DIALOG(buf.c_str(), wxT("Erase files"));
751 return true;
754 wxLogVerbose(wxT("=== end rm-rf"));
755 return rc ? true : false;