French translation update by Mustapha Senhaji.
[Rockbox.git] / rbutil / rbutil.cpp
blob9ffe9a6c5892b41cbfcb70724e6c02958e08088b
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 int DownloadURL(wxString src, wxString dest)
63 int input, errnum = 0, success = false;
64 wxString buf, errstr;
65 wxLogVerbose(_("=== begin DownloadURL(%s,%s)"), src.c_str(),
66 dest.c_str());
68 buf.Printf(_("Fetching %s"), src.c_str());
69 wxProgressDialog* progress = new wxProgressDialog(_("Downloading"),
70 buf, 100, NULL, wxPD_APP_MODAL |
71 wxPD_AUTO_HIDE | wxPD_SMOOTH | wxPD_ELAPSED_TIME |
72 wxPD_REMAINING_TIME | wxPD_CAN_ABORT);
73 progress->Update(0);
75 input = true;
76 wxURL* in_http = new wxURL(src);
77 if (in_http->GetError() == wxURL_NOERR)
80 wxFFileOutputStream* os = new wxFFileOutputStream(dest);
81 input = false;
82 if (os->IsOk())
84 wxInputStream* is = in_http->GetInputStream();
85 input = true;
86 if (is)
88 size_t filesize = is->GetSize();
89 input = true;
90 if (is->IsOk())
92 char buffer[FILE_BUFFER_SIZE + 1];
93 size_t current = 0;
95 while (! is->Eof())
97 is->Read(buffer, FILE_BUFFER_SIZE);
98 input = true;
99 if (is->LastRead() )
101 os->Write(buffer, is->LastRead());
102 input = false;
103 if (os->IsOk())
105 current += os->LastWrite();
106 if (!progress->Update(current * 100 / filesize))
108 errstr = _("Download aborted by user");
109 errnum = 1000;
110 break;
113 } else
115 errnum = os->GetLastError();
116 errstr.Printf(_("Can't write to output stream (%s)"),
117 stream_err_str(errnum).c_str() );
119 break;
122 } else
124 errnum = is->GetLastError();
125 if (errnum == wxSTREAM_EOF)
127 errnum = 0;
128 break;
130 errstr.Printf(_("Can't read from input stream (%s)"),
131 stream_err_str(errnum).c_str() );
135 os->Close();
136 if (! errnum)
138 errnum = os->GetLastError();
139 errstr.Printf(_("Can't close output file (%s)"),
140 stream_err_str(errnum).c_str() );
142 input = false;
145 if (! errnum) success = true;
147 } else
149 errnum = is->GetLastError();
150 errstr.Printf(_("Can't get input stream size (%s)"),
151 stream_err_str(errnum).c_str() );
154 } else
156 errnum = in_http->GetError();
157 errstr.Printf(_("Can't get input stream (%d)"), errnum);
159 delete is;
160 } else
162 errnum = os->GetLastError();
163 errstr.Printf(_("Can't create output stream (%s)"),
164 stream_err_str(errnum).c_str() );
166 delete os;
167 } else
169 errstr.Printf(_("Can't open URL %s (%d)"), src.c_str(),
170 in_http->GetError() );
171 errnum = 100;
174 delete in_http;
175 delete progress;
177 if (!success)
179 if (errnum == 0) errnum = 999;
180 if (input)
182 buf.Printf(_("%s reading\n%s"),
183 errstr.c_str(), src.c_str());
184 ERR_DIALOG(buf, _("Download URL"));
185 } else
187 buf.Printf(_("%s writing to download\n/%s"),
188 errstr.c_str(), dest.c_str());
189 ERR_DIALOG(buf, _("Download URL"));
194 wxLogVerbose(_("=== end DownloadURL"));
195 return errnum;
198 int UnzipFile(wxString src, wxString destdir, bool isInstall)
200 wxZipEntryPtr entry;
201 wxString in_str, progress_msg, buf;
202 int errnum = 0, curfile = 0, totalfiles = 0;
203 InstallLog* log = NULL;
205 wxLogVerbose(_("===begin UnzipFile(%s,%s,%i)"),
206 src.c_str(), destdir.c_str(), isInstall);
208 wxFFileInputStream* in_file = new wxFFileInputStream(src);
209 wxZipInputStream* in_zip = new wxZipInputStream(*in_file);
210 if (in_file->Ok() )
212 if (! in_zip->IsOk() )
214 errnum = in_zip->GetLastError();
215 buf.Printf(_("Can't open ZIP stream %s for reading (%s)"),
216 src.c_str(), stream_err_str(errnum).c_str() );
217 ERR_DIALOG(buf, _("Unzip File") );
218 delete in_zip;
219 delete in_file;
220 return true;
223 totalfiles = in_zip->GetTotalEntries();
224 if (! in_zip->IsOk() )
226 errnum = in_zip->GetLastError();
227 buf.Printf(_("Error Getting total ZIP entries for %s (%s)"),
228 src.c_str(), stream_err_str(errnum).c_str() );
229 ERR_DIALOG(buf, _("Unzip File") );
230 delete in_zip;
231 delete in_file;
232 return true;
234 } else
236 errnum = in_file->GetLastError();
237 buf.Printf(_("Can't open %s (%s)"), src.c_str(),
238 stream_err_str(errnum).c_str() );
239 ERR_DIALOG(buf, _("Unzip File") );
240 delete in_zip;
241 delete in_file;
242 return true;
245 wxProgressDialog* progress = new wxProgressDialog(_("Unpacking archive"),
246 _("Preparing to unpack the downloaded files to your audio"
247 "device"), totalfiles, NULL, wxPD_APP_MODAL |
248 wxPD_AUTO_HIDE | wxPD_SMOOTH | wxPD_ELAPSED_TIME |
249 wxPD_REMAINING_TIME | wxPD_CAN_ABORT);
250 progress->Update(0);
252 // We're not overly worried if the logging fails
253 if (isInstall)
255 buf.Printf(wxT("%s" PATH_SEP UNINSTALL_FILE), destdir.c_str());
256 log = new InstallLog(buf);
259 while (! errnum &&
260 (entry.reset(in_zip->GetNextEntry()), entry.get() != NULL) )
263 curfile++;
264 wxString name = entry->GetName();
265 progress_msg.Printf(_("Unpacking %s"), name.c_str());
266 if (! progress->Update(curfile, progress_msg) ) {
267 buf.Printf(_("Unpacking cancelled by user"));
268 MESG_DIALOG(buf);
269 errnum = 1000;
270 break;
273 in_str.Printf(wxT("%s" PATH_SEP "%s"), destdir.c_str(), name.c_str());
275 if (entry->IsDir() ) {
276 if (!wxDirExists(in_str) ) {
277 if (! wxMkdir(in_str, 0777) ) {
278 buf.Printf(_("Unable to create directory %s"),
279 in_str.c_str() );
280 errnum = 100;
281 break;
284 log->WriteFile(name, true); // Directory
285 continue;
288 wxFFileOutputStream* out = new wxFFileOutputStream(in_str);
289 if (! out->IsOk() )
291 buf.Printf(_("Can't open file %s for writing"), in_str.c_str() );
292 delete out;
293 return 100;
294 } else if (isInstall)
296 log->WriteFile(name);
299 in_zip->Read(*out);
300 if (! out->IsOk()) {
301 buf.Printf(_("Can't write to %s (%d)"), in_str.c_str(),
302 errnum = out->GetLastError() );
305 if (!in_zip->IsOk() && ! in_file->GetLastError() == wxSTREAM_EOF)
307 buf.Printf(_("Can't read from %s (%d)"), src.c_str(),
308 errnum = in_file->GetLastError() );
311 if (! out->Close() && errnum == 0)
313 buf.Printf(_("Unable to close %s (%d)"), in_str.c_str(),
314 errnum = out->GetLastError() );
318 delete out;
322 delete in_zip; delete in_file; delete progress;
324 if (errnum)
326 ERR_DIALOG(buf, _("Unzip File"));
329 if (log) delete log;
330 wxLogVerbose(_("=== end UnzipFile"));
331 return(errnum);
334 int Uninstall(const wxString dir, bool isFullUninstall) {
335 wxString buf, uninst;
336 bool gooddata = false;
337 unsigned int i;
338 bool errflag = false;
339 InstallLog *log = NULL;
340 wxArrayString* FilesToRemove = NULL;
342 wxLogVerbose(_("=== begin Uninstall(%s,%i)"), dir.c_str(), isFullUninstall);
344 wxProgressDialog* progress = new wxProgressDialog(_("Uninstalling"),
345 _("Reading uninstall data from jukebox"), 100, NULL,
346 wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_SMOOTH |
347 wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME | wxPD_CAN_ABORT);
348 progress->Update(0);
350 if (! isFullUninstall)
353 buf.Printf(wxT("%s" PATH_SEP UNINSTALL_FILE), dir.c_str());
354 log = new InstallLog(buf, false); // Don't create the log
355 FilesToRemove = log->GetInstalledFiles();
356 if (log) delete log;
358 if (FilesToRemove == NULL || FilesToRemove->GetCount() < 1) {
359 wxLogNull lognull;
360 if ( wxMessageDialog(NULL,
361 _("Rockbox Utility can't find any uninstall data on this "
362 "jukebox.\n"
363 "Would you like to attempt a full uninstall?\n"
364 "(WARNING: A full uninstall removes all files in your Rockbox "
365 "folder)"),
366 _("Standard uninstall not possible"),
367 wxICON_EXCLAMATION | wxYES_NO | wxNO_DEFAULT).ShowModal()
368 == wxID_YES)
370 isFullUninstall = true;
372 else {
373 MESG_DIALOG(_("Uninstall cancelled by user"));
374 delete progress;
375 return 1000;
380 if (isFullUninstall )
382 buf.Printf(wxT("%s" PATH_SEP ".rockbox"), dir.c_str());
383 if (rm_rf(buf) )
385 WARN_DIALOG(_("Unable to completely remove Rockbox directory"),
386 _("Full uninstall") );
387 errflag = true;
390 wxDir* root = new wxDir(dir);
391 wxArrayString* special = new wxArrayString();
392 // Search for files for deletion in the jukebox root
393 for (i = 0; i < rootmatch->GetCount(); i++)
395 const wxString match = (*rootmatch)[i];
396 root->GetAllFiles(dir, special, match, wxDIR_FILES);
398 delete root;
400 // Sort in reverse order so we get directories last
401 special->Sort(true);
403 for (i = 0; i < special->GetCount(); i++)
406 if (wxDirExists((*special)[i]) )
408 // We don't check the return code since we don't want non
409 // empty dirs disappearing.
410 wxRmdir((*special)[i]);
412 } else if (wxFileExists((*special)[i]) )
414 if (! wxRemoveFile((*special)[i]) )
416 buf.Printf(_("Can't delete %s"), (*special)[i].c_str());
417 WARN_DIALOG(buf.c_str(), _("Full uninstall"));
418 errflag = true;
421 // Otherwise there isn't anything there, so we don't have to worry.
423 delete special;
424 } else
426 wxString instplat, this_path_sep;
427 unsigned int totalfiles, rc;
428 totalfiles = FilesToRemove->GetCount();
429 FilesToRemove->Sort(true); // Reverse alphabetical ie dirs after files
431 for (i = 0; i < totalfiles; i++)
433 // If we're running on the device, let's not delete our own
434 // installation, eh?
435 if (gv->portable &&
436 FilesToRemove->Item(i).StartsWith(wxT(PATH_SEP
437 "RockboxUtility")) )
439 continue;
442 wxString* buf2 = new wxString;
443 buf.Printf("%s%s", dir.c_str() , FilesToRemove->Item(i).c_str() );
444 buf2->Format(_("Deleting %s"), buf.c_str());
446 if (! progress->Update((i + 1) * 100 / totalfiles, *buf2) )
448 WARN_DIALOG(_("Cancelled by user"), _("Normal Uninstall"));
449 delete progress;
450 return true;
453 if (wxDirExists(buf) )
455 // If we're about to attempt to remove .rockbox. delete
456 // install data first
457 buf2->Printf(wxT("%s" PATH_SEP ".rockbox"), dir.c_str() );
458 if ( buf.IsSameAs(buf2->c_str()) )
460 buf2->Printf(wxT("%s" PATH_SEP UNINSTALL_FILE), dir.c_str());
461 wxRemoveFile(*buf2);
464 if ( rc = ! wxRmdir(buf) )
466 buf = buf.Format(_("Can't remove directory %s"),
467 buf.c_str());
468 errflag = true;
469 WARN_DIALOG(buf.c_str(), _("Standard uninstall"));
471 } else if (wxFileExists(buf) )
473 if ( rc = ! wxRemoveFile(buf) )
475 buf = buf.Format(_("Can't delete file %s"),
476 buf.c_str());
477 errflag = true;
478 WARN_DIALOG(buf.c_str(), _("Standard uninstall"));
480 } else
482 errflag = true;
483 buf = buf.Format(_("Can't find file or directory %s"),
484 buf.c_str() );
485 WARN_DIALOG(buf.c_str(), _("Standard uninstall") );
488 uninst = uninst.AfterFirst('\n');
490 if (errflag)
492 ERR_DIALOG(_("Unable to remove some files"),
493 _("Standard uninstall")) ;
496 if (FilesToRemove != NULL) delete FilesToRemove;
499 delete progress;
500 wxLogVerbose(_("=== end Uninstall"));
501 return errflag;
505 wxString stream_err_str(int errnum)
507 wxString out;
509 switch (errnum) {
510 case wxSTREAM_NO_ERROR:
511 out = wxT("wxSTREAM_NO_ERROR");
512 break;
513 case wxSTREAM_EOF:
514 out = wxT("wxSTREAM_EOF");
515 break;
516 case wxSTREAM_WRITE_ERROR:
517 out = wxT("wxSTREAM_WRITE_ERROR");
518 break;
519 case wxSTREAM_READ_ERROR:
520 out = wxT("wxSTREAM_READ_ERROR");
521 break;
522 default:
523 out = wxT("UNKNOWN");
524 break;
526 return out;
529 bool InstallRbutil(wxString dest)
531 wxArrayString filestocopy;
532 wxString str, buf, dstr, localpath, destdir;
533 unsigned int i;
534 wxDir dir;
535 bool copied_exe = false, made_rbdir = false;
536 InstallLog* log;
538 buf.Printf(wxT("%s" PATH_SEP ".rockbox"), dest.c_str() );
540 if (! wxDirExists(buf) )
542 wxMkdir(buf);
543 made_rbdir = true;
546 buf.Printf(wxT("%s" PATH_SEP UNINSTALL_FILE), dest.c_str() );
547 log = new InstallLog(buf);
548 if (made_rbdir) log->WriteFile(wxT(".rockbox"), true);
550 destdir.Printf(wxT("%s" PATH_SEP "RockboxUtility"), dest.c_str());
551 if (! wxDirExists(destdir) )
553 if (! wxMkdir(destdir, 0777) )
555 buf.Printf(wxT("%s (%s)"),
556 _("Unable to create directory for installer"), destdir.c_str());
557 WARN_DIALOG(buf , _("Portable install") );
558 return false;
560 log->WriteFile(wxT("RockboxUtility"), true);
563 dir.GetAllFiles(gv->ResourceDir, &filestocopy, wxT("*"),
564 wxDIR_FILES);
565 if (filestocopy.GetCount() < 1)
567 WARN_DIALOG(_("No files to copy"), _("Portable install") );
568 return false;
571 // Copy the contents of the program directory
572 for (i = 0; i < filestocopy.GetCount(); i++)
574 if (filestocopy[i].AfterLast(PATH_SEP_CHR) == EXE_NAME)
576 copied_exe = true;
579 dstr.Printf(wxT("%s" PATH_SEP "%s"), destdir.c_str(),
580 filestocopy[i].AfterLast(PATH_SEP_CHR).c_str());
581 if (! wxCopyFile(filestocopy[i], dstr) )
583 buf.Printf(wxT("%s (%s -> %s)"),
584 _("Error copying file"), filestocopy[i].c_str(), dstr.c_str());
585 WARN_DIALOG(buf, _("Portable Install") );
586 return false;
588 buf = dstr;
589 buf.Replace(dest, wxEmptyString, false);
590 log->WriteFile(buf);
593 if (! copied_exe)
595 str.Printf(wxT("%s" PATH_SEP EXE_NAME), gv->AppDir.c_str());
596 dstr.Printf(wxT("%s" PATH_SEP EXE_NAME), destdir.c_str(),
597 filestocopy[i].AfterLast(PATH_SEP_CHR).c_str());
598 if (! wxCopyFile(str, dstr) )
600 buf.Printf(wxT("Can't copy program binary %s -> %s"),
601 str.c_str(), dstr.c_str() );
602 WARN_DIALOG(buf, _("Portable Install") );
603 return false;
605 buf = dstr;
606 buf.Replace(dest, wxEmptyString, false);
607 log->WriteFile(buf);
610 // Copy the local ini file so that it knows that it's a portable copy
611 gv->UserConfig->Flush();
612 dstr.Printf(wxT("%s" PATH_SEP "RockboxUtility.cfg"), destdir.c_str());
613 if (! wxCopyFile(gv->UserConfigFile, dstr) )
615 buf.Printf(wxT("%s (%s -> %s)"),
616 _("Unable to install user config file"), gv->UserConfigFile.c_str(),
617 dstr.c_str() );
618 WARN_DIALOG(buf, _("Portable Install") );
619 return false;
621 buf = dstr;
622 buf.Replace(dest, wxEmptyString, false);
623 log->WriteFile(buf);
625 delete log;
626 return true;
629 bool rm_rf(wxString file)
631 wxLogVerbose(_("=== begin rm-rf(%s)"), file.c_str() );
633 wxString buf;
634 wxArrayString selected;
635 wxDirTraverserIncludeDirs wxdtid(selected);
636 unsigned int rc = 0, i;
637 bool errflag = false;
639 if (wxFileExists(file) )
641 rc = ! wxRemoveFile(file);
642 } else if (wxDirExists(file) )
644 wxDir* dir = new wxDir(file);;
645 dir->Traverse(wxdtid);
646 delete dir;
647 // Sort into reverse alphabetical order for deletion in correct order
648 // (directories after files)
649 selected.Sort(true);
650 selected.Add(file);
652 wxProgressDialog* progress = new wxProgressDialog(_("Removing files"),
653 _("Deleting files"), selected.GetCount(), NULL,
654 wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_SMOOTH |
655 wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME | wxPD_CAN_ABORT);
657 for (i = 0; i < selected.GetCount(); i++)
659 wxLogVerbose(selected[i]);
660 if (progress != NULL)
662 buf.Printf(_("Deleting %s"), selected[i].c_str() );
663 if (! progress->Update(i, buf))
665 WARN_DIALOG(_("Cancelled by user"), _("Erase Files"));
666 delete progress;
667 return true;
671 if (wxDirExists(selected[i]) )
673 if (rc = ! wxRmdir(selected[i]) )
675 buf.Printf(_("Can't remove directory %s"),
676 selected[i].c_str());
677 errflag = true;
678 WARN_DIALOG(buf.c_str(), _("Erase files"));
680 } else if (rc = ! wxRemoveFile(selected[i]) )
682 buf.Printf(_("Error deleting file %s"), selected[i].c_str() );
683 errflag = true;
684 WARN_DIALOG(buf.c_str(),_("Erase files"));
687 delete progress;
688 } else
690 buf.Printf(_("Can't find expected file %s"), file.c_str());
691 WARN_DIALOG(buf.c_str(), _("Erase files"));
692 return true;
695 wxLogVerbose(_("=== end rm-rf"));
696 return rc ? true : false;