source: ps2launchargs/source/uLaunchELF/filer.c@ 1171

Last change on this file since 1171 was 1101, checked in by iritscen, 7 years ago

Added following to ps2launchargs:\n-Source code.\n-DLL needed to run ps2client.\n-Instructions for building uLaunchELF.

  • Property svn:executable set to *
File size: 136.3 KB
RevLine 
[1101]1//--------------------------------------------------------------
2//File name: filer.c
3//--------------------------------------------------------------
4#include "launchelf.h"
5
6typedef struct
7{
8 unsigned char unknown;
9 unsigned char sec; // date/time (second)
10 unsigned char min; // date/time (minute)
11 unsigned char hour; // date/time (hour)
12 unsigned char day; // date/time (day)
13 unsigned char month; // date/time (month)
14 unsigned short year; // date/time (year)
15} PS2TIME __attribute__((aligned (2)));
16
17#define MC_SFI 0xFEED //flag value used for mcSetFileInfo at MC file restoration
18
19#define MC_ATTR_norm_folder 0x8427 //Normal folder on PS2 MC
20#define MC_ATTR_prot_folder 0x842F //Protected folder on PS2 MC
21#define MC_ATTR_PS1_folder 0x9027 //PS1 save folder on PS2 MC
22#define MC_ATTR_norm_file 0x8497 //file (PS2/PS1) on PS2 MC
23#define MC_ATTR_PS1_file 0x9417 //PS1 save file on PS1 MC
24
25#define IOCTL_RENAME 0xFEEDC0DE //Ioctl request code for Rename function
26
27enum
28{
29 COPY,
30 CUT,
31 PASTE,
32 MCPASTE,
33 PSUPASTE,
34 DELETE,
35 RENAME,
36 NEWDIR,
37 NEWICON,
38 MOUNTVMC0,
39 MOUNTVMC1,
40 GETSIZE,
41 NUM_MENU
42} R1_menu_enum;
43
44#define PM_NORMAL 0 //PasteMode value for normal copies
45#define PM_MC_BACKUP 1 //PasteMode value for gamesave backup from MC
46#define PM_MC_RESTORE 2 //PasteMode value for gamesave restore to MC
47#define PM_PSU_BACKUP 3 //PasteMode value for gamesave backup from MC to PSU
48#define PM_PSU_RESTORE 4 //PasteMode value for gamesave restore to MC from PSU
49#define PM_RENAME 5 //PasteMode value for normal copies with new names
50#define MAX_RECURSE 16 //Maximum folder recursion for MC Backup/Restore
51
52int PasteProgress_f = 0; //Flags progress report having been made in Pasting
53int PasteMode; //Top-level PasteMode flag
54int PM_flag[MAX_RECURSE]; //PasteMode flag for each 'copy' recursion level
55int PM_file[MAX_RECURSE]; //PasteMode attribute file descriptors
56
57char mountedParty[MOUNT_LIMIT][MAX_NAME];
58int latestMount = -1;
59int vmcMounted[2] = {0, 0}; //flags true for mounted VMC false for unmounted
60int vmc_PartyIndex[2] = {-1, -1}; //PFS index for each VMC, unless -1
61int Party_vmcIndex[MOUNT_LIMIT] = {-1,-1,-1,-1}; //VMC for each PFS, unless -1
62unsigned char *elisaFnt=NULL;
63int elisa_failed = FALSE; //Set at failure to load font, cleared at browser entry
64s64 freeSpace;
65int mcfreeSpace;
66int mctype_PSx; //dlanor: Needed for proper scaling of mcfreespace
67int vfreeSpace; //flags validity of freespace value
68int browser_cut;
69int nclipFiles, nmarks, nparties;
70int file_show = 1; //dlanor: 0==name_only, 1==name+size+time, 2==title+size+time
71int file_sort = 1; //dlanor: 0==none, 1==name, 2==title, 3==mtime
72int size_valid = 0;
73int time_valid = 0;
74char parties[MAX_PARTITIONS][MAX_NAME];
75char clipPath[MAX_PATH], LastDir[MAX_NAME], marks[MAX_ENTRY];
76FILEINFO clipFiles[MAX_ENTRY];
77int fileMode = FIO_S_IRUSR | FIO_S_IWUSR | FIO_S_IXUSR | FIO_S_IRGRP | FIO_S_IWGRP | FIO_S_IXGRP | FIO_S_IROTH | FIO_S_IWOTH | FIO_S_IXOTH;
78
79char cnfmode_extU[CNFMODE_CNT][4] = {
80 "*", // cnfmode FALSE
81 "ELF", // cnfmode TRUE
82 "IRX", // cnfmode USBD_IRX_CNF
83 "JPG", // cnfmode SKIN_CNF
84 "JPG", // cnfmode GUI_SKIN_CNF
85 "IRX", // cnfmode USBKBD_IRX_CNF
86 "KBD", // cnfmode KBDMAP_FILE_CNF
87 "CNF", // cnfmode CNF_PATH_CNF
88 "*", // cnfmode TEXT_CNF
89 "", // cnfmode DIR_CNF
90 "JPG", // cnfmode JPG_CNF
91 "IRX", // cnfmode USBMASS_IRX_CNF
92 "LNG", // cnfmode LANG_CNF
93 "FNT", // cnfmode FONT_CNF
94 "*" // cnfmode SAVE_CNF
95};
96
97char cnfmode_extL[CNFMODE_CNT][4] = {
98 "*", // cnfmode FALSE
99 "elf", // cnfmode TRUE
100 "irx", // cnfmode USBD_IRX_CNF
101 "jpg", // cnfmode SKIN_CNF
102 "jpg", // cnfmode GUI_SKIN_CNF
103 "irx", // cnfmode USBKBD_IRX_CNF
104 "kbd", // cnfmode KBDMAP_FILE_CNF
105 "cnf", // cnfmode CNF_PATH_CNF
106 "*", // cnfmode TEXT_CNF
107 "", // cnfmode DIR_CNF
108 "jpg", // cnfmode JPG_CNF
109 "irx", // cnfmode USBMASS_IRX_CNF
110 "lng", // cnfmode LANG_CNF
111 "fnt", // cnfmode FONT_CNF
112 "*" // cnfmode SAVE_CNF
113};
114
115int host_ready = 0;
116int host_error = 0;
117int host_elflist = 0;
118int host_use_Bsl = 1; //By default assume that host paths use backslash
119
120unsigned long written_size; //Used for pasting progress report
121u64 PasteTime; //Used for pasting progress report
122
123typedef struct {
124 u8 unused;
125 u8 sec;
126 u8 min;
127 u8 hour;
128 u8 day;
129 u8 month;
130 u16 year;
131} ps2time;
132
133typedef struct { //Offs: Example content
134 ps2time cTime; //0x00: 8 bytes creation timestamp (struct above)
135 ps2time mTime; //0x08: 8 bytes modification timestamp (struct above)
136 u32 size; //0x10: file size
137 u16 attr; //0x14: 0x8427 (=normal folder, 8497 for normal file)
138 u16 unknown_1_u16; //0x16: 2 zero bytes
139 u64 unknown_2_u64; //0x18: 8 zero bytes
140 u8 name[32]; //0x20: 32 name bytes, padded with zeroes
141} mcT_header __attribute__((aligned (64)));
142
143typedef struct { //Offs: Example content
144 u16 attr; //0x00: 0x8427 (=normal folder, 8497 for normal file)
145 u16 unknown_1_u16; //0x02: 2 zero bytes
146 u32 size; //0x04: header_count-1, file size, 0 for pseudo
147 ps2time cTime; //0x08: 8 bytes creation timestamp (struct above)
148 u64 EMS_used_u64; //0x10: 8 zero bytes (but used by EMS)
149 ps2time mTime; //0x18: 8 bytes modification timestamp (struct above)
150 u64 unknown_2_u64; //0x20: 8 bytes from mcTable
151 u8 unknown_3_24_bytes[24]; //0x28: 24 zero bytes
152 u8 name[32]; //0x40: 32 name bytes, padded with zeroes
153 u8 unknown_4_416_bytes[0x1A0]; //0x60: zero byte padding to reach 0x200 size
154} psu_header; //0x200: End of psu_header struct
155
156int PSU_content; //Used to count PSU content headers for the main header
157
158//USB_mass definitions for multiple drive usage
159char USB_mass_ix[10] = {'0',0,0,0,0,0,0,0,0,0};
160int USB_mass_max_drives = USB_MASS_MAX_DRIVES;
161u64 USB_mass_scan_time = 0;
162int USB_mass_scanned = 0; //0==Not_found_OR_No_Multi 1==found_Multi_mass_once
163int USB_mass_loaded = 0; //0==none, 1==internal, 2==external
164
165
166//char debugs[4096]; //For debug display strings. Comment it out when unused
167//--------------------------------------------------------------
168//executable code
169//--------------------------------------------------------------
170void clear_mcTable(mcTable *mcT)
171{
172 memset((void *) mcT, 0, sizeof(mcTable));
173}
174//--------------------------------------------------------------
175void clear_psu_header(psu_header *psu)
176{
177 memset((void *) psu, 0, sizeof(psu_header));
178}
179//--------------------------------------------------------------
180void pad_psu_header(psu_header *psu)
181{
182 memset((void *) psu, 0xFF, sizeof(psu_header));
183}
184//--------------------------------------------------------------
185// getHddParty below takes as input the string path and the struct file
186// and uses these to calculate the output strings party and dir. If the
187// file struct is not passed as NULL, then its file->name entry will be
188// added to the internal copy of the path string (which remains unchanged),
189// and if that file struct entry is for a folder, then a slash is also added.
190// The modified path is then used to calculate the output strings as follows.
191//-----
192// party = the full path string with "hdd0:" and partition spec, but without
193// the slash character between them, used in user specified full paths. So
194// the first slash in that string will come after the partition name.
195//-----
196// dir = the pfs path string, starting like "pfs0:" (but may use different
197// pfs index), and this is then followed by the path within that partition.
198// Note that despite the name 'dir', this is also used for files.
199//-----
200//NB: From the first slash character those two strings are identical when
201// both are used, but either pointer may be set to NULL in the function call,
202// as an indication that the caller isn't interested in that part.
203//--------------------------------------------------------------
204int getHddParty(const char *path, const FILEINFO *file, char *party, char *dir)
205{
206 char fullpath[MAX_PATH], *p;
207
208 if(strncmp(path,"hdd",3)) return -1;
209
210 strcpy(fullpath, path);
211 if(file!=NULL){
212 strcat(fullpath, file->name);
213 if(file->stats.attrFile & MC_ATTR_SUBDIR) strcat(fullpath,"/");
214 }
215 if((p=strchr(&fullpath[6], '/'))==NULL) return -1;
216 if(dir!=NULL) sprintf(dir, "pfs0:%s", p);
217 *p=0;
218 if(party!=NULL) sprintf(party, "hdd0:%s", &fullpath[6]);
219
220 return 0;
221}
222//--------------------------------------------------------------
223int mountParty(const char *party)
224{
225 int i, j;
226 char pfs_str[6];
227
228 for(i=0; i<MOUNT_LIMIT; i++){ //Here we check already mounted PFS indexes
229 if(!strcmp(party, mountedParty[i]))
230 goto return_i;
231 }
232
233 for(i=0, j=-1; i<MOUNT_LIMIT; i++){ //Here we search for a free PFS index
234 if(mountedParty[i][0] == 0){
235 j=i;
236 break;
237 }
238 }
239
240 if(j == -1){ //Here we search for a suitable PFS index to unmount
241 for(i=0; i<MOUNT_LIMIT; i++){
242 if((i!=latestMount) && (Party_vmcIndex[i]<0)){
243 j=i;
244 break;
245 }
246 }
247 unmountParty(j);
248 }
249 //Here j is the index of a free PFS mountpoint
250 //But 'free' only means that the main uLE program isn't using it
251 //If the ftp server is running, that may have used the mountpoints
252
253 //RA NB: The old code to reclaim FTP partitions was seriously bugged...
254
255 i = j;
256 strcpy(pfs_str, "pfs0:");
257
258 pfs_str[3] = '0'+i;
259 if(fileXioMount(pfs_str, party, FIO_MT_RDWR) < 0){ //if FTP stole it
260 for(i=0; i<=4; i++){ //for loop to kill FTP partition mountpoints
261 if((i!=latestMount) && (Party_vmcIndex[i]<0)){ //if unneeded by uLE
262 unmountParty(i); //unmount partition mountpoint
263 pfs_str[3] = '0'+i; //prepare to reuse that mountpoint
264 if(fileXioMount(pfs_str, party, FIO_MT_RDWR) >= 0)
265 break; //break from the loop on successful mount
266 } //ends if unneeded by uLE
267 } //ends for loop to kill FTP partition mountpoints
268 //Here i indicates what happened above with the following meanings:
269 //0..4==Success after trying i mountpoints, 5==Failure
270 if(i>4)
271 return -1;
272 } //ends if clause for mountpoints stolen by FTP
273 strcpy(mountedParty[i], party);
274return_i:
275 latestMount = i;
276 return i;
277}
278//--------------------------------------------------------------
279void unmountParty(int party_ix)
280{
281 char pfs_str[6];
282
283 strcpy(pfs_str, "pfs0:");
284 pfs_str[3] += party_ix;
285 if(fileXioUmount(pfs_str) < 0)
286 return; //leave variables unchanged if unmount failed (remember true state)
287 if(party_ix < MOUNT_LIMIT){
288 mountedParty[party_ix][0] = 0;
289 }
290 if(latestMount==party_ix)
291 latestMount=-1;
292}
293//--------------------------------------------------------------
294// unmountAll can unmount all mountpoints from 0 to MOUNT_LIMIT,
295// but unlike the individual unmountParty, it will only do so
296// for mountpoints indicated as used by the matching string in
297// the string array 'mountedParty'.
298// From v4.23 this routine is also used to unmount VMC devices
299//------------------------------
300void unmountAll(void)
301{
302 char pfs_str[6];
303 char vmc_str[6];
304 int i;
305
306 strcpy(vmc_str, "vmc0:");
307 for(i=0; i<2; i++){
308 if(vmcMounted[i]){
309 vmc_str[3] = '0'+i;
310 fileXioUmount(vmc_str);
311 vmcMounted[i] = 0;
312 vmc_PartyIndex[i]=-1;
313 }
314 }
315
316 strcpy(pfs_str, "pfs0:");
317 for(i=0; i<MOUNT_LIMIT; i++){
318 Party_vmcIndex[i]=-1;
319 if(mountedParty[i][0]!=0){
320 pfs_str[3] = '0'+i;
321 fileXioUmount(pfs_str);
322 mountedParty[i][0] = 0;
323 }
324 }
325 latestMount = -1;
326} //ends unmountAll
327//--------------------------------------------------------------
328int ynDialog(const char *message)
329{
330 char msg[512];
331 int dh, dw, dx, dy;
332 int sel=0, a=6, b=4, c=2, n, tw;
333 int i, x, len, ret;
334 int event, post_event=0;
335
336 strcpy(msg, message);
337
338 for(i=0,n=1; msg[i]!=0; i++){ //start with one string at pos zero
339 if(msg[i]=='\n'){ //line separator at current pos ?
340 msg[i]=0; //split old line to separate string
341 n++; //increment string count
342 }
343 } //loop back for next character pos
344 for(i=len=tw=0; i<n; i++){ //start with string 0, assume 0 length & width
345 ret = printXY(&msg[len], 0, 0, 0, FALSE, 0); //get width of current string
346 if(ret>tw) tw=ret; //tw = largest text width of strings so far
347 len+=strlen(&msg[len])+1; //len = pos of next string start
348 }
349 if(tw<96) tw=96;
350
351 dh = FONT_HEIGHT*(n+1)+2*2+a+b+c;
352 dw = 2*2+a*2+tw;
353 dx = (SCREEN_WIDTH-dw)/2;
354 dy = (SCREEN_HEIGHT-dh)/2;
355// printf("tw=%d\ndh=%d\ndw=%d\ndx=%d\ndy=%d\n", tw,dh,dw,dx,dy);
356
357 event = 1; //event = initial entry
358 while(1){
359 //Pad response section
360 waitPadReady(0, 0);
361 if(readpad()){
362 if(new_pad & PAD_LEFT){
363 event |= 2; //event |= valid pad command
364 sel=0;
365 }else if(new_pad & PAD_RIGHT){
366 event |= 2; //event |= valid pad command
367 sel=1;
368 }else if((!swapKeys && new_pad & PAD_CROSS)
369 || (swapKeys && new_pad & PAD_CIRCLE) ){
370 ret=-1;
371 break;
372 }else if((swapKeys && new_pad & PAD_CROSS)
373 || (!swapKeys && new_pad & PAD_CIRCLE) ){
374 if(sel==0) ret=1;
375 else ret=-1;
376 break;
377 }
378 }
379
380 if(event||post_event){ //NB: We need to update two frame buffers per event
381
382 //Display section
383 drawPopSprite(setting->color[0],
384 dx, dy,
385 dx+dw, (dy+dh));
386 drawFrame(dx, dy, dx+dw, (dy+dh), setting->color[1]);
387 for(i=len=0; i<n; i++){
388 printXY(&msg[len], dx+2+a,(dy+a+2+i*16), setting->color[3],TRUE,0);
389 len+=strlen(&msg[len])+1;
390 }
391
392 //Cursor positioning section
393 x=(tw-96)/4;
394 printXY(LNG(OK), dx+a+x+FONT_WIDTH,
395 (dy+a+b+2+n*FONT_HEIGHT), setting->color[3],TRUE,0);
396 printXY(LNG(CANCEL), dx+dw-x-(strlen(LNG(CANCEL))+1)*FONT_WIDTH,
397 (dy+a+b+2+n*FONT_HEIGHT), setting->color[3],TRUE,0);
398 if(sel==0)
399 drawChar(LEFT_CUR, dx+a+x,(dy+a+b+2+n*FONT_HEIGHT), setting->color[3]);
400 else
401 drawChar(LEFT_CUR,dx+dw-x-(strlen(LNG(CANCEL))+2)*FONT_WIDTH-1,
402 (dy+a+b+2+n*FONT_HEIGHT),setting->color[3]);
403 }//ends if(event||post_event)
404 drawLastMsg();
405 post_event = event;
406 event = 0;
407 }//ends while
408 drawSprite(setting->color[0], dx, dy, dx+dw+1, (dy+dh)+1);
409 drawScr();
410 drawSprite(setting->color[0], dx, dy, dx+dw+1, (dy+dh)+1);
411 drawScr();
412 return ret;
413}
414//------------------------------
415//endfunc ynDialog
416//--------------------------------------------------------------
417void nonDialog(char *message)
418{
419 char msg[80*30]; //More than this can't be shown on screen, even in PAL
420 static int dh, dw, dx, dy; //These are static, to allow cleanup
421 int a=6, b=4, c=2, n, tw;
422 int i, len, ret;
423
424 if(message==NULL){ //NULL message means cleanup for last nonDialog
425 drawSprite(setting->color[0],
426 dx, dy,
427 dx+dw, (dy+dh));
428 return;
429 }
430
431 strcpy(msg, message);
432
433 for(i=0,n=1; msg[i]!=0; i++){ //start with one string at pos zero
434 if(msg[i]=='\n'){ //line separator at current pos ?
435 msg[i]=0; //split old line to separate string
436 n++; //increment string count
437 }
438 } //loop back for next character pos
439 for(i=len=tw=0; i<n; i++){ //start with string 0, assume 0 length & width
440 ret = printXY(&msg[len], 0, 0, 0, FALSE,0); //get width of current string
441 if(ret>tw) tw=ret; //tw = largest text width of strings so far
442 len+=strlen(&msg[len])+1; //len = pos of next string start
443 }
444 if(tw<96) tw=96;
445
446 dh = 16*n+2*2+a+b+c;
447 dw = 2*2+a*2+tw;
448 dx = (SCREEN_WIDTH-dw)/2;
449 dy = (SCREEN_HEIGHT-dh)/2;
450 //printf("tw=%d\ndh=%d\ndw=%d\ndx=%d\ndy=%d\n", tw,dh,dw,dx,dy);
451
452 drawPopSprite(setting->color[0],
453 dx, dy,
454 dx+dw, (dy+dh));
455 drawFrame(dx, dy, dx+dw, (dy+dh), setting->color[1]);
456 for(i=len=0; i<n; i++){
457 printXY(&msg[len], dx+2+a,(dy+a+2+i*FONT_HEIGHT), setting->color[3],TRUE,0);
458 len+=strlen(&msg[len])+1;
459 }
460}
461//------------------------------
462//endfunc nonDialog
463//--------------------------------------------------------------
464// cmpFile below returns negative if the 'a' entry is 'lower'
465// than the 'b' entry, normally meaning that 'a' should be in
466// a higher/earlier screen position than 'b'. Such negative
467// return value causes the calling sort routine to adjust the
468// entry order, which does not occur for other return values.
469//--------------------------------------------------------------
470int cmpFile(FILEINFO *a, FILEINFO *b) //Used for directory sort
471{
472 unsigned char *p, ca, cb;
473 int i, n, ret, aElf=FALSE, bElf=FALSE, t=(file_sort==2);
474
475 if(file_sort == 0) return 0; //return 0 for unsorted mode
476
477 if((a->stats.attrFile & MC_ATTR_OBJECT) == (b->stats.attrFile & MC_ATTR_OBJECT)){
478 if(a->stats.attrFile & MC_ATTR_FILE){
479 p = strrchr(a->name, '.');
480 if(p!=NULL && !stricmp(p+1, "ELF")) aElf=TRUE;
481 p = strrchr(b->name, '.');
482 if(p!=NULL && !stricmp(p+1, "ELF")) bElf=TRUE;
483 if(aElf && !bElf) return -1;
484 else if(!aElf && bElf) return 1;
485 }
486 if(file_sort == 3){ //Sort by timestamp
487 t=(file_show==2); //Set secondary sort criterion
488 if(time_valid){
489 u64 time_a = *(u64 *) &a->stats._modify;
490 u64 time_b = *(u64 *) &b->stats._modify;
491 if(time_a > time_b) return -1; //NB: reversed comparison for falling order
492 if(time_a < time_b) return 1;
493 }
494 }
495 if(t){
496 if(a->title[0]!=0 && b->title[0]==0) return -1;
497 else if(a->title[0]==0 && b->title[0]!=0) return 1;
498 else if(a->title[0]==0 && b->title[0]==0) t=FALSE;
499 }
500 if(t) n=strlen(a->title);
501 else n=strlen(a->name);
502 for(i=0; i<=n; i++){
503 if(t){
504 ca=a->title[i]; cb=b->title[i];
505 }else{
506 ca=a->name[i]; cb=b->name[i];
507 if(ca>='a' && ca<='z') ca-=0x20;
508 if(cb>='a' && cb<='z') cb-=0x20;
509 }
510 ret = ca-cb;
511 if(ret!=0) return ret;
512 }
513 return 0;
514 }
515
516 if(a->stats.attrFile & MC_ATTR_SUBDIR) return -1;
517 else return 1;
518}
519//--------------------------------------------------------------
520void sort(FILEINFO *a, int left, int right) {
521 FILEINFO tmp, pivot;
522 int i, p;
523
524 if (left < right) {
525 pivot = a[left];
526 p = left;
527 for (i=left+1; i<=right; i++) {
528 if (cmpFile(&a[i],&pivot)<0){
529 p=p+1;
530 tmp=a[p];
531 a[p]=a[i];
532 a[i]=tmp;
533 }
534 }
535 a[left] = a[p];
536 a[p] = pivot;
537 sort(a, left, p-1);
538 sort(a, p+1, right);
539 }
540}
541//--------------------------------------------------------------
542int readMC(const char *path, FILEINFO *info, int max)
543{
544 static mcTable mcDir[MAX_ENTRY] __attribute__((aligned(64)));
545 char dir[MAX_PATH];
546 int i, j, ret;
547
548 mcSync(0,NULL,NULL);
549
550 mcGetInfo(path[2]-'0', 0, &mctype_PSx, NULL, NULL);
551 mcSync(0, NULL, &ret);
552 if (mctype_PSx == 2) //PS2 MC ?
553 time_valid = 1;
554 size_valid = 1;
555
556 strcpy(dir, &path[4]); strcat(dir, "*");
557 mcGetDir(path[2]-'0', 0, dir, 0, MAX_ENTRY-2, (mcTable *) mcDir);
558 mcSync(0, NULL, &ret);
559
560 for(i=j=0; i<ret; i++)
561 {
562 if(mcDir[i].attrFile & MC_ATTR_SUBDIR &&
563 (!strcmp(mcDir[i].name,".") || !strcmp(mcDir[i].name,"..")))
564 continue; //Skip pseudopaths "." and ".."
565 strcpy(info[j].name, mcDir[i].name);
566 info[j].stats = mcDir[i];
567 j++;
568 }
569
570 return j;
571}
572//------------------------------
573//endfunc readMC
574//--------------------------------------------------------------
575int readCD(const char *path, FILEINFO *info, int max)
576{
577 static struct TocEntry TocEntryList[MAX_ENTRY];
578 char dir[MAX_PATH];
579 int i, j, n;
580 u64 wait_start;
581
582 loadCdModules();
583 if(cdGetDiscType() <= CDVD_TYPE_UNKNOWN){
584 wait_start = Timer();
585 while((Timer() < wait_start+500) && !uLE_cdDiscValid()){
586 if(cdmode == CDVD_TYPE_NODISK)
587 return 0;
588 }
589 if(cdmode == CDVD_TYPE_NODISK)
590 return 0;
591 if((cdmode < CDVD_TYPE_PS1CD) || (cdmode > CDVD_TYPE_PS2DVD)){
592 if(setting->discControl)
593 uLE_cdStop();
594 return 0;
595 }
596 }
597
598 strcpy(dir, &path[5]);
599 CDVD_FlushCache();
600 n = CDVD_GetDir(dir, NULL, CDVD_GET_FILES_AND_DIRS, TocEntryList, MAX_ENTRY, dir);
601
602 for(i=j=0; i<n; i++)
603 {
604 if(TocEntryList[i].fileProperties & 0x02 &&
605 (!strcmp(TocEntryList[i].filename,".") ||
606 !strcmp(TocEntryList[i].filename,"..")))
607 continue; //Skip pseudopaths "." and ".."
608 strcpy(info[j].name, TocEntryList[i].filename);
609 clear_mcTable(&info[j].stats);
610 if(TocEntryList[i].fileProperties & 0x02){
611 info[j].stats.attrFile = MC_ATTR_norm_folder;
612 }
613 else{
614 info[j].stats.attrFile = MC_ATTR_norm_file;
615 info[j].stats.fileSizeByte = TocEntryList[i].fileSize;
616 }
617 j++;
618 }
619
620 size_valid = 1;
621
622 return j;
623}
624//------------------------------
625//endfunc readCD
626//--------------------------------------------------------------
627void setPartyList(void)
628{
629 iox_dirent_t dirEnt;
630 int hddFd;
631
632 nparties=0;
633
634 if((hddFd=fileXioDopen("hdd0:")) < 0)
635 return;
636 while(fileXioDread(hddFd, &dirEnt) > 0)
637 {
638 if(nparties >= MAX_PARTITIONS)
639 break;
640 if((dirEnt.stat.attr != ATTR_MAIN_PARTITION)
641 || (dirEnt.stat.mode != FS_TYPE_PFS))
642 continue;
643
644 //Patch this to see if new CB versions use valid PFS format
645 //NB: All CodeBreaker versions up to v9.3 use invalid formats
646 if(!strncmp(dirEnt.name, "PP.",3)){
647 int len = strlen(dirEnt.name);
648 if(!strcmp(dirEnt.name+len-4, ".PCB"))
649 continue;
650 }
651
652 if(!strncmp(dirEnt.name, "__", 2) &&
653 strcmp(dirEnt.name, "__boot") &&
654 strcmp(dirEnt.name, "__net") &&
655 strcmp(dirEnt.name, "__system") &&
656 strcmp(dirEnt.name, "__sysconf") &&
657 strcmp(dirEnt.name, "__common"))
658 continue;
659
660 strcpy(parties[nparties++], dirEnt.name);
661 }
662 fileXioDclose(hddFd);
663}
664//--------------------------------------------------------------
665// The following group of file handling functions are used to allow
666// the main program to access files without having to deal with the
667// difference between fio and fileXio devices directly in each call.
668// Even so, paths for fileXio are assumed to be already prepared so
669// as to be accepted by fileXio calls (so HDD file access use "pfs")
670// Generic functions for this purpose that have been added so far are:
671// genInit(void), genLimObjName(uLE_path, reserve),
672// genFixPath(uLE_path, gen_path),
673// genOpen(path, mode), genClose(fd), genDopen(path), genDclose(fd),
674// genLseek(fd,where,how), genRead(fd,buf,size), genWrite(fd,buf,size)
675// genRemove(path), genRmdir(path)
676//--------------------------------------------------------------
677int gen_fd[256]; //Allow up to 256 generic file handles
678int gen_io[256]; //For each handle, also memorize io type
679//--------------------------------------------------------------
680void genInit(void)
681{
682 int i;
683
684 for(i=0; i<256; i++)
685 gen_fd[i] = -1;
686}
687//------------------------------
688//endfunc genInit
689//--------------------------------------------------------------
690void genLimObjName(char *uLE_path, int reserve)
691{
692 char *p, *q, *r;
693 int limit = 256; //enforce a generic limit of 256 characters
694 int folder_flag = (uLE_path[strlen(uLE_path)-1] == '/'); //flag folder object
695 int overflow;
696
697 if(!strncmp(uLE_path, "mc", 2) || !strncmp(uLE_path, "vmc", 3))
698 limit = 32; //enforce MC limit of 32 characters
699
700 if(folder_flag) //if path ends with path separator
701 uLE_path[strlen(uLE_path)-1]=0; // remove final path separator (temporarily)
702
703 p = uLE_path; //initially assume a pure object name (quite insanely :))
704 if((q=strchr(p, ':')) != NULL) //if a drive separator is present
705 p = q+1; // object name may start after drive separator
706 if((q=strrchr(p, '/')) != NULL) //If there's any path separator in the string
707 p = q+1; // object name starts after last path separator
708 limit -= reserve; //lower limit by reserved character space
709 overflow = strlen(p)-limit; //Calculate length of string to remove (if positive)
710 if((limit<=0)||(overflow<=0)) //if limit invalid, or not exceeded
711 goto limited; // no further limitation is needed
712 if((q=strrchr(p, '.')) == NULL) //if there's no extension separator
713 goto limit_end; //limitation must be done at end of full name
714 r = q-overflow; //r is the place to recopy file extension
715 if(r > p){ //if this place is above string start
716 strcpy(r, q); //remove overflow from end of prefix part
717 goto limited; //which concludes the limitation
718 }//if we fall through here, the prefix part was too short for the limitation needed
719limit_end:
720 p[limit] = 0; // remove overflow from end of full name
721limited:
722
723 if(folder_flag) //if original path ended with path separator
724 strcat(uLE_path, "/"); // reappend final path separator after name
725}
726//------------------------------
727//endfunc genLimObjName
728//--------------------------------------------------------------
729int genFixPath(char *inp_path, char *gen_path)
730{
731 char uLE_path[MAX_PATH], loc_path[MAX_PATH], party[MAX_NAME], *p;
732 char *pathSep;
733 int part_ix;
734
735 part_ix = 99; //Assume valid non-HDD path
736 if( !uLE_related(uLE_path, inp_path) )
737 part_ix = -99; //Assume invalid uLE_related path
738 strcpy(gen_path, uLE_path); //Assume no path patching needed
739 pathSep = strchr(uLE_path, '/');
740
741 if(!strncmp(uLE_path, "cdfs", 4)){ //if using CD or DVD disc path
742 loadCdModules();
743 CDVD_FlushCache();
744 CDVD_DiskReady(0);
745 //end of clause for using a CD or DVD path
746
747 } else if(!strncmp(uLE_path, "mass", 4)){ //if using USB mass: path
748 loadUsbModules();
749
750 if(pathSep && (pathSep-uLE_path<7) && pathSep[-1]==':')
751 strcpy(gen_path+(pathSep-uLE_path), pathSep+1);
752 //end of clause for using a USB mass: path
753
754 } else if(!strncmp(uLE_path, "hdd0:/", 6)){ //If using HDD path
755 strcpy(loc_path, uLE_path+6);
756 if((p=strchr(loc_path, '/'))!=NULL){
757 sprintf(gen_path,"pfs0:%s", p);
758 *p = 0;
759 } else {
760 strcpy(gen_path, "pfs0:/");
761 }
762 sprintf(party, "hdd0:%s", loc_path);
763 if(nparties==0){
764 loadHddModules();
765 setPartyList();
766 }
767 if((part_ix = mountParty(party)) >= 0)
768 gen_path[3] = part_ix+'0';
769 //end of clause for using an HDD path
770 }
771 genLimObjName(gen_path, 0);
772 return part_ix;
773 //non-HDD Path => 99, Good HDD Path => 0-3, Bad Path => negative
774}
775//------------------------------
776//endfunc genFixPath
777//--------------------------------------------------------------
778int genRmdir(char *path)
779{
780 int ret;
781
782 genLimObjName(path, 0);
783 if(!strncmp(path, "pfs", 3) || !strncmp(path, "vmc", 3)){
784 ret = fileXioRmdir(path);
785 if(!strncmp(path, "vmc", 3))
786 (void) fileXioDevctl("vmc0:", DEVCTL_VMCFS_CLEAN, NULL, 0, NULL, 0);
787 }else{
788 ret = fioRmdir(path);
789 }
790 return ret;
791}
792//------------------------------
793//endfunc genRmdir
794//--------------------------------------------------------------
795int genRemove(char *path)
796{
797 int ret;
798
799 genLimObjName(path, 0);
800 if(!strncmp(path, "pfs", 3) || !strncmp(path, "vmc", 3)){
801 ret = fileXioRemove(path);
802 if(!strncmp(path, "vmc", 3))
803 (void) fileXioDevctl("vmc0:", DEVCTL_VMCFS_CLEAN, NULL, 0, NULL, 0);
804 }else{
805 ret = fioRemove(path);
806 if(!strncmp("mc", path, 2)) //exception for MCMAN, which has its own fix
807 ret = fioRmdir(path); // Remove accidental dir (ancient ioman bug)
808 } //ends if clauses
809 return ret;
810}
811//------------------------------
812//endfunc genRemove
813//--------------------------------------------------------------
814int genOpen(char *path, int mode)
815{
816 int i, fd, io;
817
818 genLimObjName(path, 0);
819 for(i=0; i<256; i++)
820 if(gen_fd[i] < 0)
821 break;
822 if(i > 255)
823 return -1;
824
825 if(!strncmp(path, "pfs", 3) || !strncmp(path, "vmc", 3)){
826 fd = fileXioOpen(path, mode, fileMode);
827 io = 1;
828 }else{
829 fd = fioOpen(path, mode);
830 io = 0;
831 }
832 if(fd < 0)
833 return fd;
834
835 gen_fd[i] = fd;
836 gen_io[i] = io;
837 return i;
838}
839//------------------------------
840//endfunc genOpen
841//--------------------------------------------------------------
842int genDopen(char *path)
843{
844 int i, fd, io;
845
846 for(i=0; i<256; i++)
847 if(gen_fd[i] < 0)
848 break;
849 if(i > 255){
850 //printf("genDopen(\"%s\") => no free descriptors\r\n", path);
851 return -1;
852 }
853
854 if(!strncmp(path, "pfs", 3) || !strncmp(path, "vmc", 3)){
855 char tmp[MAX_PATH];
856
857 strcpy(tmp, path);
858 if(tmp[strlen(tmp)-1] == '/')
859 tmp[strlen(tmp)-1] = '\0';
860 fd = fileXioDopen(tmp);
861 io = 3;
862 }else{
863 fd = fioDopen(path);
864 io = 2;
865 }
866 if(fd < 0){
867 //printf("genDopen(\"%s\") => low error %d\r\n", path, fd);
868 return fd;
869 }
870
871 gen_fd[i] = fd;
872 gen_io[i] = io;
873 //printf("genDopen(\"%s\") =>dd = %d\r\n", path, i);
874 return i;
875}
876//------------------------------
877//endfunc genDopen
878//--------------------------------------------------------------
879int genLseek(int fd, int where, int how)
880{
881 if((fd < 0) || (fd > 255) || (gen_fd[fd] < 0))
882 return -1;
883
884 if(gen_io[fd])
885 return fileXioLseek(gen_fd[fd], where, how);
886 else
887 return fioLseek(gen_fd[fd], where, how);
888}
889//------------------------------
890//endfunc genLseek
891//--------------------------------------------------------------
892int genRead(int fd, void *buf, int size)
893{
894 if((fd < 0) || (fd > 255) || (gen_fd[fd] < 0))
895 return -1;
896
897 if(gen_io[fd])
898 return fileXioRead(gen_fd[fd], buf, size);
899 else
900 return fioRead(gen_fd[fd], buf, size);
901}
902//------------------------------
903//endfunc genRead
904//--------------------------------------------------------------
905int genWrite(int fd, void *buf, int size)
906{
907 if((fd < 0) || (fd > 255) || (gen_fd[fd] < 0))
908 return -1;
909
910 if(gen_io[fd])
911 return fileXioWrite(gen_fd[fd], buf, size);
912 else
913 return fioWrite(gen_fd[fd], buf, size);
914}
915//------------------------------
916//endfunc genWrite
917//--------------------------------------------------------------
918int genClose(int fd)
919{
920 int ret;
921
922 if((fd < 0) || (fd > 255) || (gen_fd[fd] < 0))
923 return -1;
924
925 if(gen_io[fd]==1)
926 ret = fileXioClose(gen_fd[fd]);
927 else if(gen_io[fd]==0)
928 ret = fioClose(gen_fd[fd]);
929 else
930 return -1;
931 gen_fd[fd] = -1;
932 return ret;
933}
934//------------------------------
935//endfunc genClose
936//--------------------------------------------------------------
937int genDclose(int fd)
938{
939 int ret;
940
941 if((fd < 0) || (fd > 255) || (gen_fd[fd] < 0))
942 return -1;
943
944 if(gen_io[fd]==3)
945 ret = fileXioDclose(gen_fd[fd]);
946 else if(gen_io[fd]==2)
947 ret = fioDclose(gen_fd[fd]);
948 else
949 return -1;
950 gen_fd[fd] = -1;
951 return ret;
952}
953//------------------------------
954//endfunc genDclose
955//--------------------------------------------------------------
956int readVMC(const char *path, FILEINFO *info, int max)
957{
958 iox_dirent_t dirbuf;
959 char dir[MAX_PATH];
960 int i=0, fd;
961
962 strcpy(dir, path);
963 if((fd=fileXioDopen(dir)) < 0) return 0;
964
965 while(fileXioDread(fd, &dirbuf) > 0){
966// if(dirbuf.stat.mode & FIO_S_IFDIR && //NB: normal usage (non-vmcfs)
967 if(dirbuf.stat.mode & MC_ATTR_SUBDIR && //NB: nonstandard usage of vmcfs
968 (!strcmp(dirbuf.name,".") || !strcmp(dirbuf.name,"..")))
969 continue; //Skip pseudopaths "." and ".."
970
971 strcpy(info[i].name, dirbuf.name);
972 clear_mcTable(&info[i].stats);
973// if(dirbuf.stat.mode & FIO_S_IFDIR){ //NB: normal usage (non-vmcfs)
974// info[i].stats.attrFile = MC_ATTR_norm_folder;
975// }
976 if(dirbuf.stat.mode & MC_ATTR_SUBDIR){ //NB: vmcfs usage
977 info[i].stats.attrFile = dirbuf.stat.mode;
978 }
979// else if(dirbuf.stat.mode & FIO_S_IFREG){ //NB: normal usage (non-vmcfs)
980// info[i].stats.attrFile = MC_ATTR_norm_file;
981// info[i].stats.fileSizeByte = dirbuf.stat.size;
982// }
983 else if(dirbuf.stat.mode & MC_ATTR_FILE){ //NB: vmcfs usage
984 info[i].stats.attrFile = dirbuf.stat.mode;
985 info[i].stats.fileSizeByte = dirbuf.stat.size;
986 }
987 else
988 continue; //Skip entry which is neither a file nor a folder
989 strncpy(info[i].stats.name, info[i].name, 32);
990 memcpy((void *) &info[i].stats._create, dirbuf.stat.ctime, 8);
991 memcpy((void *) &info[i].stats._modify, dirbuf.stat.mtime, 8);
992 i++;
993 if(i==max) break;
994 }
995
996 fileXioDclose(fd);
997
998 size_valid = 1;
999 time_valid = 1;
1000
1001 return i;
1002}
1003//------------------------------
1004//endfunc readVMC
1005//--------------------------------------------------------------
1006int readHDD(const char *path, FILEINFO *info, int max)
1007{
1008 iox_dirent_t dirbuf;
1009 char party[MAX_PATH], dir[MAX_PATH];
1010 int i=0, fd, ret;
1011
1012 if(nparties==0){
1013 loadHddModules();
1014 setPartyList();
1015 }
1016
1017 if(!strcmp(path, "hdd0:/")){
1018 for(i=0; i<nparties; i++){
1019 strcpy(info[i].name, parties[i]);
1020 info[i].stats.attrFile = MC_ATTR_norm_folder;
1021 }
1022 return nparties;
1023 }
1024
1025 getHddParty(path,NULL,party,dir);
1026 ret = mountParty(party);
1027 if(ret<0) return 0;
1028 dir[3] = ret+'0';
1029
1030 if((fd=fileXioDopen(dir)) < 0) return 0;
1031
1032 while(fileXioDread(fd, &dirbuf) > 0){
1033 if(dirbuf.stat.mode & FIO_S_IFDIR &&
1034 (!strcmp(dirbuf.name,".") || !strcmp(dirbuf.name,"..")))
1035 continue; //Skip pseudopaths "." and ".."
1036
1037 strcpy(info[i].name, dirbuf.name);
1038 clear_mcTable(&info[i].stats);
1039 if(dirbuf.stat.mode & FIO_S_IFDIR){
1040 info[i].stats.attrFile = MC_ATTR_norm_folder;
1041 }
1042 else if(dirbuf.stat.mode & FIO_S_IFREG){
1043 info[i].stats.attrFile = MC_ATTR_norm_file;
1044 info[i].stats.fileSizeByte = dirbuf.stat.size;
1045 }
1046 else
1047 continue; //Skip entry which is neither a file nor a folder
1048 strncpy(info[i].stats.name, info[i].name, 32);
1049 memcpy((void *) &info[i].stats._create, dirbuf.stat.ctime, 8);
1050 memcpy((void *) &info[i].stats._modify, dirbuf.stat.mtime, 8);
1051 i++;
1052 if(i==max) break;
1053 }
1054
1055 fileXioDclose(fd);
1056
1057 size_valid = 1;
1058 time_valid = 1;
1059
1060 return i;
1061}
1062//------------------------------
1063//endfunc readHDD
1064//--------------------------------------------------------------
1065void scan_USB_mass(void){
1066 int i;
1067 fio_stat_t chk_stat;
1068 char mass_path[8] = "mass0:/";
1069
1070 if( (USB_mass_max_drives < 2) //No need for dynamic lists with only one drive
1071 ||(USB_mass_scanned && ((Timer()-USB_mass_scan_time) < 5000))
1072 )
1073 return;
1074
1075 for(i=0; i<USB_mass_max_drives; i++){
1076 mass_path[4] = '0'+i;
1077 if(fioGetstat(mass_path, &chk_stat) < 0){
1078 USB_mass_ix[i] = 0;
1079 continue;
1080 }
1081 USB_mass_ix[i] = '0'+i;
1082 USB_mass_scanned =1;
1083 USB_mass_scan_time = Timer();
1084 }//ends for loop
1085}
1086//------------------------------
1087//endfunc scan_USB_mass
1088//--------------------------------------------------------------
1089int readMASS(const char *path, FILEINFO *info, int max)
1090{
1091 fio_dirent_t record;
1092 int n=0, dd=-1;
1093
1094 loadUsbModules();
1095
1096 if(!USB_mass_scanned)
1097 scan_USB_mass();
1098
1099 if ((dd = fioDopen(path)) < 0) goto exit; //exit if error opening directory
1100 while(fioDread(dd, &record) > 0){
1101 if((FIO_SO_ISDIR(record.stat.mode))
1102 && (!strcmp(record.name,".") || !strcmp(record.name,".."))
1103 ) continue; //Skip entry if pseudo-folder "." or ".."
1104
1105 strcpy(info[n].name, record.name);
1106 clear_mcTable(&info[n].stats);
1107 if(FIO_SO_ISDIR(record.stat.mode)){
1108 info[n].stats.attrFile = MC_ATTR_norm_folder;
1109 }
1110 else if(FIO_SO_ISREG(record.stat.mode)){
1111 info[n].stats.attrFile = MC_ATTR_norm_file;
1112 info[n].stats.fileSizeByte = record.stat.size;
1113 }
1114 else
1115 continue; //Skip entry which is neither a file nor a folder
1116 strncpy(info[n].stats.name, info[n].name, 32);
1117 memcpy((void *) &info[n].stats._create, record.stat.ctime, 8);
1118 memcpy((void *) &info[n].stats._modify, record.stat.mtime, 8);
1119 n++;
1120 if(n==max) break;
1121 } //ends while
1122 size_valid = 1;
1123 time_valid = 1;
1124
1125exit:
1126 if(dd >= 0) fioDclose(dd); //Close directory if opened above
1127 return n;
1128}
1129//------------------------------
1130//endfunc readMASS
1131//--------------------------------------------------------------
1132char *makeHostPath(char *dp, char *sp)
1133{
1134 int i;
1135 char ch;
1136
1137 if (!host_use_Bsl)
1138 return strcpy(dp, sp);
1139
1140 for (i=0; i<MAX_PATH-1; i++)
1141 { ch = sp[i];
1142 if (ch == '/')
1143 dp[i] = '\\';
1144 else
1145 dp[i] = ch;
1146 if (!ch)
1147 break;
1148 }
1149 return dp;
1150}
1151//--------------------------------------------------------------
1152char *makeFslPath(char *dp, char *sp)
1153{
1154 int i;
1155 char ch;
1156
1157 for (i=0; i<MAX_PATH-1; i++)
1158 { ch = sp[i];
1159 if (ch == '\\')
1160 dp[i] = '/';
1161 else
1162 dp[i] = ch;
1163 if (!ch)
1164 break;
1165 }
1166 return dp;
1167}
1168//--------------------------------------------------------------
1169void initHOST(void)
1170{
1171 int fd;
1172
1173 load_ps2host();
1174 host_error = 0;
1175 if ((fd = fioOpen("host:elflist.txt", O_RDONLY)) >= 0)
1176 { fioClose(fd);
1177 host_elflist = 1;
1178 }
1179 else
1180 { host_elflist = 0;
1181 if ((fd = fioDopen("host:")) >= 0)
1182 fioDclose(fd);
1183 else
1184 host_error = 1;
1185 }
1186 host_ready = 1;
1187}
1188//--------------------------------------------------------------
1189int readHOST(const char *path, FILEINFO *info, int max)
1190{
1191 fio_dirent_t hostcontent;
1192 int hfd, rv, size, contentptr, hostcount = 0;
1193 char *elflisttxt, elflistchar;
1194 char host_path[MAX_PATH], host_next[MAX_PATH];
1195 char Win_path[MAX_PATH];
1196
1197 initHOST();
1198 snprintf(host_path, MAX_PATH-1, "%s", path);
1199 if (!strncmp(path, "host:/", 6))
1200 strcpy(host_path+5, path+6);
1201 if ((host_elflist) && !strcmp(host_path, "host:")){
1202 if ((hfd = fioOpen("host:elflist.txt", O_RDONLY)) < 0)
1203 return 0;
1204 if ((size = fioLseek(hfd, 0, SEEK_END)) <= 0)
1205 { fioClose(hfd);
1206 return 0;
1207 }
1208 elflisttxt = (char *)malloc(size);
1209 fioLseek(hfd, 0, SEEK_SET);
1210 fioRead(hfd, elflisttxt, size);
1211 fioClose(hfd);
1212 contentptr = 0;
1213 for (rv=0;rv<=size;rv++)
1214 { elflistchar = elflisttxt[rv];
1215 if ((elflistchar == 0x0a) || (rv == size))
1216 { host_next[contentptr] = 0;
1217 snprintf(host_path, MAX_PATH-1, "%s%s", "host:", host_next);
1218 clear_mcTable(&info[hostcount].stats);
1219 if ((hfd = fioOpen(makeHostPath(Win_path, host_path), O_RDONLY)) >= 0)
1220 { fioClose(hfd);
1221 info[hostcount].stats.attrFile = MC_ATTR_norm_file;
1222 makeFslPath(info[hostcount++].name, host_next);
1223 } else if ((hfd = fioDopen(Win_path)) >= 0)
1224 { fioDclose(hfd);
1225 info[hostcount].stats.attrFile = MC_ATTR_norm_folder;
1226 makeFslPath(info[hostcount++].name, host_next);
1227 }
1228 contentptr = 0;
1229 if (hostcount > max)
1230 break;
1231 }
1232 else if (elflistchar != 0x0d)
1233 { host_next[contentptr]=elflistchar;
1234 contentptr++;
1235 }
1236 }
1237 free(elflisttxt);
1238 return hostcount-1;
1239 }
1240 //This point is only reached if elflist.txt is NOT to be used
1241
1242 if ((hfd = fioDopen(makeHostPath(Win_path, host_path))) < 0)
1243 return 0;
1244 strcpy(host_path, Win_path);
1245 while ((rv = fioDread(hfd, &hostcontent)))
1246 { if (strcmp(hostcontent.name, ".")&&strcmp(hostcontent.name, ".."))
1247 {
1248 size_valid = 1;
1249 time_valid = 1;
1250 snprintf(Win_path, MAX_PATH-1, "%s%s", host_path, hostcontent.name);
1251 strcpy(info[hostcount].name, hostcontent.name);
1252 clear_mcTable(&info[hostcount].stats);
1253
1254 if(!(hostcontent.stat.mode & FIO_SO_IFDIR)) //if not a directory
1255 info[hostcount].stats.attrFile = MC_ATTR_norm_file;
1256 else
1257 info[hostcount].stats.attrFile = MC_ATTR_norm_folder;
1258
1259 info[hostcount].stats.fileSizeByte = hostcontent.stat.size;
1260 memcpy((void *) &info[hostcount].stats._create, hostcontent.stat.ctime, 8);
1261 info[hostcount].stats._create.year += 1900;
1262 memcpy((void *) &info[hostcount].stats._modify, hostcontent.stat.mtime, 8);
1263 info[hostcount].stats._modify.year += 1900;
1264 hostcount++;
1265 if (hostcount >= max)
1266 break;
1267 }
1268 }
1269 fioDclose(hfd);
1270 strcpy (info[hostcount].name, "\0");
1271 return hostcount;
1272}
1273//------------------------------
1274//endfunc readHOST
1275//--------------------------------------------------------------
1276int getDir(const char *path, FILEINFO *info)
1277{
1278 int max=MAX_ENTRY-2;
1279 int n;
1280
1281 if(!strncmp(path, "mc", 2)) n=readMC(path, info, max);
1282 else if(!strncmp(path, "hdd", 3)) n=readHDD(path, info, max);
1283 else if(!strncmp(path, "mass", 4)) n=readMASS(path, info, max);
1284 else if(!strncmp(path, "cdfs", 4)) n=readCD(path, info, max);
1285 else if(!strncmp(path, "host", 4)) n=readHOST(path, info, max);
1286 else if(!strncmp(path, "vmc", 3)) n=readVMC(path, info, max);
1287 else return 0;
1288
1289 return n;
1290}
1291//--------------------------------------------------------------
1292// getGameTitle below is used to extract the real save title of
1293// an MC gamesave folder. Normally this is held in the icon.sys
1294// file of a PS2 game save, but that is not the case for saves
1295// on a PS1 MC, or similar saves backed up to a PS2 MC. Two new
1296// methods need to be used to extract such titles correctly, and
1297// these were added in v3.62, by me (dlanor).
1298// From v3.91 This routine also extracts titles from PSU files.
1299//--------------------------------------------------------------
1300int getGameTitle(const char *path, const FILEINFO *file, char *out)
1301{
1302 char party[MAX_NAME], dir[MAX_PATH], tmpdir[MAX_PATH];
1303 int fd=-1, size, hddin=FALSE, ret;
1304 psu_header PSU_head;
1305 int i, tst, PSU_content, psu_pad_pos;
1306 char *cp;
1307
1308 out[0] = '\0'; //Start by making an empty result string, for failures
1309
1310 //Avoid title usage in browser root or partition list
1311 if(path[0]==0 || !strcmp(path,"hdd0:/")) return -1;
1312
1313 if(!strncmp(path, "hdd", 3)){
1314 ret = getHddParty(path, file, party, dir);
1315 if((ret = mountParty(party)<0))
1316 return -1;
1317 dir[3]=ret+'0';
1318 hddin=TRUE;
1319 }else{
1320 strcpy(dir, path);
1321 strcat(dir, file->name);
1322 if(file->stats.attrFile & MC_ATTR_SUBDIR) strcat(dir, "/");
1323 }
1324
1325 ret = -1; //Assume that result will be failure, to simplify aborts
1326
1327 if((file->stats.attrFile & MC_ATTR_SUBDIR)==0){
1328 //Here we know that the object needing a title is a file
1329 strcpy(tmpdir, dir); //Copy the pathname for file access
1330 cp = strrchr(tmpdir, '.'); //Find the extension, if any
1331 if((cp==NULL) || stricmp(cp, ".psu") ) //If it's anything other than a PSU file
1332 goto get_PS1_GameTitle; //then it may be a PS1 save
1333 //Here we know that the object needing a title is a PSU file
1334 if((fd=genOpen(tmpdir, O_RDONLY)) < 0) goto finish; //Abort if open fails
1335 tst = genRead(fd, (void *) &PSU_head, sizeof(PSU_head));
1336 if(tst != sizeof(PSU_head)) goto finish; //Abort if read fails
1337 PSU_content = PSU_head.size;
1338 for(i=0; i<PSU_content; i++){
1339 tst = genRead(fd, (void *) &PSU_head, sizeof(PSU_head));
1340 if(tst != sizeof(PSU_head)) goto finish; //Abort if read fails
1341 PSU_head.name[sizeof(PSU_head.name)] = '\0';
1342 if(!strcmp(PSU_head.name, "icon.sys")) {
1343 genLseek(fd, 0xC0, SEEK_CUR);
1344 goto read_title;
1345 }
1346 if(PSU_head.size){
1347 psu_pad_pos = (PSU_head.size + 0x3FF) & -0x400;
1348 genLseek(fd, psu_pad_pos, SEEK_CUR);
1349 }
1350 //Here the PSU file pointer is positioned for reading next header
1351 }//ends for
1352 //Coming here means that the search for icon.sys failed
1353 goto finish; //So go finish off this function
1354 }//ends if clause for files needing a title
1355
1356 //Here we know that the object needing a title is a folder
1357 //First try to find a valid PS2 icon.sys file inside the folder
1358 strcpy(tmpdir, dir);
1359 strcat(tmpdir, "icon.sys");
1360 if((fd=genOpen(tmpdir, O_RDONLY)) >= 0){
1361 if((size=genLseek(fd,0,SEEK_END)) <= 0x100) goto finish;
1362 genLseek(fd,0xC0,SEEK_SET);
1363 goto read_title;
1364 }
1365 //Next try to find a valid PS1 savefile inside the folder instead
1366 strcpy(tmpdir, dir);
1367 strcat(tmpdir, file->name); //PS1 save file should have same name as folder
1368
1369get_PS1_GameTitle:
1370 if((fd=genOpen(tmpdir, O_RDONLY)) < 0) goto finish; //PS1 gamesave file needed
1371 if((size=genLseek(fd,0,SEEK_END)) < 0x2000) goto finish; //Min size is 8K
1372 if(size & 0x1FFF) goto finish; //Size must be a multiple of 8K
1373 genLseek(fd, 0, SEEK_SET);
1374 genRead(fd, out, 2);
1375 if(strncmp(out, "SC", 2)) goto finish; //PS1 gamesaves always start with "SC"
1376 genLseek(fd, 4, SEEK_SET);
1377
1378read_title:
1379 genRead(fd, out, 32*2);
1380 out[32*2] = 0;
1381 genClose(fd); fd=-1;
1382 ret=0;
1383
1384finish:
1385 if(fd>=0)
1386 genClose(fd);
1387 return ret;
1388}
1389//--------------------------------------------------------------
1390int menu(const char *path, FILEINFO *file)
1391{
1392 u64 color;
1393 char enable[NUM_MENU], tmp[80];
1394 int x, y, i, sel;
1395 int event, post_event = 0;
1396 int menu_disabled = 0;
1397 int write_disabled = 0;
1398
1399 int menu_len=strlen(LNG(Copy))>strlen(LNG(Cut))?
1400 strlen(LNG(Copy)):strlen(LNG(Cut));
1401 menu_len=strlen(LNG(Paste))>menu_len? strlen(LNG(Paste)):menu_len;
1402 menu_len=strlen(LNG(Delete))>menu_len? strlen(LNG(Delete)):menu_len;
1403 menu_len=strlen(LNG(Rename))>menu_len? strlen(LNG(Rename)):menu_len;
1404 menu_len=strlen(LNG(New_Dir))>menu_len? strlen(LNG(New_Dir)):menu_len;
1405 menu_len=strlen(LNG(Get_Size))>menu_len? strlen(LNG(Get_Size)):menu_len;
1406 menu_len=strlen(LNG(mcPaste))>menu_len? strlen(LNG(mcPaste)):menu_len;
1407 menu_len=strlen(LNG(psuPaste))>menu_len? strlen(LNG(psuPaste)):menu_len;
1408 menu_len=(strlen(LNG(Mount))+6)>menu_len? (strlen(LNG(Mount))+6):menu_len;
1409
1410 int menu_ch_w = menu_len+1; //Total characters in longest menu string
1411 int menu_ch_h = NUM_MENU; //Total number of menu lines
1412 int mSprite_Y1 = 64; //Top edge of sprite
1413 int mSprite_X2 = SCREEN_WIDTH-35; //Right edge of sprite
1414 int mSprite_X1 = mSprite_X2-(menu_ch_w+3)*FONT_WIDTH; //Left edge of sprite
1415 int mSprite_Y2 = mSprite_Y1+(menu_ch_h+1)*FONT_HEIGHT; //Bottom edge of sprite
1416
1417 memset(enable, TRUE, NUM_MENU); //Assume that all menu items are legal by default
1418
1419 //identify cases where write access is illegal, and disable menu items accordingly
1420 if( (!strncmp(path,"cdfs",4)) //Writing is always illegal for CDVD drive
1421 ||( (!strncmp(path,"host",4)) //host: has special cases
1422 &&( (!setting->HOSTwrite) //host: Writing is illegal if not enabled in CNF
1423 ||(host_elflist && !strcmp(path, "host:/")) //it's also illegal in elflist.txt
1424 ) ) ) write_disabled = 1;
1425
1426 if( !strcmp(path,"hdd0:/") || path[0]==0) //No menu cmds in partition/device lists
1427 menu_disabled = 1;
1428
1429 if(menu_disabled) {
1430 enable[COPY] = FALSE;
1431 enable[MOUNTVMC0]=FALSE;
1432 enable[MOUNTVMC1]=FALSE;
1433 enable[GETSIZE] = FALSE;
1434 }
1435
1436 if(write_disabled || menu_disabled){
1437 enable[CUT] = FALSE;
1438 enable[PASTE] = FALSE;
1439 enable[MCPASTE] = FALSE;
1440 enable[PSUPASTE] = FALSE;
1441 enable[DELETE] = FALSE;
1442 enable[RENAME] = FALSE;
1443 enable[NEWDIR] = FALSE;
1444 enable[NEWICON] = FALSE;
1445 }
1446
1447 if(!strncmp(path, "mass", 4)){
1448 enable[RENAME] = FALSE;
1449 }
1450
1451/* commented due to MC modules by jimmikaelkael (allow rename)
1452 if(!strncmp(path, "mc", 2)){
1453 int test;
1454
1455 mcGetInfo(path[2]-'0', 0, &mctype_PSx, NULL, NULL);
1456 mcSync(0, NULL, &test);
1457 if (mctype_PSx == 2) //PS2 MC ?
1458 enable[RENAME] = FALSE;
1459 }
1460*/
1461
1462 if(nmarks==0){
1463 if(!strcmp(file->name, "..")){
1464 enable[COPY] = FALSE;
1465 enable[CUT] = FALSE;
1466 enable[DELETE] = FALSE;
1467 enable[RENAME] = FALSE;
1468 enable[GETSIZE] = FALSE;
1469 }
1470 }else{
1471 enable[RENAME] = FALSE;
1472 }
1473
1474 if((file->stats.attrFile & MC_ATTR_SUBDIR)
1475 || !strncmp(path, "vmc", 3)
1476 || !strncmp(path, "mc", 2)
1477 ){
1478 enable[MOUNTVMC0]=FALSE; //forbid insane VMC mounting
1479 enable[MOUNTVMC1]=FALSE; //forbid insane VMC mounting
1480 }
1481
1482 if(nclipFiles==0){
1483 //Nothing in clipboard
1484 enable[PASTE] = FALSE;
1485 enable[MCPASTE] = FALSE;
1486 enable[PSUPASTE] = FALSE;
1487 } else {
1488 //Something in clipboard
1489 if(!strncmp(path, "mc", 2) || !strncmp(path, "vmc", 3)){
1490 if(!strncmp(clipPath, "mc", 2) || !strncmp(clipPath, "vmc", 3)){
1491 enable[MCPASTE] = FALSE; //No mcPaste if both src and dest are MC
1492 enable[PSUPASTE] = FALSE;
1493 }
1494 } else
1495 if(strncmp(clipPath, "mc", 2) && strncmp(clipPath, "vmc", 3)){
1496 enable[MCPASTE] = FALSE; //No mcPaste if both src and dest non-MC
1497 enable[PSUPASTE] = FALSE;
1498 }
1499 }
1500
1501 for(sel=0; sel<NUM_MENU; sel++) //loop to preselect the first enabled menu entry
1502 if(enable[sel]==TRUE) break; //break loop if sel is at an enabled menu entry
1503
1504 event = 1; //event = initial entry
1505 while(1){
1506 //Pad response section
1507 waitPadReady(0, 0);
1508 if(readpad()){
1509 if(new_pad & PAD_UP && sel<NUM_MENU){
1510 event |= 2; //event |= valid pad command
1511 do{
1512 sel--;
1513 if(sel<0) sel=NUM_MENU-1;
1514 }while(!enable[sel]);
1515 }else if(new_pad & PAD_DOWN && sel<NUM_MENU){
1516 event |= 2; //event |= valid pad command
1517 do{
1518 sel++;
1519 if(sel==NUM_MENU) sel=0;
1520 }while(!enable[sel]);
1521 }else if((new_pad & PAD_TRIANGLE)
1522 || (!swapKeys && new_pad & PAD_CROSS)
1523 || (swapKeys && new_pad & PAD_CIRCLE) ){
1524 return -1;
1525 }else if((swapKeys && new_pad & PAD_CROSS)
1526 || (!swapKeys && new_pad & PAD_CIRCLE) ){
1527 event |= 2; //event |= valid pad command
1528 break;
1529 }else if(new_pad & PAD_SQUARE && sel==PASTE){
1530 event |= 2; //event |= valid pad command
1531 break;
1532 }
1533 }
1534
1535 if(event||post_event){ //NB: We need to update two frame buffers per event
1536
1537 //Display section
1538 drawPopSprite(setting->color[0],
1539 mSprite_X1, mSprite_Y1,
1540 mSprite_X2, mSprite_Y2);
1541 drawFrame(mSprite_X1, mSprite_Y1, mSprite_X2, mSprite_Y2, setting->color[1]);
1542
1543 for(i=0,y=mSprite_Y1+FONT_HEIGHT/2; i<NUM_MENU; i++){
1544 if(i==COPY) strcpy(tmp, LNG(Copy));
1545 else if(i==CUT) strcpy(tmp, LNG(Cut));
1546 else if(i==PASTE) strcpy(tmp, LNG(Paste));
1547 else if(i==MCPASTE) strcpy(tmp, LNG(mcPaste));
1548 else if(i==PSUPASTE) strcpy(tmp, LNG(psuPaste));
1549 else if(i==DELETE) strcpy(tmp, LNG(Delete));
1550 else if(i==RENAME) strcpy(tmp, LNG(Rename));
1551 else if(i==NEWDIR) strcpy(tmp, LNG(New_Dir));
1552 else if(i==NEWICON) strcpy(tmp, LNG(New_Icon));
1553 else if(i==MOUNTVMC0) sprintf(tmp, "%s vmc0:", LNG(Mount));
1554 else if(i==MOUNTVMC1) sprintf(tmp, "%s vmc1:", LNG(Mount));
1555 else if(i==GETSIZE) strcpy(tmp, LNG(Get_Size));
1556
1557 if(enable[i]) color = setting->color[3];
1558 else color = setting->color[1];
1559
1560 printXY(tmp, mSprite_X1+2*FONT_WIDTH, y, color, TRUE,0);
1561 y+=FONT_HEIGHT;
1562 }
1563 if(sel<NUM_MENU)
1564 drawChar(LEFT_CUR, mSprite_X1+FONT_WIDTH, mSprite_Y1+(FONT_HEIGHT/2+sel*FONT_HEIGHT), setting->color[3]);
1565
1566 //Tooltip section
1567 x = SCREEN_MARGIN;
1568 y = Menu_tooltip_y;
1569 drawSprite(setting->color[0],
1570 0, y-1,
1571 SCREEN_WIDTH, y+FONT_HEIGHT);
1572 if (swapKeys)
1573 sprintf(tmp, "ÿ1:%s ÿ0:%s", LNG(OK), LNG(Cancel));
1574 else
1575 sprintf(tmp, "ÿ0:%s ÿ1:%s", LNG(OK), LNG(Cancel));
1576 if(sel==PASTE)
1577 sprintf(tmp+strlen(tmp), " ÿ2:%s", LNG(PasteRename));
1578 sprintf(tmp+strlen(tmp), " ÿ3:%s", LNG(Back));
1579 printXY(tmp, x, y, setting->color[2], TRUE, 0);
1580 }//ends if(event||post_event)
1581 drawScr();
1582 post_event = event;
1583 event = 0;
1584 }//ends while
1585 return sel;
1586}//ends menu
1587//--------------------------------------------------------------
1588char *PathPad_menu(const char *path)
1589{
1590 u64 color;
1591 int x, y, dx, dy, dw, dh;
1592 int a=6, b=4, c=2, tw, th;
1593 int i, sel_x, sel_y;
1594 int event, post_event=0;
1595 char textrow[80], tmp[64];
1596
1597 th = 10*FONT_HEIGHT; //Height in pixels of text area
1598 tw = 68*FONT_WIDTH; //Width in pixels of max text row
1599 dh = th+2*2+a+b+c; //Height in pixels of entire frame
1600 dw = tw+2*2+a*2; //Width in pixels of entire frame
1601 dx = (SCREEN_WIDTH-dw)/2; //X position of frame (centred)
1602 dy = (SCREEN_HEIGHT-dh)/2; //Y position of frame (centred)
1603
1604 sel_x=0; sel_y=0;
1605 event = 1; //event = initial entry
1606 while(1){
1607 //Pad response section
1608 waitPadReady(0, 0);
1609 if(readpad()){
1610 if(new_pad){
1611 event |= 2; //event |= valid pad command
1612 if(new_pad & PAD_UP){
1613 sel_y--;
1614 if(sel_y<0)
1615 sel_y=9;
1616 }else if(new_pad & PAD_DOWN){
1617 sel_y++;
1618 if(sel_y>9)
1619 sel_y=0;
1620 }else if(new_pad & PAD_LEFT){
1621 sel_y -= 5;
1622 if(sel_y<0)
1623 sel_y=0;
1624 }else if(new_pad & PAD_RIGHT){
1625 sel_y += 5;
1626 if(sel_y>9)
1627 sel_y=9;
1628 }else if(new_pad & PAD_L1){
1629 sel_x--;
1630 if(sel_x<0)
1631 sel_x=2;
1632 }else if(new_pad & PAD_R1){
1633 sel_x++;
1634 if(sel_x>2)
1635 sel_x=0;
1636 }else if(new_pad & PAD_TRIANGLE){ //Pushed 'Back'
1637 return NULL;
1638 }else if(!setting->PathPad_Lock //if PathPad changes allowed ?
1639 && ( (!swapKeys && new_pad & PAD_CROSS)
1640 ||(swapKeys && new_pad & PAD_CIRCLE) )) {//Pushed 'Clear'
1641 PathPad[sel_x*10+sel_y][0] = '\0';
1642 }else if((swapKeys && new_pad & PAD_CROSS)
1643 || (!swapKeys && new_pad & PAD_CIRCLE) ){//Pushed 'Use'
1644 return PathPad[sel_x*10+sel_y];
1645 }else if(!setting->PathPad_Lock && (new_pad & PAD_SQUARE)){//Pushed 'Set'
1646 strncpy(PathPad[sel_x*10+sel_y], path, MAX_PATH-1);
1647 PathPad[sel_x*10+sel_y][MAX_PATH-1]='\0';
1648 }
1649 }//ends 'if(new_pad)'
1650 }//ends 'if(readpad())'
1651
1652 if(event||post_event){ //NB: We need to update two frame buffers per event
1653
1654 //Display section
1655 drawSprite(setting->color[0],
1656 0, (Menu_message_y-1),
1657 SCREEN_WIDTH, (Frame_start_y));
1658 drawPopSprite(setting->color[0],
1659 dx, dy,
1660 dx+dw, (dy+dh));
1661 drawFrame(dx, dy, dx+dw, (dy+dh), setting->color[1]);
1662 for(i=0; i<10; i++){
1663 if(i==sel_y)
1664 color=setting->color[2];
1665 else
1666 color=setting->color[3];
1667 sprintf(textrow, "%02d=", (sel_x*10+i));
1668 strncat(textrow, PathPad[sel_x*10+i], 64);
1669 textrow[67] = '\0';
1670 printXY(textrow, dx+2+a,(dy+a+2+i*FONT_HEIGHT), color,TRUE,0);
1671 }
1672
1673 //Tooltip section
1674 x = SCREEN_MARGIN;
1675 y = Menu_tooltip_y;
1676 drawSprite(setting->color[0], 0, y-1, SCREEN_WIDTH, y+FONT_HEIGHT);
1677
1678 if(swapKeys) {
1679 sprintf(textrow, "ÿ1:%s ", LNG(Use));
1680 if(!setting->PathPad_Lock){
1681 sprintf(tmp, "ÿ0:%s ÿ2:%s ", LNG(Clear), LNG(Set));
1682 strcat(textrow, tmp);
1683 }
1684 } else {
1685 sprintf(textrow, "ÿ0:%s ", LNG(Use));
1686 if(!setting->PathPad_Lock){
1687 sprintf(tmp, "ÿ1:%s ÿ2:%s ", LNG(Clear), LNG(Set));
1688 strcat(textrow, tmp);
1689 }
1690 }
1691 sprintf(tmp, "ÿ3:%s L1/R1:%s", LNG(Back), LNG(Page_leftright));
1692 strcat(textrow, tmp);
1693 printXY(textrow, x, y, setting->color[2], TRUE, 0);
1694 }//ends if(event||post_event)
1695 drawScr();
1696 post_event = event;
1697 event = 0;
1698 }//ends while
1699}
1700//------------------------------
1701//endfunc PathPad_menu
1702//--------------------------------------------------------------
1703s64 getFileSize(const char *path, const FILEINFO *file)
1704{
1705 s64 size, filesize;
1706 FILEINFO files[MAX_ENTRY];
1707 char dir[MAX_PATH], party[MAX_NAME];
1708 int nfiles, i, ret, fd;
1709
1710 if(file->stats.attrFile & MC_ATTR_SUBDIR){ //Folder object to size up
1711 sprintf(dir, "%s%s/", path, file->name);
1712 nfiles = getDir(dir, files);
1713 for(i=size=0; i<nfiles; i++){
1714 filesize=getFileSize(dir, &files[i]); //recurse for each object in folder
1715 if(filesize < 0) return -1;
1716 else size += filesize;
1717 }
1718 } else { //File object to size up
1719 if(!strncmp(path, "hdd", 3)){
1720 getHddParty(path,file,party,dir);
1721 ret = mountParty(party);
1722 if(ret<0) return 0;
1723 dir[3] = ret+'0';
1724 }else
1725 sprintf(dir, "%s%s", path, file->name);
1726 if (!strncmp(dir, "host:/", 6))
1727 makeHostPath(dir+5, dir+6);
1728 if(!strncmp(path, "hdd", 3) || !strncmp(path, "vmc", 3)){
1729 fd = fileXioOpen(dir, O_RDONLY, fileMode);
1730 size = fileXioLseek(fd,0,SEEK_END);
1731 fileXioClose(fd);
1732 }else{
1733 fd = fioOpen(dir, O_RDONLY);
1734 size = fioLseek(fd,0,SEEK_END);
1735 fioClose(fd);
1736 }
1737 }
1738 return size;
1739}
1740//------------------------------
1741//endfunc getFileSize
1742//--------------------------------------------------------------
1743int delete(const char *path, const FILEINFO *file)
1744{
1745 FILEINFO files[MAX_ENTRY];
1746 char party[MAX_NAME], dir[MAX_PATH], hdddir[MAX_PATH];
1747 int nfiles, i, ret;
1748
1749 if(!strncmp(path, "hdd", 3)){
1750 getHddParty(path,file,party,hdddir);
1751 ret = mountParty(party);
1752 if(ret<0) return 0;
1753 hdddir[3] = ret+'0';
1754 }
1755 sprintf(dir, "%s%s", path, file->name);
1756 genLimObjName(dir, 0);
1757 if (!strncmp(dir, "host:/", 6))
1758 makeHostPath(dir+5, dir+6);
1759
1760 if(file->stats.attrFile & MC_ATTR_SUBDIR){ //Is the object to delete a folder ?
1761 strcat(dir,"/");
1762 nfiles = getDir(dir, files);
1763 for(i=0; i<nfiles; i++){
1764 ret=delete(dir, &files[i]); //recursively delete contents of folder
1765 if(ret < 0) return -1;
1766 }
1767 if(!strncmp(dir, "mc", 2)){
1768 mcSync(0,NULL,NULL);
1769 mcDelete(dir[2]-'0', 0, &dir[4]);
1770 mcSync(0, NULL, &ret);
1771
1772 }else if(!strncmp(path, "hdd", 3)){
1773 ret = fileXioRmdir(hdddir);
1774
1775 }else if(!strncmp(path, "vmc", 3)){
1776 ret = fileXioRmdir(dir);
1777 (void) fileXioDevctl("vmc0:", DEVCTL_VMCFS_CLEAN, NULL, 0, NULL, 0);
1778
1779 }else if(!strncmp(path, "mass", 4)){
1780 char *pathSep;
1781
1782 pathSep = strchr(path, '/');
1783 strcpy(dir, path);
1784 strcat(dir, file->name);
1785 ret = fioRmdir(dir);
1786 if((ret < 0) && (dir[4] == ':')){
1787 sprintf(dir, "mass0:%s%s", &path[5], file->name);
1788 ret = fioRmdir(dir);
1789 }
1790
1791 }else if(!strncmp(path, "host", 4)){
1792 sprintf(dir, "%s%s", path, file->name);
1793 ret = fioRmdir(dir);
1794 }
1795 } else { //The object to delete is a file
1796 if(!strncmp(path, "mc", 2)){
1797 mcSync(0,NULL,NULL);
1798 mcDelete(dir[2]-'0', 0, &dir[4]);
1799 mcSync(0, NULL, &ret);
1800 }else if(!strncmp(path, "hdd", 3)){
1801 ret = fileXioRemove(hdddir);
1802 }else if(!strncmp(path, "vmc", 3)){
1803 ret = fileXioRemove(dir);
1804 (void) fileXioDevctl("vmc0:", DEVCTL_VMCFS_CLEAN, NULL, 0, NULL, 0);
1805 }else if((!strncmp(path, "mass", 4)) || (!strncmp(path, "host", 4))){
1806 ret = fioRemove(dir);
1807 }
1808 }
1809 return ret;
1810}
1811//--------------------------------------------------------------
1812int Rename(const char *path, const FILEINFO *file, const char *name)
1813{
1814 char party[MAX_NAME], oldPath[MAX_PATH], newPath[MAX_PATH];
1815 int test, ret=0;
1816
1817 if(!strncmp(path, "hdd", 3)){
1818 sprintf(party, "hdd0:%s", &path[6]);
1819 *strchr(party, '/')=0;
1820 sprintf(oldPath, "pfs0:%s", strchr(&path[6], '/')+1);
1821 sprintf(newPath, "%s%s", oldPath, name);
1822 strcat(oldPath, file->name);
1823
1824 ret = mountParty(party);
1825 if(ret<0) return -1;
1826 oldPath[3] = newPath[3] = ret+'0';
1827
1828 ret=fileXioRename(oldPath, newPath);
1829 }else if(!strncmp(path, "vmc", 3)){
1830 sprintf(oldPath, "%s%s", path, file->name);
1831 sprintf(newPath, "%s%s", path, name);
1832 ret=fileXioRename(oldPath, newPath);
1833 }else if(!strncmp(path, "mc", 2)){
1834 sprintf(oldPath, "%s%s", path, file->name);
1835 sprintf(newPath, "%s%s", path, name);
1836 if((test=fioDopen(newPath))>=0){ //Does folder of same name exist ?
1837 fioDclose(test);
1838 ret = -17;
1839 }else if((test=fioOpen(newPath, O_RDONLY))>=0){ //Does file of same name exist ?
1840 fioClose(test);
1841 ret = -17;
1842 }else{ //No file/folder of the same name exists
1843 mcGetInfo(path[2]-'0', 0, &mctype_PSx, NULL, NULL);
1844 mcSync(0, NULL, &test);
1845 if (mctype_PSx == 2) //PS2 MC ?
1846 strncpy((void *)file->stats.name, name, 32);
1847 mcSetFileInfo(path[2]-'0', 0, oldPath+4, &file->stats, 0x0010); //Fix file stats
1848 mcSync(0, NULL, &test);
1849 if(ret == -4)
1850 ret = -17;
1851 else{ //PS1 MC !
1852 strncpy((void *)file->stats.name, name, 32);
1853 mcSetFileInfo(path[2]-'0', 0, oldPath+4, &file->stats, 0x0010); //Fix file stats
1854 mcSync(0, NULL, &test);
1855 if(ret == -4)
1856 ret = -17;
1857 }
1858 }
1859 }else if(!strncmp(path, "host", 4)){
1860 int temp_fd;
1861
1862 strcpy(oldPath, path);
1863 if(!strncmp(oldPath, "host:/", 6))
1864 makeHostPath(oldPath+5, oldPath+6);
1865 strcpy(newPath, oldPath+5);
1866 strcat(oldPath, file->name);
1867 strcat(newPath, name);
1868 if(file->stats.attrFile & MC_ATTR_SUBDIR){ //Rename a folder ?
1869 ret = (temp_fd = fioDopen(oldPath));
1870 if (temp_fd >= 0){
1871 ret = fioIoctl(temp_fd, IOCTL_RENAME, (void *) newPath);
1872 fioDclose(temp_fd);
1873 }
1874 } else if(file->stats.attrFile & MC_ATTR_FILE){ //Rename a file ?
1875 ret = (temp_fd = fioOpen(oldPath, O_RDONLY));
1876 if (temp_fd >= 0){
1877 ret = fioIoctl(temp_fd, IOCTL_RENAME, (void *) newPath);
1878 fioClose(temp_fd);
1879 }
1880 } else //This was neither a folder nor a file !!!
1881 return -1;
1882 } else //The device was not recognized
1883 return -1;
1884
1885 return ret;
1886}
1887
1888//--------------------------------------------------------------
1889int newdir(const char *path, const char *name)
1890{
1891 char party[MAX_NAME], dir[MAX_PATH];
1892 int ret=0;
1893
1894 if(!strncmp(path, "hdd", 3)){
1895 getHddParty(path,NULL,party,dir);
1896 ret = mountParty(party);
1897 if(ret<0) return -1;
1898 dir[3] = ret+'0';
1899 //fileXioChdir(dir);
1900 strcat(dir, name);
1901 genLimObjName(dir, 0);
1902 ret = fileXioMkdir(dir, fileMode);
1903 }else if(!strncmp(path, "vmc", 3)){
1904 strcpy(dir, path);
1905 strcat(dir, name);
1906 genLimObjName(dir, 0);
1907 if((ret = fileXioDopen(dir)) >= 0){
1908 fileXioDclose(ret);
1909 ret = -17; //return fileXio error code for pre-existing folder
1910 } else {
1911 ret = fileXioMkdir(dir, fileMode);
1912 }
1913 }else if(!strncmp(path, "mc", 2)){
1914 sprintf(dir, "%s%s", path+4, name);
1915 genLimObjName(dir, 0);
1916 mcSync(0,NULL,NULL);
1917 mcMkDir(path[2]-'0', 0, dir);
1918 mcSync(0, NULL, &ret);
1919 if(ret == -4)
1920 ret = -17; //return fileXio error code for pre-existing folder
1921 }else if(!strncmp(path, "mass", 4)){
1922 strcpy(dir, path);
1923 strcat(dir, name);
1924 genLimObjName(dir, 0);
1925 ret = fioMkdir(dir);
1926 }else if(!strncmp(path, "host", 4)){
1927 strcpy(dir, path);
1928 strcat(dir, name);
1929 genLimObjName(dir, 0);
1930 if(!strncmp(dir, "host:/", 6))
1931 makeHostPath(dir+5, dir+6);
1932 if((ret = fioDopen(dir)) >= 0){
1933 fioDclose(ret);
1934 ret = -17; //return fileXio error code for pre-existing folder
1935 } else {
1936 ret = fioMkdir(dir);//Create the new folder
1937 }
1938 } else { //Device not recognized
1939 ret = -1;
1940 }
1941 return ret;
1942}
1943//--------------------------------------------------------------
1944//The function 'copy' below is called to copy a single object,
1945//indicated by 'file' from 'inPath' to 'outPath', but this may
1946//be either a single file or a folder. In the latter case the
1947//folder contents should also be copied, recursively.
1948//--------------------------------------------------------------
1949int copy(char *outPath, const char *inPath, FILEINFO file, int recurses)
1950{
1951 FILEINFO newfile, files[MAX_ENTRY];
1952 fio_stat_t fio_stat;
1953 iox_stat_t iox_stat;
1954 char out[MAX_PATH], in[MAX_PATH], tmp[MAX_PATH],
1955 progress[MAX_PATH*4],
1956 *buff=NULL, inParty[MAX_NAME], outParty[MAX_NAME];
1957 int hddout=FALSE, hddin=FALSE, nfiles, i;
1958 size_t size, outsize;
1959 int ret=-1, pfsout=-1, pfsin=-1, in_fd=-1, out_fd=-1, buffSize;
1960 int dummy;
1961 mcTable stats;
1962 int speed=0;
1963 int remain_time=0, TimeDiff=0;
1964 long old_size=0, SizeDiff=0;
1965 u64 OldTime=0LL;
1966 psu_header PSU_head;
1967 mcT_header *mcT_head_p = (mcT_header *) &file.stats;
1968 mcT_header *mcT_files_p = (mcT_header *) &files[0].stats;
1969 int psu_pad_size = 0, PSU_restart_f = 0;
1970 char *cp, *np;
1971
1972 PM_flag[recurses+1] = PM_NORMAL; //assume normal mode for next level
1973 PM_file[recurses+1] = -1; //assume that no special file is needed
1974
1975restart_copy: //restart point for PM_PSU_RESTORE to reprocess modified arguments
1976
1977 newfile = file; //assume that no renaming is to be done
1978
1979 if(PasteMode==PM_RENAME && recurses==0){ //if renaming requested and valid
1980 if(keyboard(newfile.name, 36)<=0) //if name entered by user made the result invalid
1981 strcpy(newfile.name, file.name); // recopy newname from file.name
1982 } //ends if clause for renaming name entry
1983 //Here the struct 'newfile' is FILEINFO for destination, regardless of renaming
1984 //for non-renaming cases this is always identical to the struct 'file'
1985
1986 if(!strncmp(inPath, "hdd", 3)){
1987 hddin = TRUE;
1988 getHddParty(inPath, &file, inParty, in);
1989 pfsin = mountParty(inParty);
1990 in[3]=pfsin+'0';
1991 }else
1992 sprintf(in, "%s%s", inPath, file.name);
1993
1994 if(!strncmp(outPath, "hdd", 3)){
1995 hddout = TRUE;
1996 getHddParty(outPath, &newfile, outParty, out);
1997 pfsout = mountParty(outParty);
1998 out[3]=pfsout+'0';
1999 }else
2000 sprintf(out, "%s%s", outPath, newfile.name);
2001
2002 if(!strcmp(in, out)) return 0; //if in and out are identical our work is done.
2003
2004//Here 'in' and 'out' are complete pathnames for the object to copy
2005//patched to contain appropriate 'pfs' refs where args used 'hdd'
2006//The physical device specifiers remain in 'inPath' and 'outPath'
2007
2008//Here we have an object to copy, which may be either a file or a folder
2009 if(file.stats.attrFile & MC_ATTR_SUBDIR){
2010//Here we have a folder to copy, starting with an attempt to create it
2011//This is where we must act differently for PSU backup, creating a PSU file instead
2012 if(PasteMode==PM_PSU_BACKUP){
2013 if(recurses)
2014 return -1; //abort, as subfolders are not copied to PSU backups
2015 i = strlen(out)-1;
2016 if(out[i]=='/')
2017 out[i] = 0;
2018 strcpy(tmp, out);
2019 np = tmp+strlen(tmp)-strlen(file.name); //np = start of the pure filename
2020 cp = tmp+strlen(tmp); //cp = end of the pure filename
2021 if(!setting->PSU_HugeNames)
2022 cp = np; //cp = start of the pure filename
2023
2024 if((file_show==2) || setting->PSU_HugeNames){ //at request, use game title
2025 ret = getGameTitle(inPath, &file, file.title);
2026 if((ret == 0) && file.title[0] && setting->PSU_HugeNames){
2027 *cp++ = '_';
2028 *cp = '\0';
2029 }
2030 transcpy_sjis(cp, file.title);
2031 }
2032 //Here game title has been used for the name if requested, either alone
2033 //or combined with the original folder name (for PSU_HugeNames)
2034
2035 if(np[0] == 0) //If name is now empty (bad gamesave title)
2036 strcpy(np, file.name); //revert to normal folder name
2037
2038 for(i=0; np[i];) {
2039 i = strcspn(np, "\"\\/:*?<>|"); //Filter out illegal name characters
2040 if(np[i])
2041 np[i] = '_';
2042 }
2043 //Here illegal characters, from either title or original folder name
2044 //have been filtered out (replaced by underscore) to ensure compatibility
2045
2046 cp = tmp+strlen(tmp); //set cp pointing to the end of the filename
2047 if(setting->PSU_DateNames){ //at request, append modification timestamp string
2048 sprintf(cp, "_%04d-%02d-%02d_%02d-%02d-%02d",
2049 mcT_head_p->mTime.year, mcT_head_p->mTime.month, mcT_head_p->mTime.day,
2050 mcT_head_p->mTime.hour, mcT_head_p->mTime.min, mcT_head_p->mTime.sec);
2051 }
2052 //Here a timestamp has been added to the name if requested by PSU_DateNames
2053
2054 genLimObjName(tmp, 4); //Limit name to leave room for 4 characters more
2055 strcat(tmp, ".psu"); //add the PSU file extension
2056
2057 if(!strncmp(tmp, "host:/", 6))
2058 makeHostPath(tmp+5, tmp+6);
2059
2060 if(setting->PSU_DateNames && setting->PSU_NoOverwrite){
2061 if(0 <= (out_fd = genOpen(tmp, O_RDONLY))){ //Name conflict ?
2062 genClose(out_fd);
2063 out_fd=-1;
2064 return 0;
2065 }
2066 }
2067 //here tmp is the name of an existing file, to be removed before making new one
2068 genRemove(tmp);
2069 if(0 > (out_fd = genOpen(tmp, O_WRONLY | O_TRUNC | O_CREAT)))
2070 return -1; //return error on failure to create PSU file
2071
2072 PM_file[recurses+1] = out_fd;
2073 PM_flag[recurses+1] = PM_PSU_BACKUP; //Set PSU backup mode for next level
2074 clear_psu_header(&PSU_head);
2075 PSU_content = 2; //2 content headers minimum, for empty PSU
2076 PSU_head.attr = mcT_head_p->attr;
2077 PSU_head.size = PSU_content;
2078 PSU_head.cTime = mcT_head_p->cTime;
2079 PSU_head.mTime = mcT_head_p->mTime;
2080 memcpy(PSU_head.name, mcT_head_p->name, sizeof(PSU_head.name));
2081 PSU_head.unknown_1_u16 = mcT_head_p->unknown_1_u16;
2082 PSU_head.unknown_2_u64 = mcT_head_p->unknown_2_u64;
2083 size = genWrite(out_fd, (void *) &PSU_head, sizeof(PSU_head));
2084 if(size != sizeof(PSU_head)){
2085PSU_error:
2086 genClose(PM_file[recurses+1]);
2087 return -1;
2088 }
2089 clear_psu_header(&PSU_head);
2090 PSU_head.attr = 0x8427; //Standard folder attr, for pseudo "." and ".."
2091 PSU_head.cTime = mcT_head_p->cTime;
2092 PSU_head.mTime = mcT_head_p->mTime;
2093 PSU_head.name[0] = '.'; //Set name entry to "."
2094 size = genWrite(out_fd, (void *) &PSU_head, sizeof(PSU_head));
2095 if(size != sizeof(PSU_head)) goto PSU_error;
2096 PSU_head.name[1] = '.'; //Change name entry to ".."
2097 size = genWrite(out_fd, (void *) &PSU_head, sizeof(PSU_head));
2098 if(size != sizeof(PSU_head)) goto PSU_error;
2099 } else { //any other PasteMode than PM_PSU_BACKUP
2100 ret = newdir(outPath, newfile.name);
2101 if(ret == -17){ //NB: 'newdir' must return -17 for ALL pre-existing folder cases
2102 ret = getGameTitle(outPath, &newfile, newfile.title);
2103 transcpy_sjis(tmp, newfile.title);
2104 sprintf(progress,
2105 "%s:\n"
2106 "%s%s/\n"
2107 "\n"
2108 "%s:\n",
2109 LNG(Name_conflict_for_this_folder), outPath,
2110 file.name, LNG(With_gamesave_title));
2111 if(tmp[0])
2112 strcat(progress, tmp);
2113 else
2114 strcat(progress, LNG(Undefined_Not_a_gamesave));
2115 sprintf(tmp, "\n\n%s ?", LNG(Do_you_wish_to_overwrite_it));
2116 strcat(progress, tmp);
2117 if(ynDialog(progress)<0) return -1;
2118 if( (PasteMode == PM_MC_BACKUP)
2119 || (PasteMode == PM_MC_RESTORE)
2120 || (PasteMode == PM_PSU_RESTORE)
2121 ) {
2122 ret = delete(outPath, &newfile); //Attempt recursive delete
2123 if(ret < 0) return -1;
2124 if(newdir(outPath, newfile.name) < 0) return -1;
2125 }
2126 drawMsg(LNG(Pasting));
2127 } else if(ret < 0){
2128 return -1; //return error for failure to create destination folder
2129 }
2130 }
2131//Here a destination folder, or a PSU file exists, ready to receive files
2132 if(PasteMode==PM_MC_BACKUP){ //MC Backup mode folder paste preparation
2133 sprintf(tmp, "%s/PS2_MC_Backup_Attributes.BUP.bin", out);
2134 genRemove(tmp);
2135 out_fd = genOpen(tmp, O_WRONLY | O_CREAT);
2136
2137 if(out_fd>=0){
2138 size = genWrite(out_fd, (void *) &file.stats, 64);
2139 if(size == 64){
2140 PM_file[recurses+1] = out_fd;
2141 PM_flag[recurses+1] = PM_MC_BACKUP;
2142 }
2143 else
2144 genClose(PM_file[recurses+1]);
2145 }
2146 } else if(PasteMode==PM_MC_RESTORE){ //MC Restore mode folder paste preparation
2147 sprintf(tmp, "%s/PS2_MC_Backup_Attributes.BUP.bin", in);
2148
2149 if(!strncmp(tmp, "host:/", 6))
2150 makeHostPath(tmp+5, tmp+6);
2151 in_fd = genOpen(tmp, O_RDONLY);
2152
2153 if(in_fd>=0){
2154 size = genRead(in_fd, (void *) &file.stats, 64); //Read stats for the save folder
2155 if(size == 64){
2156 PM_file[recurses+1] = in_fd;
2157 PM_flag[recurses+1] = PM_MC_RESTORE;
2158 }
2159 else
2160 genClose(PM_file[recurses+1]);
2161 }
2162 }
2163 if(PM_flag[recurses+1]==PM_NORMAL){ //Normal mode folder paste preparation
2164 }
2165 sprintf(in, "%s%s/", inPath, file.name); //restore phys dev spec to 'in'
2166 sprintf(out, "%s%s", outPath, newfile.name); //restore phys dev spec to 'out'
2167 genLimObjName(out, 0); //Limit dest folder name
2168 strcat(out, "/"); //Separate dest folder name
2169
2170 if(PasteMode == PM_PSU_RESTORE && PSU_restart_f) {
2171 nfiles = PSU_content;
2172 for(i=0; i<nfiles; i++) {
2173 size = genRead(PM_file[recurses+1], (void *) &PSU_head, sizeof(PSU_head));
2174 if(size != sizeof(PSU_head)) { //Break with error on read failure
2175 ret = -1;
2176 break;
2177 }
2178 if( (PSU_head.size == 0)
2179 && (PSU_head.attr & MC_ATTR_SUBDIR))//Dummy/Pseudo folder entry ?
2180 continue; //Just ignore dummies
2181 if(PSU_head.attr & MC_ATTR_SUBDIR) { //break with error on weird folder in PSU
2182 ret = -1;
2183 break;
2184 }
2185 if(PSU_head.size & 0x3FF) //Check if file is padded in PSU
2186 psu_pad_size = 0x400-(PSU_head.size & 0x3FF);
2187 else
2188 psu_pad_size = 0;
2189 //here we need to create a proper FILEINFO struct for PSU-contained file
2190 mcT_files_p->attr = PSU_head.attr;
2191 mcT_files_p->size = PSU_head.size;
2192 mcT_files_p->cTime = PSU_head.cTime;
2193 mcT_files_p->mTime = PSU_head.mTime;
2194 memcpy(mcT_files_p->name, PSU_head.name, sizeof(PSU_head.name));
2195 mcT_files_p->unknown_1_u16 = PSU_head.unknown_1_u16;
2196 mcT_files_p->unknown_2_u64 = PSU_head.unknown_2_u64;
2197 memcpy(files[0].name, PSU_head.name, sizeof(PSU_head.name));
2198 files[0].name[sizeof(PSU_head.name)] = 0;
2199 //Finally we can make the recursive call
2200 if((ret = copy(out, in, files[0], recurses+1)) < 0)
2201 break;
2202 //We must also step past any file padding, for next header
2203 if(psu_pad_size)
2204 genLseek(PM_file[recurses+1], psu_pad_size, SEEK_CUR);
2205 //finally, we must adjust attributes of the new file copy, to ensure
2206 //correct timestamps and attributes (requires MC-specific functions)
2207 strcpy(tmp, out);
2208 strncat(tmp, files[0].stats.name, 32);
2209 mcGetInfo(tmp[2]-'0', 0, &dummy, &dummy, &dummy); //Wakeup call
2210 mcSync(0, NULL, &dummy);
2211 mcSetFileInfo(tmp[2]-'0', 0, &tmp[4], &files[0].stats, MC_SFI); //Fix file stats
2212 mcSync(0, NULL, &dummy);
2213 } //ends main for loop of valid PM_PSU_RESTORE mode
2214 genClose(PM_file[recurses+1]); //Close the PSU file
2215 //Finally fix the stats of the containing folder
2216 //It has to be done last, as timestamps would change when fixing files
2217 //--- This has been moved to a later clause, shared with PM_MC_RESTORE ---
2218 } else { //Any other mode than a valid PM_PSU_RESTORE
2219 nfiles = getDir(in, files);
2220 for(i=0; i<nfiles; i++) {
2221 if((ret = copy(out, in, files[i], recurses+1)) < 0)
2222 break;
2223 } //ends main for loop for all modes other than valid PM_PSU_RESTORE
2224 }
2225//folder contents are copied by the recursive call above, with error handling below
2226 if(ret<0){
2227 if(PM_flag[recurses+1]==PM_PSU_BACKUP) goto PSU_error;
2228 else return -1;
2229 }
2230
2231//Here folder contents have been copied error-free, but we also need to copy
2232//attributes and timestamps, and close the attribute/PSU file if such was used
2233//Lots of stuff need to be done here to make PSU operations work properly
2234 if(PM_flag[recurses+1]==PM_MC_BACKUP){ //MC Backup mode folder paste closure
2235 genClose(PM_file[recurses+1]);
2236 } else if(PM_flag[recurses+1]==PM_PSU_BACKUP){ //PSU Backup mode folder paste closure
2237 genLseek(PM_file[recurses+1], 0, SEEK_SET);
2238 clear_psu_header(&PSU_head);
2239 PSU_head.attr = mcT_head_p->attr;
2240 PSU_head.size = PSU_content;
2241 PSU_head.cTime = mcT_head_p->cTime;
2242 PSU_head.mTime = mcT_head_p->mTime;
2243 memcpy(PSU_head.name, mcT_head_p->name, sizeof(PSU_head.name));
2244 PSU_head.unknown_1_u16 = mcT_head_p->unknown_1_u16;
2245 PSU_head.unknown_2_u64 = mcT_head_p->unknown_2_u64;
2246 size = genWrite(PM_file[recurses+1], (void *) &PSU_head, sizeof(PSU_head));
2247 genLseek(PM_file[recurses+1], 0, SEEK_END);
2248 genClose(PM_file[recurses+1]);
2249 } else if(PM_flag[recurses+1]==PM_MC_RESTORE){ //MC Restore mode folder paste closure
2250 in_fd = PM_file[recurses+1];
2251 for(size=64, i=0; size==64;){
2252 size = genRead(in_fd, (void *) &stats, 64);
2253 if(size == 64){
2254 strcpy(tmp, out);
2255 strncat(tmp, stats.name, 32);
2256 mcGetInfo(tmp[2]-'0', 0, &dummy, &dummy, &dummy); //Wakeup call
2257 mcSync(0, NULL, &dummy);
2258 mcSetFileInfo(tmp[2]-'0', 0, &tmp[4], &stats, MC_SFI); //Fix file stats
2259 mcSync(0, NULL, &dummy);
2260 } else {
2261 genClose(in_fd);
2262 }
2263 }
2264 //Finally fix the stats of the containing folder
2265 //It has to be done last, as timestamps would change when fixing files
2266 //--- This has been moved to a later clause, shared with PM_PSU_RESTORE ---
2267 } else if(PM_flag[recurses+1]==PM_NORMAL){ //Normal mode folder paste closure
2268 if(!strncmp(out, "mc", 2)){ //Handle folder copied to MC
2269 mcGetInfo(out[2]-'0', 0, &dummy, &dummy, &dummy); //Wakeup call
2270 mcSync(0, NULL, &dummy);
2271 ret = MC_SFI; //default request for changing entire mcTable
2272 if(strncmp(in, "mc", 2)){ //Handle file copied from non-MC to MC
2273 file.stats.attrFile = MC_ATTR_norm_folder; //normalize MC folder attribute
2274 if(!strncmp(in, "host", 4)){ //Handle folder copied from host: to MC
2275 ret = 4; //request change only of main attribute for host:
2276 } //ends host: source clause
2277 } //ends non-MC source clause
2278 mcSetFileInfo(out[2]-'0', 0, &out[4], &file.stats, ret);
2279 mcSync(0, NULL, &dummy);
2280 } else { //Handle folder copied to non-MC
2281 if(!strncmp(out, "pfs", 3)){ //for pfs on HDD we use fileXio_ stuff
2282 memcpy(iox_stat.ctime, (void *) &file.stats._create, 8);
2283 memcpy(iox_stat.mtime, (void *) &file.stats._modify, 8);
2284 memcpy(iox_stat.atime, iox_stat.mtime, 8);
2285 ret = FIO_CST_CT|FIO_CST_AT|FIO_CST_MT; //Request timestamp stat change
2286 if(!strncmp(in, "host", 4)){ //Handle folder copied from host:
2287 ret = 0; //Request NO stat change
2288 }
2289//// dummy = fileXioChStat(out, &iox_stat, ret); //disabled due to bugs
2290 } else if(!strncmp(out, "host", 4)) { //for files copied to host: we skip Chstat
2291 } else if(!strncmp(out, "mass", 4)) { //for files copied to mass: we skip Chstat
2292 } else { //for other devices we use fio_ stuff
2293 memcpy(fio_stat.ctime, (void *) &file.stats._create, 8);
2294 memcpy(fio_stat.mtime, (void *) &file.stats._modify, 8);
2295 memcpy(fio_stat.atime, fio_stat.mtime, 8);
2296 ret = FIO_CST_CT|FIO_CST_AT|FIO_CST_MT; //Request timestamp stat change
2297 if(!strncmp(in, "host", 4)){ //Handle folder copied from host:
2298 ret = 0; //Request NO stat change
2299 }
2300 dummy = fioChstat(out, &fio_stat, ret); //(no such devices yet)
2301 }
2302 }
2303 }
2304 if( (PM_flag[recurses+1]==PM_MC_RESTORE)
2305 || (PM_flag[recurses+1]==PM_PSU_RESTORE)) {
2306 //Finally fix the stats of the containing folder
2307 //It has to be done last, as timestamps would change when fixing files
2308 mcGetInfo(out[2]-'0', 0, &dummy, &dummy, &dummy); //Wakeup call
2309 mcSync(0, NULL, &dummy);
2310 mcSetFileInfo(out[2]-'0', 0, &out[4], &file.stats, MC_SFI); //Fix folder stats
2311 mcSync(0, NULL, &dummy);
2312 }
2313//the return code below is used if there were no errors copying a folder
2314 return 0;
2315 }
2316
2317//Here we know that the object to copy is a file, not a folder
2318//But in PSU Restore mode we must treat PSU files as special folders, at level 0.
2319//and recursively call copy with higher recurse level to process the contents
2320 if(PasteMode==PM_PSU_RESTORE && recurses==0){
2321 cp = strrchr(in, '.');
2322 if((cp==NULL) || stricmp(cp, ".psu") )
2323 goto non_PSU_RESTORE_init; //if not a PSU file, go do normal pasting
2324
2325 in_fd = genOpen(in, O_RDONLY);
2326
2327 if(in_fd < 0)
2328 return -1;
2329 size = genRead(in_fd, (void *) &PSU_head, sizeof(PSU_head));
2330 if(size != sizeof(PSU_head)){
2331 genClose(in_fd);
2332 return -1;
2333 }
2334 PM_file[recurses+1] = in_fd; //File descriptor for PSU
2335 PM_flag[recurses+1] = PM_PSU_RESTORE; //Mode flag for recursive entry
2336 //Here we need to prep the file struct to appear like a normal MC folder
2337 //before 'restarting' this 'copy' to handle creation of destination folder
2338 //as well as the copying of files from the PSU into that folder
2339 mcT_head_p->attr = PSU_head.attr;
2340 PSU_content = PSU_head.size;
2341 mcT_head_p->size = 0;
2342 mcT_head_p->cTime = PSU_head.cTime;
2343 mcT_head_p->mTime = PSU_head.mTime;
2344 memcpy(mcT_head_p->name, PSU_head.name, sizeof(PSU_head.name));
2345 mcT_head_p->unknown_1_u16 = PSU_head.unknown_1_u16;
2346 mcT_head_p->unknown_2_u64 = PSU_head.unknown_2_u64;
2347 memcpy(file.name, PSU_head.name, sizeof(PSU_head.name));
2348 file.name[sizeof(PSU_head.name)] = 0;
2349 PSU_restart_f = 1;
2350 goto restart_copy;
2351 }
2352non_PSU_RESTORE_init:
2353//In MC Restore mode we must here avoid copying the attribute file
2354 if(PM_flag[recurses]==PM_MC_RESTORE)
2355 if(!strcmp(file.name,"PS2_MC_Backup_Attributes.BUP.bin"))
2356 return 0;
2357
2358//It is now time to open the input file, indicated by 'in_fd'
2359//But in PSU Restore mode we must use the already open PSU file instead
2360 if(PM_flag[recurses]==PM_PSU_RESTORE){
2361 in_fd = PM_file[recurses];
2362 size = mcT_head_p->size;
2363 }
2364 else { //Any other mode than PM_PSU_RESTORE
2365 if (!strncmp(in, "host:/", 6))
2366 makeHostPath(in+5, in+6);
2367 in_fd = genOpen(in, O_RDONLY);
2368 if(in_fd<0) goto copy_file_exit;
2369 size = genLseek(in_fd,0,SEEK_END);
2370 genLseek(in_fd,0,SEEK_SET);
2371 }
2372
2373//Here the input file has been opened, indicated by 'in_fd'
2374//It is now time to open the output file, indicated by 'out_fd'
2375//except in the case of a PSU backup, when we must add a header to PSU instead
2376 if(PM_flag[recurses]==PM_PSU_BACKUP){
2377 out_fd = PM_file[recurses];
2378 clear_psu_header(&PSU_head);
2379 PSU_head.attr = mcT_head_p->attr;
2380 PSU_head.size = mcT_head_p->size;
2381 PSU_head.cTime = mcT_head_p->cTime;
2382 PSU_head.mTime = mcT_head_p->mTime;
2383 memcpy(PSU_head.name, mcT_head_p->name, sizeof(PSU_head.name));
2384 genWrite(out_fd, (void *) &PSU_head, sizeof(PSU_head));
2385 if(PSU_head.size & 0x3FF)
2386 psu_pad_size = 0x400-(PSU_head.size & 0x3FF);
2387 else
2388 psu_pad_size = 0;
2389 PSU_content++; //Increase PSU content header count
2390 } else { //Any other PasteMode than PM_PSU_BACKUP needs a new output file
2391 if (!strncmp(out, "host:/", 6))
2392 makeHostPath(out+5, out+6);
2393 genLimObjName(out, 0); //Limit dest file name
2394 genRemove(out); //Remove old file if present
2395 out_fd=genOpen(out, O_WRONLY | O_TRUNC | O_CREAT); //Create new file
2396 if(out_fd<0) goto copy_file_exit;
2397 }
2398
2399//Here the output file has been opened, indicated by 'out_fd'
2400
2401 buffSize = 0x100000; //First assume buffer size = 1MB (good for HDD)
2402 if(!strncmp(out, "mass", 4) || !strncmp(out, "vmc", 3))
2403 buffSize = 50000; //Use 50000 if writing to USB (Flash RAM writes)
2404//VMC contents should use the same size, as VMCs will often be stored on USB
2405 else if(!strncmp(out, "mc", 2))
2406 buffSize = 125000; //Use 125000 if writing to MC (pretty slow too)
2407 else if(!strncmp(in, "mc",2))
2408 buffSize = 200000; //Use 200000 if reading from MC (still pretty slow)
2409 else if(!strncmp(out, "host", 4))
2410 buffSize = 350000; //Use 350000 if writing to HOST (acceptable)
2411 else if((!strncmp(in, "mass", 4)) || (!strncmp(in, "host", 4)))
2412 buffSize = 500000; //Use 500000 reading from USB or HOST (acceptable)
2413
2414 if(size < buffSize)
2415 buffSize = size;
2416
2417 buff = (char*)malloc(buffSize); //Attempt buffer allocation
2418 if(buff==NULL){ //if allocation fails
2419 buffSize = 32768; //Set buffsize to 32KB
2420 buff = (char*)malloc(buffSize); //Allocate 32KB buffer
2421 }
2422
2423 old_size = written_size; //Note initial progress data pos
2424 OldTime = Timer(); //Note initial progress time
2425
2426 while(size>0){ // ----- The main copying loop starts here -----
2427
2428 if(size < buffSize)
2429 buffSize = size; //Adjust effective buffer size to remaining data
2430
2431 TimeDiff = Timer()-OldTime;
2432 OldTime = Timer();
2433 SizeDiff = written_size-old_size;
2434 old_size = written_size;
2435 if(SizeDiff){ //if anything was written this time
2436 speed = (SizeDiff * 1000)/TimeDiff; //calc real speed
2437 remain_time = size / speed; //calc time remaining for that speed
2438 }else if(TimeDiff){ //if nothing written though time passed
2439 speed = 0; //set speed as zero
2440 remain_time = -1; //set time remaining as unknown
2441 }else{ //if nothing written and no time passed
2442 speed = -1; //set speed as unknown
2443 remain_time = -1; //set time remaining as unknown
2444 }
2445
2446 sprintf(progress, "%s : %s", LNG(Pasting_file), file.name);
2447
2448 sprintf(tmp, "\n%s : ", LNG(Remain_Size));
2449 strcat(progress, tmp);
2450 if(size<=1024)
2451 sprintf(tmp, "%lu %s", (long)size, LNG(bytes)); // bytes
2452 else
2453 sprintf(tmp, "%lu %s", (long)size/1024, LNG(Kbytes)); // Kbytes
2454 strcat(progress, tmp);
2455
2456 sprintf(tmp, "\n%s: ", LNG(Current_Speed));
2457 strcat(progress, tmp);
2458 if(speed==-1)
2459 strcpy(tmp, LNG(Unknown));
2460 else if(speed<=1024)
2461 sprintf(tmp, "%d %s/sec", speed, LNG(bytes)); // bytes/sec
2462 else
2463 sprintf(tmp, "%d %s/sec", speed/1024, LNG(Kbytes)); //Kbytes/sec
2464 strcat(progress, tmp);
2465
2466 sprintf(tmp, "\n%s : ", LNG(Remain_Time));
2467 strcat(progress, tmp);
2468 if(remain_time==-1)
2469 strcpy(tmp, LNG(Unknown));
2470 else if(remain_time<60)
2471 sprintf(tmp, "%d sec", remain_time); // sec
2472 else if(remain_time<3600)
2473 sprintf(tmp, "%d m %d sec", remain_time/60, remain_time%60); // min,sec
2474 else
2475 sprintf(tmp, "%d h %d m %d sec", remain_time/3600, (remain_time%3600)/60, remain_time%60); // hour,min,sec
2476 strcat(progress, tmp);
2477
2478 sprintf(tmp, "\n\n%s: ", LNG(Written_Total));
2479 strcat(progress, tmp);
2480 sprintf(tmp, "%ld %s", written_size/1024, LNG(Kbytes)); //Kbytes
2481 strcat(progress, tmp);
2482
2483 sprintf(tmp, "\n%s: ", LNG(Average_Speed));
2484 strcat(progress, tmp);
2485 TimeDiff = Timer()-PasteTime;
2486 if(TimeDiff == 0)
2487 strcpy(tmp, LNG(Unknown));
2488 else {
2489 speed = (written_size * 1000)/TimeDiff; //calc real speed
2490 if(speed<=1024)
2491 sprintf(tmp, "%d %s/sec", speed, LNG(bytes)); // bytes/sec
2492 else
2493 sprintf(tmp, "%d %s/sec", speed/1024, LNG(Kbytes)); //Kbytes/sec
2494 }
2495 strcat(progress, tmp);
2496
2497 if(PasteProgress_f) //if progress report was used earlier in this pasting
2498 nonDialog(NULL); //order cleanup for that screen area
2499 nonDialog(progress); //Make new progress report
2500 PasteProgress_f = 1; //and note that it was done for next time
2501 drawMsg(file.name);
2502 if(readpad() && new_pad){
2503 if(-1 == ynDialog(LNG(Continue_transfer))) {
2504 genClose(out_fd); out_fd=-1;
2505 if(PM_flag[recurses]!=PM_PSU_BACKUP)
2506 genRemove(out);
2507 ret = -1; // flag generic error
2508 goto copy_file_exit; // go deal with it
2509 }
2510 }
2511 //buffSize = genRead(in_fd, buff, buffSize);
2512 genRead(in_fd, buff, buffSize);
2513 if(buffSize > 0){
2514 outsize = genWrite(out_fd, buff, buffSize);
2515 }
2516// if((buffSize <= 0) || (buffSize!=outsize)){
2517 if(buffSize <= 0){
2518 genClose(out_fd); out_fd=-1;
2519 if(PM_flag[recurses]!=PM_PSU_BACKUP)
2520 genRemove(out);
2521 ret = -1; // flag generic error
2522 goto copy_file_exit;
2523 }
2524 size -= buffSize;
2525 written_size += buffSize;
2526 } // ends while(size>0), ----- The main copying loop ends here -----
2527 ret=0;
2528//Here the file has been copied. without error, as indicated by 'ret' above
2529//but we also need to copy attributes and timestamps (as yet only for MC)
2530//For PSU backup output padding may be needed, but not output file closure
2531 if(PM_flag[recurses]==PM_PSU_BACKUP){
2532 if(psu_pad_size){
2533 pad_psu_header(&PSU_head);
2534 if(psu_pad_size >= sizeof(PSU_head)){
2535 genWrite(out_fd, (void *) &PSU_head, sizeof(PSU_head));
2536 psu_pad_size -= sizeof(PSU_head);
2537 }
2538 if(psu_pad_size)
2539 genWrite(out_fd, (void *) &PSU_head, psu_pad_size);
2540 }
2541 out_fd = -1; //prevent output file closure below
2542 goto copy_file_exit;
2543 }
2544
2545 if(PM_flag[recurses]==PM_MC_BACKUP){ //MC Backup mode file paste closure
2546 size = genWrite(PM_file[recurses], (void *) &file.stats, 64);
2547 if(size != 64) return -1; //Abort if attribute file crashed
2548 }
2549
2550 if(out_fd>=0){
2551 genClose(out_fd);
2552 out_fd = -1; //prevent dual closure attempt
2553 }
2554
2555 if(!strncmp(out, "mc", 2)){ //Handle file copied to MC
2556 mcGetInfo(out[2]-'0', 0, &mctype_PSx, &dummy, &dummy); //Wakeup call & MC type check
2557 mcSync(0, NULL, &dummy);
2558 ret = MC_SFI; //default request for changing entire mcTable
2559 if(strncmp(in, "mc", 2)){ //Handle file copied from non-MC to MC
2560 file.stats.attrFile = MC_ATTR_norm_file; //normalize MC file attribute
2561 if(!strncmp(in, "host", 4)){ //Handle folder copied from host: to MC
2562 ret = 4; //request change only of main attribute for host:
2563 } //ends host: source clause
2564 } //ends non-MC source clause
2565 if(mctype_PSx == 2){ //if copying to a PS2 MC
2566 mcSetFileInfo(out[2]-'0', 0, &out[4], &file.stats, ret);
2567 mcSync(0, NULL, &dummy);
2568 }
2569 } else { //Handle file copied to non-MC
2570 if(!strncmp(out, "pfs", 3)){ //for pfs on HDD we use fileXio_ stuff
2571 memcpy(iox_stat.ctime, (void *) &file.stats._create, 8);
2572 memcpy(iox_stat.mtime, (void *) &file.stats._modify, 8);
2573 memcpy(iox_stat.atime, iox_stat.mtime, 8);
2574 ret = FIO_CST_CT|FIO_CST_AT|FIO_CST_MT; //Request timestamp stat change
2575 if(!strncmp(in, "host", 4)){ //Handle file copied from host:
2576 ret = 0; //Request NO stat change
2577 }
2578//// dummy = fileXioChStat(out, &iox_stat, ret); //disabled due to bugs
2579 } else if(!strncmp(out, "host", 4)) { //for files copied to host: we skip Chstat
2580 } else if(!strncmp(out, "mass", 4)) { //for files copied to mass: we skip Chstat
2581 } else { //for other devices we use fio_ stuff
2582 memcpy(fio_stat.ctime, (void *) &file.stats._create, 8);
2583 memcpy(fio_stat.mtime, (void *) &file.stats._modify, 8);
2584 memcpy(fio_stat.atime, fio_stat.mtime, 8);
2585 ret = FIO_CST_CT|FIO_CST_AT|FIO_CST_MT; //Request timestamp stat change
2586 if(!strncmp(in, "host", 4)){ //Handle file copied from host:
2587 ret = 0; //Request NO stat change
2588 }
2589 dummy = fioChstat(out, &fio_stat, ret); //(no such devices yet)
2590 }
2591 }
2592
2593//The code below is also used for all errors in copying a file,
2594//but those cases are distinguished by a negative value in 'ret'
2595copy_file_exit:
2596 free(buff);
2597 if(PM_flag[recurses]!=PM_PSU_RESTORE){ //Avoid closing PSU file here for PSU Restore
2598 if(in_fd>=0){
2599 genClose(in_fd);
2600 }
2601 }
2602 if(out_fd>=0){
2603 genClose(out_fd);
2604 }
2605 return ret;
2606}
2607//------------------------------
2608//endfunc copy
2609//--------------------------------------------------------------
2610//dlanor: For v3.64 the virtual keyboard function is modified to
2611//allow entry of empty strings. The function now returns string
2612//length, except if you use 'CANCEL' when it returns -1 instead.
2613//Routines that require a non-empty string (eg: Rename, Newdir)
2614//must test with '>' now, instead of '>=' as used previously.
2615//--------------------------------------------------------------
2616int keyboard(char *out, int max)
2617{
2618 int event, post_event=0;
2619 const int
2620 WFONTS= 13,
2621 HFONTS= 7,
2622 KEY_W = LINE_THICKNESS+12+(13*FONT_WIDTH+12*12)+12+LINE_THICKNESS,
2623 KEY_H = LINE_THICKNESS + 1 + FONT_HEIGHT + 1
2624 + LINE_THICKNESS + 8 + (8*FONT_HEIGHT) + 8 + LINE_THICKNESS,
2625 KEY_X = ((SCREEN_WIDTH - KEY_W)/2) & -2,
2626 KEY_Y = ((SCREEN_HEIGHT - KEY_H)/2)& -2;
2627 char *KEY="ABCDEFGHIJKLM"
2628 "NOPQRSTUVWXYZ"
2629 "abcdefghijklm"
2630 "nopqrstuvwxyz"
2631 "0123456789/|\\"
2632 "<>(){}[].,:;\""
2633 "!@#$%&=+-^*_'";
2634 int KEY_LEN;
2635 int cur=0, sel=0, i=0, x, y, t=0;
2636 char tmp[256], *p;
2637 unsigned char KeyPress;
2638
2639 p=strrchr(out, '.');
2640 if(p==NULL) cur=strlen(out);
2641 else cur=(int)(p-out);
2642 KEY_LEN = strlen(KEY);
2643
2644 event = 1; //event = initial entry
2645 while(1){
2646 //Pad response section
2647 waitPadReady(0, 0);
2648 if(readpad_no_KB()){
2649 if(new_pad)
2650 event |= 2; //event |= pad command
2651 if(new_pad & PAD_UP){
2652 if(sel<=WFONTS*HFONTS){
2653 if(sel>=WFONTS) sel-=WFONTS;
2654 }else{
2655 sel-=4;
2656 }
2657 }else if(new_pad & PAD_DOWN){
2658 if(sel/WFONTS == HFONTS-1){
2659 if(sel%WFONTS < 5) sel=WFONTS*HFONTS;
2660 else sel=WFONTS*HFONTS+1;
2661 }else if(sel/WFONTS <= HFONTS-2)
2662 sel+=WFONTS;
2663 }else if(new_pad & PAD_LEFT){
2664 if(sel>0) sel--;
2665 }else if(new_pad & PAD_RIGHT){
2666 if(sel<=WFONTS*HFONTS) sel++;
2667 }else if(new_pad & PAD_START){
2668 sel = WFONTS*HFONTS;
2669 }else if(new_pad & PAD_L1){
2670 if(cur>0) cur--;
2671 t=0;
2672 }else if(new_pad & PAD_R1){
2673 if(cur<strlen(out)) cur++;
2674 t=0;
2675 }else if((!swapKeys && new_pad & PAD_CROSS)
2676 || (swapKeys && new_pad & PAD_CIRCLE) ){
2677 if(cur>0){
2678 strcpy(tmp, out);
2679 out[cur-1]=0;
2680 strcat(out, &tmp[cur]);
2681 cur--;
2682 t=0;
2683 }
2684 }else if(new_pad & PAD_SQUARE){ //Square => space
2685 i=strlen(out);
2686 if(i<max && i<33){
2687 strcpy(tmp, out);
2688 out[cur]=' ';
2689 out[cur+1]=0;
2690 strcat(out, &tmp[cur]);
2691 cur++;
2692 t=0;
2693 }
2694 }else if((swapKeys && new_pad & PAD_CROSS)
2695 || (!swapKeys && new_pad & PAD_CIRCLE) ){
2696 i=strlen(out);
2697 if(sel < WFONTS*HFONTS){ //Any char in matrix selected ?
2698 if(i<max && i<33){
2699 strcpy(tmp, out);
2700 out[cur]=KEY[sel];
2701 out[cur+1]=0;
2702 strcat(out, &tmp[cur]);
2703 cur++;
2704 t=0;
2705 }
2706 }else if(sel == WFONTS*HFONTS){ //'OK' exit-button selected ?
2707 break; //break out of loop with i==strlen
2708 }else //Must be 'CANCEL' exit-button
2709 return -1;
2710 }else if(new_pad & PAD_TRIANGLE){
2711 return -1;
2712 }
2713 }
2714
2715 //Kbd response section
2716 if(setting->usbkbd_used && PS2KbdRead(&KeyPress)) {
2717
2718 event |= 2; //event |= pad command
2719
2720 if(KeyPress == PS2KBD_ESCAPE_KEY) {
2721 PS2KbdRead(&KeyPress);
2722 if(KeyPress == 0x29){ // Key Right;
2723 if(cur<strlen(out)) cur++;
2724 t=0;
2725 }else if(KeyPress == 0x2a){ // Key Left;
2726 if(cur>0) cur--;
2727 t=0;
2728 }else if(KeyPress == 0x24){ // Key Home;
2729 cur=0;
2730 t=0;
2731 }else if(KeyPress == 0x27){ // Key End;
2732 cur=strlen(out);
2733 t=0;
2734 }else if(KeyPress == 0x26){ // Key Delete;
2735 if(strlen(out)>cur){
2736 strcpy(tmp, out);
2737 out[cur]=0;
2738 strcat(out, &tmp[cur+1]);
2739 t=0;
2740 }
2741 }else if(KeyPress == 0x1b){ // Key Escape;
2742 return -1;
2743 }
2744 }else{
2745 if(KeyPress == 0x07){ // Key BackSpace;
2746 if(cur>0){
2747 strcpy(tmp, out);
2748 out[cur-1]=0;
2749 strcat(out, &tmp[cur]);
2750 cur--;
2751 t=0;
2752 }
2753 }else if(KeyPress == 0x0a){ // Key Return;
2754 break;
2755 }else{ // All Other Keys;
2756 i=strlen(out);
2757 if(i<max && i<33){
2758 strcpy(tmp, out);
2759 out[cur]=KeyPress;
2760 out[cur+1]=0;
2761 strcat(out, &tmp[cur]);
2762 cur++;
2763 t=0;
2764 }
2765 }
2766 }
2767 KeyPress = '\0';
2768 } //ends if(setting->usbkbd_used && PS2KbdRead(&KeyPress))
2769
2770 t++;
2771
2772 if(t & 0x0F) event |= 4; //repetitive timer event
2773
2774 if(event||post_event){ //NB: We need to update two frame buffers per event
2775
2776 //Display section
2777 drawPopSprite(setting->color[0],
2778 KEY_X, KEY_Y,
2779 KEY_X+KEY_W-1, KEY_Y+KEY_H-1);
2780 drawFrame(
2781 KEY_X, KEY_Y,
2782 KEY_X+KEY_W-1, KEY_Y+KEY_H-1, setting->color[1]);
2783 drawOpSprite(setting->color[1],
2784 KEY_X, KEY_Y+LINE_THICKNESS+1+FONT_HEIGHT+1,
2785 KEY_X+KEY_W-1, KEY_Y+LINE_THICKNESS+1+FONT_HEIGHT+1+LINE_THICKNESS-1);
2786 printXY(out, KEY_X+LINE_THICKNESS+3, KEY_Y+LINE_THICKNESS+1, setting->color[3], TRUE, 0);
2787 if(((event|post_event)&4) && (t & 0x10)){
2788 drawOpSprite(setting->color[2],
2789 KEY_X + LINE_THICKNESS + 1 + cur*8,
2790 KEY_Y + LINE_THICKNESS + 2,
2791 KEY_X + LINE_THICKNESS + 1 + cur*8 + LINE_THICKNESS - 1,
2792 KEY_Y + LINE_THICKNESS + 2 + (FONT_HEIGHT-2) - 1);
2793 }
2794 for(i=0; i<KEY_LEN; i++)
2795 drawChar(KEY[i],
2796 KEY_X + LINE_THICKNESS + 12 + (i%WFONTS)*(FONT_WIDTH+12),
2797 KEY_Y + LINE_THICKNESS + 1 + FONT_HEIGHT + 1
2798 + LINE_THICKNESS + 8 + (i/WFONTS)*FONT_HEIGHT, setting->color[3]);
2799 printXY(LNG(OK),
2800 KEY_X + LINE_THICKNESS + 12,
2801 KEY_Y + LINE_THICKNESS + 1 + FONT_HEIGHT + 1
2802 + LINE_THICKNESS + 8 + HFONTS*FONT_HEIGHT, setting->color[3], TRUE, 0);
2803 printXY(LNG(CANCEL),
2804 KEY_X + KEY_W - 1 - (strlen(LNG(CANCEL))+2)*FONT_WIDTH,
2805 KEY_Y + LINE_THICKNESS + 1 + FONT_HEIGHT + 1
2806 + LINE_THICKNESS + 8 + HFONTS*FONT_HEIGHT, setting->color[3], TRUE, 0);
2807
2808 //Cursor positioning section
2809 if(sel<=WFONTS*HFONTS)
2810 x = KEY_X + LINE_THICKNESS + 12 + (sel%WFONTS)*(FONT_WIDTH+12) - 8;
2811 else
2812 x = KEY_X + KEY_W - 2 - (strlen(LNG(CANCEL))+3)*FONT_WIDTH;
2813 y = KEY_Y + LINE_THICKNESS + 1 + FONT_HEIGHT + 1
2814 + LINE_THICKNESS + 8 + (sel/WFONTS)*FONT_HEIGHT;
2815 drawChar(LEFT_CUR, x, y, setting->color[2]);
2816
2817 //Tooltip section
2818 x = SCREEN_MARGIN;
2819 y = Menu_tooltip_y;
2820 drawSprite(setting->color[0], 0, y-1, SCREEN_WIDTH, y+FONT_HEIGHT);
2821
2822 if (swapKeys){
2823 sprintf(tmp, "ÿ1:%s ÿ0", LNG(Use));
2824 }else{
2825 sprintf(tmp, "ÿ0:%s ÿ1", LNG(Use));
2826 }
2827 sprintf(tmp+strlen(tmp), ":%s ÿ2:%s L1:%s R1:%s START:%s ÿ3:%s",
2828 LNG(BackSpace), LNG(SPACE), LNG(Left), LNG(Right), LNG(Enter), LNG(Exit));
2829 printXY(tmp, x, y, setting->color[2], TRUE, 0);
2830 }//ends if(event||post_event)
2831 drawScr();
2832 post_event = event;
2833 event = 0;
2834 }//ends while
2835 return strlen(out);
2836}
2837//------------------------------
2838//endfunc keyboard
2839//--------------------------------------------------------------
2840//keyboard2 below is used for testing output from a USB keyboard
2841//it can be commented out when not used by the programmer.
2842//When using it for tests, simply replace the call to 'keyboard'
2843//somewhere (Rename routine is a good choice) with a call to
2844//'keyboard2' instead. It uses the old routines for virtual keys
2845//via gamepad, so you can still enter proper strings that way,
2846//but each key pressed on the USB keyboard will be expanded to a
2847//sequence corresponding to sprintf(somestring," %02X ", key).
2848//Thus four characters are added to the output string for each
2849//such key, and after character 32 the cursor loops back to the
2850//first character again.
2851//--------------------------------------------------------------
2852/*
2853int keyboard2(char *out, int max)
2854{
2855 int event, post_event=0;
2856 const int KEY_W=276,
2857 KEY_H=168,
2858 KEY_X=(SCREEN_WIDTH - KEY_W)/2,
2859 KEY_Y=((SCREEN_HEIGHT - KEY_H)/2),
2860 WFONTS=13,
2861 HFONTS=7;
2862 char *KEY="ABCDEFGHIJKLM"
2863 "NOPQRSTUVWXYZ"
2864 "abcdefghijklm"
2865 "nopqrstuvwxyz"
2866 "0123456789 "
2867 "()[]!#$%&@; "
2868 "=+-'^.,_ ";
2869 int KEY_LEN;
2870 int cur=0, sel=0, i=0, x, y, t=0;
2871 char tmp[256], *p;
2872 unsigned char KeyPress;
2873
2874 p=strrchr(out, '.');
2875 if(p==NULL) cur=strlen(out);
2876 else cur=(int)(p-out);
2877 KEY_LEN = strlen(KEY);
2878
2879 event = 1; //event = initial entry
2880 while(1){
2881 //Pad response section
2882 waitPadReady(0, 0);
2883 if(readpad_no_KB()){
2884 if(new_pad)
2885 event |= 2; //event |= pad command
2886 if(new_pad & PAD_UP){
2887 if(sel<=WFONTS*HFONTS){
2888 if(sel>=WFONTS) sel-=WFONTS;
2889 }else{
2890 sel-=4;
2891 }
2892 }else if(new_pad & PAD_DOWN){
2893 if(sel/WFONTS == HFONTS-1){
2894 if(sel%WFONTS < 5) sel=WFONTS*HFONTS;
2895 else sel=WFONTS*HFONTS+1;
2896 }else if(sel/WFONTS <= HFONTS-2)
2897 sel+=WFONTS;
2898 }else if(new_pad & PAD_LEFT){
2899 if(sel>0) sel--;
2900 }else if(new_pad & PAD_RIGHT){
2901 if(sel<=WFONTS*HFONTS) sel++;
2902 }else if(new_pad & PAD_START){
2903 sel = WFONTS*HFONTS;
2904 }else if(new_pad & PAD_L1){
2905 if(cur>0) cur--;
2906 t=0;
2907 }else if(new_pad & PAD_R1){
2908 if(cur<strlen(out)) cur++;
2909 t=0;
2910 }else if((!swapKeys && new_pad & PAD_CROSS)
2911 || (swapKeys && new_pad & PAD_CIRCLE) ){
2912 if(cur>0){
2913 strcpy(tmp, out);
2914 out[cur-1]=0;
2915 strcat(out, &tmp[cur]);
2916 cur--;
2917 t=0;
2918 }
2919 }else if((swapKeys && new_pad & PAD_CROSS)
2920 || (!swapKeys && new_pad & PAD_CIRCLE) ){
2921 i=strlen(out);
2922 if(sel < WFONTS*HFONTS){ //Any char in matrix selected ?
2923 if(i<max && i<33){
2924 strcpy(tmp, out);
2925 out[cur]=KEY[sel];
2926 out[cur+1]=0;
2927 strcat(out, &tmp[cur]);
2928 cur++;
2929 t=0;
2930 }
2931 }else if(sel == WFONTS*HFONTS){ //'OK' exit-button selected ?
2932 break; //break out of loop with i==strlen
2933 }else //Must be 'CANCEL' exit-button
2934 return -1;
2935 }
2936 }
2937
2938 //Kbd response section
2939 if(PS2KbdRead(&KeyPress)) {
2940 strcpy(tmp, out);
2941 sprintf(out+cur," %02X %n",KeyPress, &x);
2942 if(cur+x < strlen(tmp))
2943 strcat(out, tmp+cur+x);
2944 cur+=x;
2945 if(cur>=31)
2946 cur=0;
2947 t=0;
2948 } //ends if(PS2KbdRead(&KeyPress))
2949
2950 t++;
2951
2952 if(t & 0x0F) event |= 4; //repetitive timer event
2953
2954 if(event||post_event){ //NB: We need to update two frame buffers per event
2955
2956 //Display section
2957 drawPopSprite(setting->color[0],
2958 KEY_X, KEY_Y,
2959 KEY_X+KEY_W, KEY_Y+KEY_H);
2960 drawFrame(
2961 KEY_X, KEY_Y,
2962 KEY_X+KEY_W, KEY_Y+KEY_H, setting->color[1]);
2963 drawOpSprite(setting->color[1],
2964 KEY_X, KEY_Y+20,
2965 KEY_X+KEY_W, KEY_Y+20+LINE_THICKNESS);
2966 printXY(out, KEY_X+2+3, KEY_Y+3, setting->color[3], TRUE, 0);
2967 if(((event|post_event)&4) && (t & 0x10)){
2968 printXY("|",
2969 KEY_X+cur*8+1, KEY_Y+3, setting->color[3], TRUE, 0);
2970 }
2971 for(i=0; i<KEY_LEN; i++)
2972 drawChar(KEY[i],
2973 KEY_X+2+4 + (i%WFONTS+1)*20 - 12,
2974 KEY_Y+28 + (i/WFONTS)*16,
2975 setting->color[3]);
2976 printXY("OK CANCEL",
2977 KEY_X+2+4 + 20 - 12, KEY_Y+28 + HFONTS*16, setting->color[3], TRUE, 0);
2978
2979 //Cursor positioning section
2980 if(sel<=WFONTS*HFONTS)
2981 x = KEY_X+2+4 + (sel%WFONTS+1)*20 - 20;
2982 else
2983 x = KEY_X+2+4 + 25*8;
2984 y = KEY_Y+28 + (sel/WFONTS)*16;
2985 drawChar(LEFT_CUR, x, y, setting->color[3]);
2986
2987 //Tooltip section
2988 x = SCREEN_MARGIN;
2989 y = Menu_tooltip_y;
2990 drawSprite(setting->color[0], 0, y-1, SCREEN_WIDTH, y+FONT_HEIGHT);
2991
2992 if (swapKeys)
2993 printXY("ÿ1:OK ÿ0:Back L1:Left R1:Right START:Enter",
2994 x, y, setting->color[2], TRUE, 0);
2995 else
2996 printXY("ÿ0:OK ÿ1:Back L1:Left R1:Right START:Enter",
2997 x, y, setting->color[2], TRUE, 0);
2998 }//ends if(event||post_event)
2999 drawScr();
3000 post_event = event;
3001 event = 0;
3002 }//ends while
3003 return i;
3004}
3005*/
3006//------------------------------
3007//endfunc keyboard2 (commented out except in testing)
3008//--------------------------------------------------------------
3009int setFileList(const char *path, const char *ext, FILEINFO *files, int cnfmode)
3010{
3011 char *p;
3012 int nfiles, i, j, ret;
3013
3014 size_valid = 0;
3015 time_valid = 0;
3016
3017 nfiles = 0;
3018 if(path[0]==0){
3019 //-- Start case for browser root pseudo folder with device links --
3020 if(USB_mass_scanned) //if mass drives were scanned in earlier browsing
3021 scan_USB_mass(); //then allow another scan here (timer dependent)
3022
3023 strcpy(files[nfiles].name, "mc0:");
3024 files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
3025 strcpy(files[nfiles].name, "mc1:");
3026 files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
3027 strcpy(files[nfiles].name, "hdd0:");
3028 files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
3029 strcpy(files[nfiles].name, "cdfs:");
3030 files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
3031 if( (cnfmode!=USBD_IRX_CNF)
3032 &&(cnfmode!=USBKBD_IRX_CNF)
3033 &&(cnfmode!=USBMASS_IRX_CNF)) {
3034 //The condition above blocks selecting USB drivers from USB devices
3035 if(USB_mass_ix[0] || !USB_mass_scanned){
3036 strcpy(files[nfiles].name, "mass:");
3037 files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
3038 }
3039 for(i=1; i<10; i++){
3040 if(USB_mass_ix[i]){
3041 strcpy(files[nfiles].name, "mass0:");
3042 files[nfiles].name[4] = USB_mass_ix[i];
3043 files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
3044 }
3045 }
3046 }
3047 if (!cnfmode || (cnfmode==JPG_CNF)) {
3048 //This condition blocks selecting any CONFIG items on PC
3049 //or in a virtual memory card
3050 strcpy(files[nfiles].name, "host:");
3051 files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
3052 if(vmcMounted[0]){
3053 strcpy(files[nfiles].name, "vmc0:");
3054 files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
3055 }
3056 if(vmcMounted[1]){
3057 strcpy(files[nfiles].name, "vmc1:");
3058 files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
3059 }
3060 }
3061 if(cnfmode<2) {
3062 //This condition blocks use of MISC pseudo-device for drivers and skins
3063 //And allows this device only for launch keys and for normal browsing
3064 strcpy(files[nfiles].name, LNG(MISC));
3065 files[nfiles].stats.attrFile = MC_ATTR_SUBDIR;
3066 nfiles++;
3067 }
3068 for(i=0; i<nfiles; i++)
3069 files[i].title[0]=0;
3070 vfreeSpace=FALSE;
3071 //-- End case for browser root pseudo folder with device links --
3072 }else if(!strcmp(path, setting->Misc)){
3073 //-- Start case for MISC command pseudo folder with function links --
3074 nfiles = 0;
3075 strcpy(files[nfiles].name, "..");
3076 files[nfiles++].stats.attrFile = MC_ATTR_SUBDIR;
3077 if(cnfmode) { //Stop recursive FileBrowser entry, only allow it for launch keys
3078 strcpy(files[nfiles].name, LNG(FileBrowser));
3079 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3080 }
3081 strcpy(files[nfiles].name, LNG(PS2Browser));
3082 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3083 strcpy(files[nfiles].name, LNG(PS2Disc));
3084 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3085 strcpy(files[nfiles].name, LNG(PS2Net));
3086 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3087 strcpy(files[nfiles].name, LNG(PS2PowerOff));
3088 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3089 strcpy(files[nfiles].name, LNG(HddManager));
3090 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3091 strcpy(files[nfiles].name, LNG(TextEditor));
3092 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3093 strcpy(files[nfiles].name, LNG(JpgViewer));
3094 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3095 strcpy(files[nfiles].name, LNG(Configure));
3096 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3097 strcpy(files[nfiles].name, LNG(Load_CNFprev));
3098 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3099 strcpy(files[nfiles].name, LNG(Load_CNFnext));
3100 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3101 strcpy(files[nfiles].name, LNG(Set_CNF_Path));
3102 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3103 strcpy(files[nfiles].name, LNG(Load_CNF));
3104 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3105//Next 2 lines add an optional font test routine
3106 strcpy(files[nfiles].name, LNG(ShowFont));
3107 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3108 strcpy(files[nfiles].name, LNG(Debug_Info));
3109 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3110 strcpy(files[nfiles].name, LNG(About_uLE));
3111 files[nfiles++].stats.attrFile = MC_ATTR_FILE;
3112 for(i=0; i<nfiles; i++)
3113 files[i].title[0]=0;
3114 //-- End case for MISC command pseudo folder with function links --
3115 }else{
3116 //-- Start case for normal folder with file/folder links --
3117 strcpy(files[0].name, "..");
3118 files[0].stats.attrFile = MC_ATTR_SUBDIR;
3119 nfiles = getDir(path, &files[1]) + 1;
3120 if(strcmp(ext,"*")){
3121 for(i=j=1; i<nfiles; i++){
3122 if(files[i].stats.attrFile & MC_ATTR_SUBDIR)
3123 files[j++] = files[i];
3124 else{
3125 p = strrchr(files[i].name, '.');
3126 if(p!=NULL && !stricmp(ext,p+1))
3127 files[j++] = files[i];
3128 }
3129 }
3130 nfiles = j;
3131 }
3132 if((file_show==2)||(file_sort==2)){
3133 for(i=1; i<nfiles; i++){
3134 ret = getGameTitle(path, &files[i], files[i].title);
3135 if(ret<0) files[i].title[0]=0;
3136 }
3137 }
3138 if(!strcmp(path, "hdd0:/"))
3139 vfreeSpace=FALSE;
3140 else if(nfiles>1)
3141 sort(&files[1], 0, nfiles-2);
3142 //-- End case for normal folder with file/folder links --
3143 }
3144 return nfiles;
3145}
3146//------------------------------
3147//endfunc setFileList
3148//--------------------------------------------------------------
3149int BrowserModePopup(void)
3150{
3151 char tmp[80];
3152 int x, y, i, test;
3153 int event, post_event=0;
3154
3155 int entry_file_show = file_show;
3156 int entry_file_sort = file_sort;
3157
3158 int Show_len = strlen(LNG(Show_Content_as))+1;
3159 int Sort_len = strlen(LNG(Sort_Content_by))+1;
3160
3161 int menu_len = Show_len;
3162 if(menu_len < (i = Sort_len)) menu_len = i;
3163 if(menu_len < (i = strlen(LNG(Filename))+strlen(LNG(_plus_Details)))) menu_len = i;
3164 if(menu_len < (i = strlen(LNG(Game_Title))+strlen(LNG(_plus_Details)))) menu_len = i;
3165 if(menu_len < (i = strlen(LNG(No_Sort)))) menu_len = i;
3166 if(menu_len < (i = strlen(LNG(Timestamp)))) menu_len = i;
3167 if(menu_len < (i = strlen(LNG(Back_to_Browser)))) menu_len = i;
3168 menu_len += 3; //All of the above strings are indented 3 spaces, for tooltips
3169
3170 int menu_ch_w = menu_len+1; //Total characters in longest menu string
3171 int menu_ch_h = 14; //Total number of menu lines
3172 int mSprite_w = (menu_ch_w + 3) * FONT_WIDTH;
3173 int mSprite_h = (menu_ch_h +1) * FONT_HEIGHT;
3174 int mSprite_X1 = SCREEN_WIDTH/2 - mSprite_w/2;
3175 int mSprite_Y1 = SCREEN_HEIGHT/2 - mSprite_h/2;
3176 int mSprite_X2 = mSprite_X1+mSprite_w;
3177 int mSprite_Y2 = mSprite_Y1+mSprite_h;
3178
3179 char minuses_s[81];
3180
3181 for(i=0; i<80; i++)
3182 minuses_s[i] = '-';
3183 minuses_s[80] = '\0';
3184
3185 event = 1; //event = initial entry
3186 while(1){
3187 //Pad response section
3188 waitPadReady(0, 0);
3189 if(readpad()){
3190 switch(new_pad){
3191 case PAD_RIGHT:
3192 file_sort = 0;
3193 event |= 2; //event |= valid pad command
3194 break;
3195 case PAD_DOWN:
3196 file_sort = 1;
3197 event |= 2; //event |= valid pad command
3198 break;
3199 case PAD_LEFT:
3200 file_sort = 2;
3201 event |= 2; //event |= valid pad command
3202 break;
3203 case PAD_UP:
3204 file_sort = 3;
3205 event |= 2; //event |= valid pad command
3206 break;
3207 case PAD_CIRCLE:
3208 file_show = 0;
3209 event |= 2; //event |= valid pad command
3210 break;
3211 case PAD_CROSS:
3212 file_show = 1;
3213 event |= 2; //event |= valid pad command
3214 break;
3215 case PAD_SQUARE:
3216 file_show = 2;
3217 event |= 2; //event |= valid pad command
3218 if((file_show==2) && (elisaFnt==NULL) && (elisa_failed==FALSE)){
3219 int fd;
3220
3221 fd = uLE_related(tmp, "uLE:/ELISA100.FNT");
3222 if(!strncmp(tmp, "cdrom", 5)) strcat(tmp, ";1");
3223 if(fd==1)
3224 fd = genOpen(tmp, O_RDONLY);
3225 else
3226 fd = -1;
3227 if(fd>=0){
3228 test = genLseek(fd,0,SEEK_END);
3229 if(test==55016){
3230 elisaFnt = (char*)malloc(test);
3231 genLseek(fd,0,SEEK_SET);
3232 genRead(fd, elisaFnt, test);
3233 }
3234 genClose(fd);
3235 }else
3236 elisa_failed = TRUE;
3237 }
3238 break;
3239 case PAD_TRIANGLE:
3240 return (file_show!=entry_file_show)||(file_sort!=entry_file_sort);
3241 } //ends switch(new_pad)
3242 } //ends if(readpad())
3243
3244 if(event||post_event){ //NB: We need to update two frame buffers per event
3245
3246 //Display section
3247 drawPopSprite(setting->color[0],
3248 mSprite_X1, mSprite_Y1,
3249 mSprite_X2, mSprite_Y2);
3250 drawFrame(mSprite_X1, mSprite_Y1, mSprite_X2, mSprite_Y2, setting->color[1]);
3251
3252 for(i=0, y=mSprite_Y1+FONT_HEIGHT/2; i<menu_ch_h; i++){
3253 if(i==0) sprintf(tmp, " %s:", LNG(Show_Content_as));
3254 else if(i==1) sprintf(tmp, " %s", &minuses_s[80-Show_len]);
3255 else if(i==2) sprintf(tmp, "ÿ0 %s", LNG(Filename));
3256 else if(i==3) sprintf(tmp, "ÿ1 %s%s", LNG(Filename), LNG(_plus_Details));
3257 else if(i==4) sprintf(tmp, "ÿ2 %s%s", LNG(Game_Title), LNG(_plus_Details));
3258 else if(i==6) sprintf(tmp, " %s:", LNG(Sort_Content_by));
3259 else if(i==7) sprintf(tmp, " %s", &minuses_s[80-Sort_len]);
3260 else if(i==8) sprintf(tmp, "ÿ: %s", LNG(No_Sort));
3261 else if(i==9) sprintf(tmp, "ÿ; %s", LNG(Filename));
3262 else if(i==10) sprintf(tmp, "ÿ< %s", LNG(Game_Title));
3263 else if(i==11) sprintf(tmp, "ÿ= %s", LNG(Timestamp));
3264 else if(i==13) sprintf(tmp, "ÿ3 %s", LNG(Back_to_Browser));
3265 else tmp[0] = 0;
3266
3267 printXY(tmp, mSprite_X1+2*FONT_WIDTH, y, setting->color[3], TRUE,0);
3268 //Display marker for current modes
3269 if((file_show == i-2) || (file_sort == i-8))
3270 drawChar(LEFT_CUR, mSprite_X1+FONT_WIDTH/2, y, setting->color[2]);
3271 y+=FONT_HEIGHT;
3272
3273 } //ends for loop handling one text row per loop
3274
3275 //Tooltip section
3276 x = SCREEN_MARGIN;
3277 y = Menu_tooltip_y;
3278 drawSprite(setting->color[0],
3279 0, y-1,
3280 SCREEN_WIDTH, y+FONT_HEIGHT);
3281 }//ends if(event||post_event)
3282 drawScr();
3283 post_event = event;
3284 event = 0;
3285 }//ends while
3286}
3287//------------------------------
3288//endfunc BrowserModePopup
3289//--------------------------------------------------------------
3290// get_FilePath is the main browser function.
3291// It also contains the menu handler for the R1 submenu
3292// The static variables declared here are only for the use of
3293// this function and the submenu functions that it calls
3294//--------------------------------------------------------------
3295// sincro: ADD USBD_IRX_CNF mode for found IRX file for USBD.IRX
3296// example: getFilePath(setting->usbd_file, USBD_IRX_CNF);
3297// polo: ADD SKIN_CNF mode for found jpg file for SKIN
3298// example: getFilePath(setting->skin, SKIN_CNF);
3299// suloku: ADD GUI_SKIN_CNF mode for found jpg file for MAIN_SKIN
3300// example: getFilePath(setting->GUI_skin, GUI_SKIN_CNF);
3301// dlanor: ADD USBKBD_IRX_CNF mode for found IRX file for USBKBD.IRX
3302// example: getFilePath(setting->usbkbd_file, USBKBD_IRX_CNF);
3303// dlanor: ADD USBMASS_IRX_CNF mode for found IRX file for usb_mass
3304// example: getFilePath(setting->usbmass_file, USBMASS_IRX_CNF);
3305// dlanor: ADD SAVE_CNF mode returning either pure path or pathname
3306// dlanor: ADD return value 0=pure path, 1=pathname, negative=error/no_selection
3307static int browser_cd, browser_up, browser_repos, browser_pushed;
3308static int browser_sel, browser_nfiles;
3309static void submenu_func_GetSize(char *mess, char *path, FILEINFO *files);
3310static void submenu_func_Paste(char *mess, char *path);
3311static void submenu_func_mcPaste(char *mess, char *path);
3312static void submenu_func_psuPaste(char *mess, char *path);
3313int getFilePath(char *out, int cnfmode)
3314{
3315 char path[MAX_PATH], cursorEntry[MAX_PATH],
3316 msg0[MAX_PATH], msg1[MAX_PATH],
3317 tmp[MAX_PATH], tmp1[MAX_PATH], tmp2[MAX_PATH], ext[8], *p;
3318 u64 color;
3319 FILEINFO files[MAX_ENTRY];
3320 int top=0, rows;
3321 int x, y, y0, y1;
3322 int i, j, ret, rv=-1; //NB: rv is for return value of this function
3323 int event, post_event=0;
3324 int font_height;
3325 int iconbase, iconcolr;
3326
3327 elisa_failed = FALSE; //set at failure to load font, cleared at each browser entry
3328
3329 browser_cd=TRUE;
3330 browser_up=FALSE;
3331 browser_repos=FALSE;
3332 browser_pushed=TRUE;
3333 browser_sel=0;
3334 browser_nfiles=0;
3335
3336 strcpy(ext, cnfmode_extL[cnfmode]);
3337
3338 if( (cnfmode==USBD_IRX_CNF)
3339 ||(cnfmode==USBKBD_IRX_CNF)
3340 ||(cnfmode==USBMASS_IRX_CNF)
3341 ||( (!strncmp(LastDir,setting->Misc,strlen(setting->Misc))) && (cnfmode>LK_ELF_CNF)))
3342 path[0] = '\0'; //start in main root if recent folder unreasonable
3343 else
3344 strcpy(path, LastDir); //If reasonable, start in recent folder
3345
3346 unmountAll(); //unmount all uLE-used mountpoints
3347
3348 clipPath[0] = 0;
3349 nclipFiles = 0;
3350 browser_cut = 0;
3351
3352 file_show = 1;
3353 file_sort = 1;
3354
3355 font_height = FONT_HEIGHT;
3356 if((file_show==2) && (elisaFnt!=NULL))
3357 font_height = FONT_HEIGHT+2;
3358 rows = (Menu_end_y-Menu_start_y)/font_height;
3359
3360 event = 1; //event = initial entry
3361 while(1){
3362
3363 //Pad response section
3364 waitPadReady(0, 0);
3365 if(readpad()){
3366 if(new_pad){
3367 browser_pushed=TRUE;
3368 event |= 2; //event |= pad command
3369 }
3370 if(new_pad & PAD_UP)
3371 browser_sel--;
3372 else if(new_pad & PAD_DOWN)
3373 browser_sel++;
3374 else if(new_pad & PAD_LEFT)
3375 browser_sel-=rows/2;
3376 else if(new_pad & PAD_RIGHT)
3377 browser_sel+=rows/2;
3378 else if(new_pad & PAD_TRIANGLE)
3379 browser_up=TRUE;
3380 else if((swapKeys && (new_pad & PAD_CROSS))
3381 || (!swapKeys && (new_pad & PAD_CIRCLE)) ){ //Pushed OK
3382 if(files[browser_sel].stats.attrFile & MC_ATTR_SUBDIR){
3383 //pushed OK for a folder
3384 if(!strcmp(files[browser_sel].name,".."))
3385 browser_up=TRUE;
3386 else {
3387 strcat(path, files[browser_sel].name);
3388 strcat(path, "/");
3389 browser_cd=TRUE;
3390 }
3391 }else{
3392 //pushed OK for a file
3393 sprintf(out, "%s%s", path, files[browser_sel].name);
3394 // Must to include a function for check IRX Header
3395 if( ((cnfmode==LK_ELF_CNF) || (cnfmode==NON_CNF))
3396 &&(checkELFheader(out)<0)){
3397 browser_pushed=FALSE;
3398 sprintf(msg0, "%s.", LNG(This_file_isnt_an_ELF));
3399 out[0] = 0;
3400 }else{
3401 strcpy(LastDir, path);
3402 rv = 1; //flag pathname selected
3403 break;
3404 }
3405 }
3406 }else if(new_pad & PAD_R3){ //New clause for uLE-relative paths
3407 if(files[browser_sel].stats.attrFile & MC_ATTR_SUBDIR){
3408 //pushed R3 for a folder (navigate to uLE CNF folder)
3409 strcpy(path, LaunchElfDir);
3410 if( (p = strchr(path, ':')) ){ //device separator ?
3411 if( p[1] != '/' ){ //missing path separator ? (mass: & host:)
3412 p[1] = '/'; //insert path separator
3413 strcpy(p+2, LaunchElfDir+(p-path)+1); //append rest of pathname
3414 }
3415 }
3416 browser_cd=TRUE;
3417 }else{
3418 //pushed R3 for a file (treat as uLE-related)
3419 sprintf(out, "%s%s", path, files[browser_sel].name);
3420 // Must to include a function for check IRX Header
3421 if( ((cnfmode==LK_ELF_CNF) || (cnfmode==NON_CNF))
3422 &&(checkELFheader(out)<0)){
3423 browser_pushed=FALSE;
3424 sprintf(msg0, "%s.", LNG(This_file_isnt_an_ELF));
3425 out[0] = 0;
3426 }else{
3427 strcpy(LastDir, path);
3428 sprintf(out, "%s%s", "uLE:/", files[browser_sel].name);
3429 rv = 1; //flag pathname selected
3430 break;
3431 }
3432 }
3433 }else if(new_pad & PAD_R2){
3434 char *temp = PathPad_menu(path);
3435
3436 if(temp != NULL){
3437 strcpy(path, temp);
3438 browser_cd=TRUE;
3439 vfreeSpace=FALSE;
3440 }
3441 } else if(new_pad & PAD_L1) {
3442 browser_cd = BrowserModePopup();
3443 }
3444 //pad checks above are for commands common to all browser modes
3445 //pad checks below are for commands that differ depending on cnfmode
3446 if(cnfmode==DIR_CNF){
3447 if(new_pad & PAD_START) {
3448 strcpy(out, path);
3449 strcpy(LastDir, path);
3450 rv = 0; //flag pathname selected
3451 break;
3452 }
3453 }else if(cnfmode==SAVE_CNF){ //Generic Save commands
3454 if(new_pad & PAD_START) {
3455 if(files[browser_sel].stats.attrFile & MC_ATTR_SUBDIR){
3456 //no file was highlighted, so prep to save with empty filename
3457 strcpy(out, path);
3458 rv = 0; //flag pure path selected
3459 }else{
3460 //a file was highlighted, so prep to save with that filename
3461 sprintf(out, "%s%s", path, files[browser_sel].name);
3462 rv = 1; //flag pathname selected
3463 }
3464 strcpy(LastDir, path);
3465 break;
3466 }
3467 }
3468 if(cnfmode){ //A file is to be selected, not in normal browser mode
3469 if(new_pad & PAD_SQUARE) {
3470 if(!strcmp(ext,"*")) strcpy(ext, cnfmode_extL[cnfmode]);
3471 else strcpy(ext, "*");
3472 browser_cd=TRUE;
3473 }else if((!swapKeys && (new_pad & PAD_CROSS))
3474 || (swapKeys && (new_pad & PAD_CIRCLE)) ){ //Cancel command ?
3475 unmountAll();
3476 return rv;
3477 }
3478 }else{ //cnfmode == FALSE
3479 if(new_pad & PAD_R1) {
3480 ret = menu(path, &files[browser_sel]);
3481 if(ret==COPY || ret==CUT){
3482 strcpy(clipPath, path);
3483 if(nmarks>0){
3484 for(i=nclipFiles=0; i<browser_nfiles; i++)
3485 if(marks[i])
3486 clipFiles[nclipFiles++]=files[i];
3487 }else{
3488 clipFiles[0]=files[browser_sel];
3489 nclipFiles = 1;
3490 }
3491 sprintf(msg0, "%s", LNG(Copied_to_the_Clipboard));
3492 browser_pushed=FALSE;
3493 if(ret==CUT) browser_cut=TRUE;
3494 else browser_cut=FALSE;
3495 } //ends COPY and CUT
3496 else if(ret==DELETE){
3497 if(nmarks==0){ //dlanor: using title was inappropriate here (filesystem op)
3498 sprintf(tmp,"%s",files[browser_sel].name);
3499 if(files[browser_sel].stats.attrFile & MC_ATTR_SUBDIR)
3500 strcat(tmp,"/");
3501 sprintf(tmp1, "\n%s ?", LNG(Delete));
3502 strcat(tmp, tmp1);
3503 ret = ynDialog(tmp);
3504 }else
3505 ret = ynDialog(LNG(Mark_Files_Delete));
3506
3507 if(ret>0){
3508 int first_deleted = 0;
3509 if(nmarks==0){
3510 strcpy(tmp, files[browser_sel].name);
3511 if(files[browser_sel].stats.attrFile & MC_ATTR_SUBDIR) strcat(tmp,"/");
3512 sprintf(tmp1, " %s", LNG(deleting));
3513 strcat(tmp, tmp1);
3514 drawMsg(tmp);
3515 ret=delete(path, &files[browser_sel]);
3516 }else{
3517 for(i=0; i<browser_nfiles; i++){
3518 if(marks[i]){
3519 if(!first_deleted) //if this is the first mark
3520 first_deleted = i; //then memorize it for cursor positioning
3521 strcpy(tmp, files[i].name);
3522 if(files[i].stats.attrFile & MC_ATTR_SUBDIR) strcat(tmp,"/");
3523 sprintf(tmp1, " %s", LNG(deleting));
3524 strcat(tmp, tmp1);
3525 drawMsg(tmp);
3526 ret=delete(path, &files[i]);
3527 if(ret<0) break;
3528 }
3529 }
3530 }
3531 if(ret>=0) {
3532 if(nmarks==0)
3533 strcpy(cursorEntry, files[browser_sel-1].name);
3534 else
3535 strcpy(cursorEntry, files[first_deleted-1].name);
3536 } else {
3537 strcpy(cursorEntry, files[browser_sel].name);
3538 sprintf(msg0, "%s Err=%d", LNG(Delete_Failed), ret);
3539 browser_pushed = FALSE;
3540 }
3541 browser_cd=TRUE;
3542 browser_repos=TRUE;
3543 }
3544 } //ends DELETE
3545 else if(ret==RENAME){
3546 strcpy(tmp, files[browser_sel].name);
3547 if(keyboard(tmp, 36)>0){
3548 if(Rename(path, &files[browser_sel], tmp)<0){
3549 browser_pushed=FALSE;
3550 strcpy(msg0, LNG(Rename_Failed));
3551 }else
3552 browser_cd=TRUE;
3553 }
3554 } //ends RENAME
3555 else if(ret==PASTE) submenu_func_Paste(msg0, path);
3556 else if(ret==MCPASTE) submenu_func_mcPaste(msg0, path);
3557 else if(ret==PSUPASTE) submenu_func_psuPaste(msg0, path);
3558 else if(ret==NEWDIR){
3559 tmp[0]=0;
3560 if(keyboard(tmp, 36)>0){
3561 ret = newdir(path, tmp);
3562 if(ret == -17){
3563 strcpy(msg0, LNG(directory_already_exists));
3564 browser_pushed=FALSE;
3565 }else if(ret < 0){
3566 strcpy(msg0, LNG(NewDir_Failed));
3567 browser_pushed=FALSE;
3568 }else{ //dlanor: modified for similarity to PC browsers
3569 sprintf(msg0, "%s: ", LNG(Created_folder));
3570 strcat(msg0, tmp);
3571 browser_pushed=FALSE;
3572 strcpy(cursorEntry, tmp);
3573 browser_repos=TRUE;
3574 browser_cd=TRUE;
3575 }
3576 }
3577 } //ends NEWDIR
3578 else if(ret==NEWICON){
3579 strcpy(tmp, LNG(Icon_Title));
3580 if(keyboard(tmp, 36) <= 0)
3581 goto DoneIcon;
3582 genFixPath(path, tmp1);
3583 strcat(tmp1, "icon.sys");
3584 if((ret = genOpen(tmp1, O_RDONLY))>=0){ //if old "icon.sys" file exists
3585 genClose(ret);
3586 sprintf(msg1,
3587 "\n\"icon.sys\" %s.\n\n%s ?", LNG(file_alredy_exists),
3588 LNG(Do_you_wish_to_overwrite_it));
3589 if(ynDialog(msg1) < 0)
3590 goto DoneIcon;
3591 genRemove(tmp1);
3592 }
3593 make_iconsys(tmp, "icon.icn", tmp1);
3594 browser_cd=TRUE;
3595 strcpy(tmp, LNG(IconText));
3596 keyboard(tmp, 36);
3597 genFixPath(path, tmp1);
3598 strcat(tmp1, "icon.icn");
3599 if((ret = genOpen(tmp1, O_RDONLY))>=0){ //if old "icon.icn" file exists
3600 genClose(ret);
3601 sprintf(msg1,
3602 "\n\"icon.icn\" %s.\n\n%s ?", LNG(file_alredy_exists),
3603 LNG(Do_you_wish_to_overwrite_it));
3604 if(ynDialog(msg1) < 0)
3605 goto DoneIcon;
3606 genRemove(tmp1);
3607 }
3608 make_icon(tmp, tmp1);
3609 DoneIcon:
3610 strcpy(tmp, tmp1); //Dummy code to make 'goto DoneIcon' legal for gcc
3611 } //ends NEWICON
3612 else if((ret==MOUNTVMC0) || (ret==MOUNTVMC1)){
3613 i = ret-MOUNTVMC0;
3614 load_vmcfs();
3615 sprintf(tmp, "vmc%d:", i);
3616 if(vmcMounted[i]){
3617 if((j=vmc_PartyIndex[i]) >= 0){
3618 vmc_PartyIndex[i] = -1;
3619 if(j != vmc_PartyIndex[1^i])
3620 Party_vmcIndex[j] = -1;
3621 }
3622 fileXioUmount(tmp);
3623 vmcMounted[i] = 0;
3624 }
3625 j = genFixPath(path, tmp1);
3626 strcpy(tmp2, tmp1);
3627 if (!strncmp(path, "host:", 5)){
3628 makeHostPath(tmp2, tmp1);
3629 }
3630 strcat(tmp2, files[browser_sel].name);
3631 if( (x = fileXioMount(tmp, tmp2, FIO_MT_RDWR)) >= 0){
3632 if((j>=0) && (j<MOUNT_LIMIT)){
3633 vmc_PartyIndex[i] = j;
3634 Party_vmcIndex[j] = i;
3635 }
3636 vmcMounted[i] = 1;
3637 sprintf(path, "%s/", tmp);
3638 browser_cd = TRUE;
3639 cnfmode = NON_CNF;
3640 strcpy(ext, cnfmode_extL[cnfmode]);
3641 }
3642 else{
3643 sprintf(msg1, "\n'%s vmc%d:' for \"%s\"\nResult=%d",
3644 LNG(Mount), i, tmp2, x);
3645 (void) ynDialog(msg1);
3646 }
3647 } //ends MOUNTVMCx
3648 else if(ret==GETSIZE){
3649 submenu_func_GetSize(msg0, path, files);
3650 } //ends GETSIZE
3651 //R1 menu handling is completed above
3652 }else if((!swapKeys && new_pad & PAD_CROSS)
3653 || (swapKeys && new_pad & PAD_CIRCLE) ){
3654 if(browser_sel!=0 && path[0]!=0 && strcmp(path,"hdd0:/")){
3655 if(marks[browser_sel]){
3656 marks[browser_sel]=FALSE;
3657 nmarks--;
3658 }else{
3659 marks[browser_sel]=TRUE;
3660 nmarks++;
3661 }
3662 }
3663 browser_sel++;
3664 } else if(new_pad & PAD_SQUARE) {
3665 if(path[0]!=0 && strcmp(path,"hdd0:/")){
3666 for(i=1; i<browser_nfiles; i++){
3667 if(marks[i]){
3668 marks[i]=FALSE;
3669 nmarks--;
3670 }else{
3671 marks[i]=TRUE;
3672 nmarks++;
3673 }
3674 }
3675 }
3676 } else if(new_pad & PAD_SELECT){ //Leaving the browser ?
3677 unmountAll();
3678 return rv;
3679 }
3680 }
3681 }//ends pad response section
3682
3683 //browser path adjustment section
3684 if(browser_up){
3685 if((p=strrchr(path, '/'))!=NULL)
3686 *p = 0;
3687 if((p=strrchr(path, '/'))!=NULL){
3688 p++;
3689 strcpy(cursorEntry, p);
3690 *p = 0;
3691 }else{
3692 strcpy(cursorEntry, path);
3693 path[0] = 0;
3694 }
3695 browser_cd=TRUE;
3696 browser_repos=TRUE;
3697 }//ends 'if(browser_up)'
3698 //----- Process newly entered directory here (incl initial entry)
3699 if(browser_cd){
3700 browser_nfiles = setFileList(path, ext, files, cnfmode);
3701 if(!cnfmode){ //Calculate free space (unless configuring)
3702 if(!strncmp(path, "mc", 2)){
3703 mcGetInfo(path[2]-'0', 0, &mctype_PSx, &mcfreeSpace, NULL);
3704 mcSync(0, NULL, &ret);
3705 freeSpace = mcfreeSpace*((mctype_PSx==1) ? 8192 : 1024);
3706 vfreeSpace=TRUE;
3707 }else if(!strncmp(path,"vmc",3)){
3708 strncpy(tmp, path, 5);
3709 tmp[5]='\0';
3710 freeSpace = fileXioDevctl(tmp, DEVCTL_VMCFS_CKFREE, NULL, 0, NULL, 0);
3711 vfreeSpace=TRUE;
3712 }else if(!strncmp(path,"hdd",3)&&strcmp(path,"hdd0:/")){
3713 s64 ZoneFree, ZoneSize;
3714 char pfs_str[6];
3715
3716 strcpy(pfs_str, "pfs0:");
3717 pfs_str[3] += latestMount;
3718 ZoneFree = fileXioDevctl(pfs_str, PFSCTL_GET_ZONE_FREE, NULL, 0, NULL, 0);
3719 ZoneSize = fileXioDevctl(pfs_str, PFSCTL_GET_ZONE_SIZE, NULL, 0, NULL, 0);
3720 //printf("ZoneFree==%d ZoneSize==%d\r\n", ZoneFree, ZoneSize);
3721 freeSpace = ZoneFree*ZoneSize;
3722 vfreeSpace=TRUE;
3723 }
3724 }
3725 browser_sel=0;
3726 top=0;
3727 if(browser_repos){
3728 browser_repos = FALSE;
3729 for(i=0; i<browser_nfiles; i++) {
3730 if(!strcmp(cursorEntry, files[i].name)) {
3731 browser_sel=i;
3732 top=browser_sel-3;
3733 break;
3734 }
3735 }
3736 } //ends if(browser_repos)
3737 nmarks = 0;
3738 memset(marks, 0, MAX_ENTRY);
3739 browser_cd=FALSE;
3740 browser_up=FALSE;
3741 } //ends if(browser_cd)
3742 if(setting->discControl && !strncmp(path,"cdfs",4))
3743 uLE_cdStop();
3744 if(top > browser_nfiles-rows) top=browser_nfiles-rows;
3745 if(top < 0) top=0;
3746 if(browser_sel >= browser_nfiles) browser_sel=browser_nfiles-1;
3747 if(browser_sel < 0) browser_sel=0;
3748 if(browser_sel >= top+rows) top=browser_sel-rows+1;
3749 if(browser_sel < top) top=browser_sel;
3750
3751 if(event||post_event){ //NB: We need to update two frame buffers per event
3752
3753 //Display section
3754 clrScr(setting->color[0]);
3755
3756 x = Menu_start_x;
3757 y = Menu_start_y;
3758 font_height = FONT_HEIGHT;
3759 if((file_show==2) && (elisaFnt!=NULL)){
3760 y-=2;
3761 font_height = FONT_HEIGHT+2;
3762 }
3763 rows = (Menu_end_y-Menu_start_y)/font_height;
3764
3765 for(i=0; i<rows; i++) //Repeat loop for each browser text row
3766 {
3767 int title_flag = 0; //Assume that normal file/folder names are wanted
3768 int name_limit = 0; //Assume that no name length problems exist
3769
3770 if(top+i >= browser_nfiles) break;
3771 if(top+i == browser_sel) color = setting->color[2]; //Highlight cursor line
3772 else color = setting->color[3];
3773
3774 if(!strcmp(files[top+i].name,".."))
3775 strcpy(tmp,"..");
3776 else if((file_show==2) && files[top+i].title[0]!=0) {
3777 strcpy(tmp,files[top+i].title);
3778 title_flag = 1;
3779 }else{ //Show normal file/folder names
3780 strcpy(tmp,files[top+i].name);
3781 if(file_show > 0){ //Does display mode include file details ?
3782 name_limit = 43*8;
3783 } else { //Filenames are shown without file details
3784 name_limit = 71*8;
3785 }
3786 }
3787 if(name_limit){ //Do we need to check name length ?
3788 int name_end = name_limit/7; //Max string length for acceptable spacing
3789
3790 if(files[top+i].stats.attrFile & MC_ATTR_SUBDIR)
3791 name_end -= 1; //For folders, reserve one character for final '/'
3792 if(strlen(tmp) > name_end){ //Is name too long for clean display ?
3793 tmp[name_end-1] = '~'; //indicate filename abbreviation
3794 tmp[name_end] = 0; //abbreviate name length to make room for details
3795 }
3796 }
3797
3798 if(files[top+i].stats.attrFile & MC_ATTR_SUBDIR)
3799 strcat(tmp, "/");
3800 if(title_flag)
3801 printXY_sjis(tmp, x+4, y, color, TRUE);
3802 else
3803 printXY(tmp, x+4, y, color, TRUE, name_limit);
3804 if(file_show > 0){
3805 unsigned int size = files[top+i].stats.fileSizeByte;
3806 int scale = 0; //0==Bytes, 1==KBytes, 2==MBytes, 3==GB
3807 char scale_s[5] = " KMGT";
3808 PS2TIME timestamp = *(PS2TIME *) &files[top+i].stats._modify;
3809
3810 if(!size_valid) size = 0;
3811 if(!time_valid) memset((void *) &timestamp, 0, sizeof(timestamp));
3812
3813 if(!size_valid || !(top+i))
3814 strcpy(tmp, "----- B");
3815 else {
3816 while(size > 99999){
3817 scale++;
3818 size /= 1024;
3819 }
3820 sprintf(tmp, "%5u%cB", size, scale_s[scale]);
3821 }
3822
3823 if(!time_valid || !(top+i))
3824 strcat(tmp, " ----.--.-- --:--:--");
3825 else {
3826 sprintf(tmp+strlen(tmp), " %04d.%02d.%02d %02d:%02d:%02d",
3827 ((timestamp.year < 2256) ?timestamp.year :(timestamp.year-256)),
3828 timestamp.month,
3829 timestamp.day,
3830 timestamp.hour,
3831 timestamp.min,
3832 timestamp.sec
3833 );
3834 }
3835
3836 printXY(tmp, x+4+44*FONT_WIDTH, y, color, TRUE, 0);
3837 }
3838 if(setting->FB_NoIcons){ //if FileBrowser should not use icons
3839 if(marks[top+i])
3840 drawChar('*', x-6, y, setting->color[3]);
3841 } else { //if Icons must be used in front of file/folder names
3842 if(files[top+i].stats.attrFile & MC_ATTR_SUBDIR){
3843 iconbase = ICON_FOLDER;
3844 iconcolr = 4;
3845 } else {
3846 iconbase = ICON_FILE;
3847 p = strrchr(files[top+i].name, '.');
3848 if(p!=NULL && !stricmp(p+1, "ELF"))
3849 iconcolr = 5;
3850 else
3851 iconcolr = 6;
3852 }
3853 if(marks[top+i])
3854 iconbase += 2;
3855 drawChar(iconbase, x-3-FONT_WIDTH, y, setting->color[iconcolr]);
3856 drawChar(iconbase+1, x-3, y, setting->color[iconcolr]);
3857 }
3858 y += font_height;
3859 } //ends for, so all browser rows were fixed above
3860 if(browser_nfiles > rows) { //if more files than available rows, use scrollbar
3861 drawFrame(SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*8, Frame_start_y,
3862 SCREEN_WIDTH-SCREEN_MARGIN, Frame_end_y, setting->color[1]);
3863 y0=(Menu_end_y-Menu_start_y+8) * ((double)top/browser_nfiles);
3864 y1=(Menu_end_y-Menu_start_y+8) * ((double)(top+rows)/browser_nfiles);
3865 drawOpSprite(setting->color[1],
3866 SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*6, (y0+Menu_start_y-4),
3867 SCREEN_WIDTH-SCREEN_MARGIN-LINE_THICKNESS*2, (y1+Menu_start_y-4));
3868 } //ends clause for scrollbar
3869 if(nclipFiles) { //if Something in clipboard, emulate LED indicator
3870 u64 LED_colour, RIM_colour = GS_SETREG_RGBA(0,0,0,0);
3871 int RIM_w=4, LED_w=6, indicator_w = LED_w+2*RIM_w;
3872 int x2 = SCREEN_WIDTH-SCREEN_MARGIN-2, x1 = x2-indicator_w;
3873 int y1 = Frame_start_y+2, y2 = y1+indicator_w;
3874
3875 if(browser_cut) LED_colour = GS_SETREG_RGBA(0xC0,0,0,0); //Red LED == CUT
3876 else LED_colour = GS_SETREG_RGBA(0,0xC0,0,0); //Green LED == COPY
3877 drawOpSprite(RIM_colour, x1, y1, x2, y2);
3878 drawOpSprite(LED_colour, x1+RIM_w, y1+RIM_w, x2-RIM_w, y2-RIM_w);
3879 } //ends clause for clipboard indicator
3880 if(browser_pushed)
3881 sprintf(msg0, "%s: %s", LNG(Path), path);
3882
3883 //Tooltip section
3884 if(cnfmode) {//cnfmode indicates configurable file selection
3885 if (swapKeys)
3886 sprintf(msg1, "ÿ1:%s ÿ0:%s ÿ3:%s ÿ2:", LNG(OK), LNG(Cancel), LNG(Up));
3887 else
3888 sprintf(msg1, "ÿ0:%s ÿ1:%s ÿ3:%s ÿ2:", LNG(OK), LNG(Cancel), LNG(Up));
3889 if(ext[0] == '*')
3890 strcat(msg1, "*->");
3891 strcat(msg1, cnfmode_extU[cnfmode]);
3892 if(ext[0] != '*')
3893 strcat(msg1, "->*");
3894 sprintf(tmp, " R2:%s", LNG(PathPad));
3895 strcat(msg1, tmp);
3896 if((cnfmode==DIR_CNF)||(cnfmode==SAVE_CNF)) { //modes using Start
3897 sprintf(tmp, " Start:%s", LNG(Choose));
3898 strcat(msg1, tmp);
3899 }
3900 }else{ // cnfmode == FALSE
3901 if (swapKeys)
3902 sprintf(msg1, "ÿ1:%s ÿ3:%s ÿ0:%s ÿ2:%s L1:%s R1:%s R2:%s Sel:%s",
3903 LNG(OK), LNG(Up), LNG(Mark), LNG(RevMark),
3904 LNG(Mode), LNG(Menu), LNG(PathPad), LNG(Exit));
3905 else
3906 sprintf(msg1, "ÿ0:%s ÿ3:%s ÿ1:%s ÿ2:%s L1:%s R1:%s R2:%s Sel:%s",
3907 LNG(OK), LNG(Up), LNG(Mark), LNG(RevMark),
3908 LNG(Mode), LNG(Menu), LNG(PathPad), LNG(Exit));
3909 }
3910 setScrTmp(msg0, msg1);
3911 if(vfreeSpace){
3912 if(freeSpace >= 1024*1024)
3913 sprintf(tmp, "[%.1fMB %s]", (double)freeSpace/1024/1024, LNG(free));
3914 else if(freeSpace >= 1024)
3915 sprintf(tmp, "[%.1fKB %s]", (double)freeSpace/1024, LNG(free));
3916 else
3917 sprintf(tmp, "[%dB %s]", (int) freeSpace, LNG(free));
3918 ret=strlen(tmp);
3919 drawSprite(setting->color[0],
3920 SCREEN_WIDTH-SCREEN_MARGIN-(ret+1)*FONT_WIDTH, (Menu_message_y-1),
3921 SCREEN_WIDTH-SCREEN_MARGIN, (Menu_message_y+FONT_HEIGHT));
3922 printXY(tmp,
3923 SCREEN_WIDTH-SCREEN_MARGIN-ret*FONT_WIDTH,
3924 (Menu_message_y),
3925 setting->color[2], TRUE, 0);
3926 }
3927 }//ends if(event||post_event)
3928 drawScr();
3929 post_event = event;
3930 event = 0;
3931 }//ends while
3932
3933 //Leaving the browser
3934 unmountAll();
3935 return rv;
3936}
3937//------------------------------
3938//endfunc getFilePath
3939//--------------------------------------------------------------
3940void submenu_func_GetSize(char *mess, char *path, FILEINFO *files)
3941{
3942 s64 size;
3943 int ret, i, text_pos, text_inc, sel=-1;
3944 char filepath[MAX_PATH];
3945
3946/*
3947 int test;
3948 iox_stat_t stats;
3949 PS2TIME *time;
3950*/
3951
3952 drawMsg(LNG(Checking_Size));
3953 if(nmarks==0){
3954 size = getFileSize(path, &files[browser_sel]);
3955 sel = browser_sel; //for stat checking
3956 }else{
3957 for(i=size=0; i<browser_nfiles; i++){
3958 if(marks[i]){
3959 size += getFileSize(path, &files[i]);
3960 sel = i; //for stat checking
3961 }
3962 if(size<0) size=-1;
3963 }
3964 }
3965 printf("size result = %ld\r\n", size);
3966 if(size<0){
3967 strcpy(mess, LNG(Size_test_Failed));
3968 text_pos = strlen(mess);
3969 }else{
3970 text_pos = 0;
3971 if(size >= 1024*1024)
3972 sprintf(mess, "%s = %.1fMB%n", LNG(SIZE), (double)size/1024/1024, &text_inc);
3973 else if(size >= 1024)
3974 sprintf(mess, "%s = %.1fKB%n", LNG(SIZE), (double)size/1024, &text_inc);
3975 else
3976 sprintf(mess, "%s = %ldB%n", LNG(SIZE), size, &text_inc);
3977 text_pos += text_inc;
3978 }
3979
3980//----- Comment out this section to skip attributes entirely -----
3981 if((nmarks<2) && (sel>=0)){
3982 sprintf(filepath, "%s%s", path, files[sel].name);
3983//----- Start of section for debug display of attributes -----
3984/*
3985 printf("path =\"%s\"\r\n", path);
3986 printf("file =\"%s\"\r\n", files[sel].name);
3987 if (!strncmp(filepath, "host:/", 6))
3988 makeHostPath(filepath+5, filepath+6);
3989 if(!strncmp(filepath, "hdd", 3))
3990 test = fileXioGetStat(filepath, &stats);
3991 else
3992 test = fioGetstat(filepath, (fio_stat_t *) &stats);
3993 printf("test = %d\r\n", test);
3994 printf("mode = %08X\r\n", stats.mode);
3995 printf("attr = %08X\r\n", stats.attr);
3996 printf("size = %08X\r\n", stats.size);
3997 time = (PS2TIME *) stats.ctime;
3998 printf("ctime = %04d.%02d.%02d %02d:%02d:%02d.%02d\r\n",
3999 time->year,time->month,time->day,
4000 time->hour,time->min,time->sec,time->unknown);
4001 time = (PS2TIME *) stats.atime;
4002 printf("atime = %04d.%02d.%02d %02d:%02d:%02d.%02d\r\n",
4003 time->year,time->month,time->day,
4004 time->hour,time->min,time->sec,time->unknown);
4005 time = (PS2TIME *) stats.mtime;
4006 printf("mtime = %04d.%02d.%02d %02d:%02d:%02d.%02d\r\n",
4007 time->year,time->month,time->day,
4008 time->hour,time->min,time->sec,time->unknown);
4009*/
4010//----- End of section for debug display of attributes -----
4011 sprintf(mess+text_pos, " m=%04X %04d.%02d.%02d %02d:%02d:%02d%n",
4012 files[sel].stats.attrFile,
4013 files[sel].stats._modify.year,
4014 files[sel].stats._modify.month,
4015 files[sel].stats._modify.day,
4016 files[sel].stats._modify.hour,
4017 files[sel].stats._modify.min,
4018 files[sel].stats._modify.sec,
4019 &text_inc
4020 );
4021 text_pos += text_inc;
4022 if(!strncmp(path, "mc", 2)){
4023 mcGetInfo(path[2]-'0', 0, &mctype_PSx, NULL, NULL);
4024 mcSync(0, NULL, &ret);
4025 sprintf(mess+text_pos, " %s=%d%n", LNG(mctype), mctype_PSx, &text_inc);
4026 text_pos += text_inc;
4027 }
4028 sprintf(mess+text_pos, " mcTsz=%d%n", files[sel].stats.fileSizeByte, &text_inc);
4029 text_pos += text_inc;
4030 }
4031//----- End of sections that show attributes -----
4032 browser_pushed = FALSE;
4033}
4034//------------------------------
4035//endfunc submenu_func_GetSize
4036//--------------------------------------------------------------
4037void subfunc_Paste(char *mess, char *path)
4038{
4039 char tmp[MAX_PATH], tmp1[MAX_PATH];
4040 int i, ret=-1;
4041
4042 written_size = 0;
4043 PasteTime = Timer(); //Note initial pasting time
4044 drawMsg(LNG(Pasting));
4045 if(!strcmp(path,clipPath)) goto finished;
4046
4047 for(i=0; i<nclipFiles; i++){
4048 strcpy(tmp, clipFiles[i].name);
4049 if(clipFiles[i].stats.attrFile & MC_ATTR_SUBDIR) strcat(tmp,"/");
4050 sprintf(tmp1, " %s", LNG(pasting));
4051 strcat(tmp, tmp1);
4052 drawMsg(tmp);
4053 PM_flag[0] = PM_NORMAL; //Always use normal mode at top level
4054 PM_file[0] = -1; //Thus no attribute file is used here
4055 ret = copy(path, clipPath, clipFiles[i], 0);
4056 if(ret < 0) break;
4057 if(browser_cut){
4058 ret=delete(clipPath, &clipFiles[i]);
4059 if(ret<0) break;
4060 }
4061 }
4062
4063// unmountAll(); //disabled to avoid interference with VMC implementation
4064
4065finished:
4066 if(ret < 0){
4067 strcpy(mess, LNG(Paste_Failed));
4068 browser_pushed = FALSE;
4069 }else
4070 if(browser_cut) nclipFiles=0;
4071 browser_cd=TRUE;
4072}
4073//------------------------------
4074//endfunc subfunc_Paste
4075//--------------------------------------------------------------
4076void submenu_func_Paste(char *mess, char *path)
4077{
4078 if(new_pad & PAD_SQUARE)
4079 PasteMode = PM_RENAME;
4080 else
4081 PasteMode = PM_NORMAL;
4082 subfunc_Paste(mess, path);
4083}
4084//------------------------------
4085//endfunc submenu_func_Paste
4086//--------------------------------------------------------------
4087void submenu_func_mcPaste(char *mess, char *path)
4088{
4089 if(!strncmp(path, "mc", 2)||!strncmp(path, "vmc", 3)){
4090 PasteMode = PM_MC_RESTORE;
4091 } else {
4092 PasteMode = PM_MC_BACKUP;
4093 }
4094 subfunc_Paste(mess, path);
4095}
4096//------------------------------
4097//endfunc submenu_func_mcPaste
4098//--------------------------------------------------------------
4099void submenu_func_psuPaste(char *mess, char *path)
4100{
4101 if(!strncmp(path, "mc", 2)||!strncmp(path, "vmc", 3)){
4102 PasteMode = PM_PSU_RESTORE;
4103 } else {
4104 PasteMode = PM_PSU_BACKUP;
4105 }
4106 subfunc_Paste(mess, path);
4107}
4108//------------------------------
4109//endfunc submenu_func_psuPaste
4110//--------------------------------------------------------------
4111//End of file: filer.c
4112//--------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.