1 /*	$Id: dosio.c,v 1.2 2003/12/05 18:07:15 nonaka Exp $	*/
2 
3 /*
4  * Copyright (c) 2003 NONAKA Kimihiro
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgment:
17  *      This product includes software developed by NONAKA Kimihiro.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <time.h>
35 
36 #include "dosio.h"
37 
38 #ifdef __LIBRETRO__
39 extern char slash;
40 #endif
41 
42 static char	curpath[MAX_PATH+32] = "";
43 static LPSTR	curfilep = curpath;
44 
45 void
dosio_init(void)46 dosio_init(void)
47 {
48 
49 	/* Nothing to do. */
50 }
51 
52 void
dosio_term(void)53 dosio_term(void)
54 {
55 
56 	/* Nothing to do. */
57 }
58 
59 /* �ե�������� */
60 FILEH
file_open(LPSTR filename)61 file_open(LPSTR filename)
62 {
63 	FILEH	ret;
64 
65 	ret = CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
66 	    0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
67 	if (ret == (FILEH)INVALID_HANDLE_VALUE) {
68 		ret = CreateFile(filename, GENERIC_READ,
69 		    0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
70 		if (ret == (FILEH)INVALID_HANDLE_VALUE)
71 			return (FILEH)FALSE;
72 	}
73 	return ret;
74 }
75 
76 FILEH
file_create(LPSTR filename,int ftype)77 file_create(LPSTR filename, int ftype)
78 {
79 	FILEH	ret;
80 
81 	(void)ftype;
82 
83 	ret = CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
84 	    0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
85 	if (ret == (FILEH)INVALID_HANDLE_VALUE)
86 		return (FILEH)FALSE;
87 	return ret;
88 }
89 
90 DWORD
file_seek(FILEH handle,long pointer,short mode)91 file_seek(FILEH handle, long pointer, short mode)
92 {
93 
94 	return SetFilePointer(handle, pointer, 0, mode);
95 }
96 
97 DWORD
file_lread(FILEH handle,void * data,DWORD length)98 file_lread(FILEH handle, void *data, DWORD length)
99 {
100 	DWORD	readsize;
101 
102 	if (ReadFile(handle, data, length, &readsize, NULL) == 0)
103 		return 0;
104 	return readsize;
105 }
106 
107 DWORD
file_lwrite(FILEH handle,void * data,DWORD length)108 file_lwrite(FILEH handle, void *data, DWORD length)
109 {
110 	DWORD	writesize;
111 
112 	if (WriteFile(handle, data, length, &writesize, NULL) == 0)
113 		return 0;
114 	return writesize;
115 }
116 
117 WORD
file_read(FILEH handle,void * data,WORD length)118 file_read(FILEH handle, void *data, WORD length)
119 {
120 	DWORD	readsize;
121 
122 	if (ReadFile(handle, data, length, &readsize, NULL) == 0)
123 		return 0;
124 	return (WORD)readsize;
125 }
126 
127 DWORD
file_zeroclr(FILEH handle,DWORD length)128 file_zeroclr(FILEH handle, DWORD length)
129 {
130 	char	buf[256];
131 	DWORD	size;
132 	DWORD	wsize;
133 	DWORD	ret = 0;
134 
135 	memset(buf, 0, sizeof(buf));
136 	while (length > 0) {
137 		wsize = (length >= sizeof(buf)) ? sizeof(buf) : length;
138 
139 		size = file_lwrite(handle, buf, wsize);
140 		if (size == (DWORD)-1)
141 			return -1;
142 
143 		ret += size;
144 		if (size != wsize)
145 			break;
146 		length -= wsize;
147 	}
148 	return ret;
149 }
150 
151 
152 WORD
file_write(FILEH handle,void * data,WORD length)153 file_write(FILEH handle, void *data, WORD length)
154 {
155 	DWORD	writesize;
156 
157 	if (WriteFile(handle, data, length, &writesize, NULL) == 0)
158 		return 0;
159 	return (WORD)writesize;
160 }
161 
162 WORD
file_lineread(FILEH handle,void * data,WORD length)163 file_lineread(FILEH handle, void *data, WORD length)
164 {
165 	LPSTR	p = (LPSTR)data;
166 	DWORD	readsize;
167 	DWORD	pos;
168 	WORD	ret = 0;
169 
170 	if ((length == 0) || ((pos = file_seek(handle, 0, 1)) == (DWORD)-1))
171 		return 0;
172 
173 	ZeroMemory(data, length);
174 	if (ReadFile(handle, data, length-1, &readsize, NULL) == 0)
175 		return 0;
176 
177 	while (*p) {
178 		ret++;
179 		pos++;
180 		if ((*p == 0x0d) || (*p == 0x0a)) {
181 			break;
182 		}
183 		p++;
184 	}
185 	*p = '\0';
186 
187 	file_seek(handle, pos, 0);
188 
189 	return ret;
190 }
191 
192 short
file_close(FILEH handle)193 file_close(FILEH handle)
194 {
195 
196 	FAKE_CloseHandle(handle);
197 	return 0;
198 }
199 
200 short
file_attr(LPSTR filename)201 file_attr(LPSTR filename)
202 {
203 
204 	return (short)GetFileAttributes(filename);
205 }
206 
207 
208 							// �����ȥե��������
209 void
file_setcd(LPSTR exename)210 file_setcd(LPSTR exename)
211 {
212 
213 	strncpy(curpath, exename, sizeof(curpath));
214 	plusyen(curpath, sizeof(curpath));
215 	curfilep = curpath + strlen(exename) + 1;
216 	*curfilep = '\0';
217 }
218 
219 LPSTR
file_getcd(LPSTR filename)220 file_getcd(LPSTR filename)
221 {
222 
223 	strncpy(curfilep, filename, MAX_PATH - (curfilep - curpath));
224 	return curpath;
225 }
226 
227 FILEH
file_open_c(LPSTR filename)228 file_open_c(LPSTR filename)
229 {
230 
231 	strncpy(curfilep, filename, MAX_PATH - (curfilep - curpath));
232 	return file_open(curpath);
233 }
234 
235 FILEH
file_create_c(LPSTR filename,int ftype)236 file_create_c(LPSTR filename, int ftype)
237 {
238 
239 	strncpy(curfilep, filename, MAX_PATH - (curfilep - curpath));
240 	return file_create(curpath, ftype);
241 }
242 
243 short
file_attr_c(LPSTR filename)244 file_attr_c(LPSTR filename)
245 {
246 
247 	strncpy(curfilep, filename, MAX_PATH - (curfilep - curpath));
248 	return file_attr(curpath);
249 }
250 
251 int
file_getftype(LPSTR filename)252 file_getftype(LPSTR filename)
253 {
254 
255 	(void)filename;
256 
257 	return FTYPE_NONE;
258 }
259 
260 
261 LPSTR
getFileName(LPSTR filename)262 getFileName(LPSTR filename)
263 {
264 	LPSTR p, q;
265 
266 	for (p = q = filename; *p != '\0'; p++)
267 		if (*p == slash/*'/'*/)
268 			q = p + 1;
269 	return q;
270 }
271 
272 void
cutFileName(LPSTR filename)273 cutFileName(LPSTR filename)
274 {
275 	LPSTR p, q;
276 
277 	for (p = filename, q = NULL; *p != '\0'; p++)
278 		if (*p == slash/*'/'*/)
279 			q = p + 1;
280 	if (q != NULL)
281 		*q = '\0';
282 }
283 
284 LPSTR
getExtName(LPSTR filename)285 getExtName(LPSTR filename)
286 {
287 	LPSTR	p;
288 	LPSTR	q;
289 
290 	p = getFileName(filename);
291 	q = NULL;
292 
293 	while (*p != '\0') {
294 		if (*p == '.')
295 			q = p + 1;
296 		p++;
297 	}
298 	if (q == NULL)
299 		q = p;
300 	return q;
301 }
302 
303 void
cutExtName(LPSTR filename)304 cutExtName(LPSTR filename)
305 {
306 	LPSTR	p;
307 	LPSTR	q;
308 
309 	p = getFileName(filename);
310 	q = NULL;
311 
312 	while (*p != '\0') {
313 		if (*p == '.')
314 			q = p;
315 		p++;
316 	}
317 	if (q != NULL)
318 		*q = '\0';
319 }
320 
321 int
kanji1st(LPSTR str,int pos)322 kanji1st(LPSTR str, int pos)
323 {
324 	int	ret = 0;
325 	BYTE	c;
326 
327 	for (; pos > 0; pos--) {
328 		c = (BYTE)str[pos];
329 		if (!((0x81 <= c && c <= 0x9f) || (0xe0 <= c && c <= 0xfc)))
330 			break;
331 		ret ^= 1;
332 	}
333 	return ret;
334 }
335 
336 int
kanji2nd(LPSTR str,int pos)337 kanji2nd(LPSTR str, int pos)
338 {
339 	int	ret = 0;
340 	BYTE	c;
341 
342 	while (pos-- > 0) {
343 		c = (BYTE)str[pos];
344 		if (!((0x81 <= c && c <= 0x9f) || (0xe0 <= c && c <= 0xfc)))
345 			break;
346 		ret ^= 1;
347 	}
348 	return ret;
349 }
350 
351 
352 int
ex_a2i(LPSTR str,int min,int max)353 ex_a2i(LPSTR str, int min, int max)
354 {
355 	int	ret = 0;
356 	char	c;
357 
358 	if (str == NULL)
359 		return(min);
360 
361 	for (;;) {
362 		c = *str++;
363 		if (c == ' ')
364 			continue;
365 		if ((c < '0') || (c > '9'))
366 			break;
367 		ret = ret * 10 + (c - '0');
368 	}
369 
370 	if (ret < min)
371 		return min;
372 	else if (ret > max)
373 		return max;
374 	return ret;
375 }
376 
377 void
cutyen(LPSTR str)378 cutyen(LPSTR str)
379 {
380 	int pos = strlen(str) - 1;
381 
382 	if ((pos > 0) && (str[pos] == slash/*'/'*/))
383 		str[pos] = '\0';
384 }
385 
386 void
plusyen(LPSTR str,int len)387 plusyen(LPSTR str, int len)
388 {
389 	int	pos = strlen(str);
390 
391 	if (pos) {
392 		if (str[pos-1] == slash/*'/'*/)
393 			return;
394 	}
395 	if ((pos + 2) >= len)
396 		return;
397 	str[pos++] = slash/*'/'*/;
398 	str[pos] = '\0';
399 }
400 
401 
402 void
fname_mix(LPSTR str,LPSTR mix,int size)403 fname_mix(LPSTR str, LPSTR mix, int size)
404 {
405 	LPSTR p;
406 	int len;
407 	char c;
408 	char check;
409 
410 	cutFileName(str);
411 	if (mix[0] == slash/*'/'*/)
412 		str[0] = '\0';
413 
414 	len = strlen(str);
415 	p = str + len;
416 	check = '.';
417 	while (len < size) {
418 		c = *mix++;
419 		if (c == '\0')
420 			break;
421 
422 		if (c == check) {
423 			/* current dir */
424 			if (mix[0] == slash/*'/'*/) {
425 				mix++;
426 				continue;
427 			}
428 			/* parent dir */
429 			if (mix[0] == '.' && mix[1] == slash/*'/'*/) {
430 				mix += 2;
431 				cutyen(str);
432 				cutFileName(str);
433 				len = strlen(str);
434 				p = str + len;
435 				continue;
436 			}
437 		}
438 		if (c == slash/*'/'*/)
439 			check = '.';
440 		else
441 			check = 0;
442 		*p++ = c;
443 		len++;
444 	}
445 	if (p < str + len)
446 		*p = '\0';
447 	else
448 		str[len - 1] = '\0';
449 }
450 
451 /*
452  * UNIX -> DOS �����Ѵ�
453  */
454 /* $NetBSD: msdosfs_conv.c,v 1.29 2001/01/18 20:28:27 jdolecek Exp $ */
455 /*-
456  * Copyright (C) 1995, 1997 Wolfgang Solfrank.
457  * Copyright (C) 1995, 1997 TooLs GmbH.
458  * All rights reserved.
459  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
460  *
461  * Redistribution and use in source and binary forms, with or without
462  * modification, are permitted provided that the following conditions
463  * are met:
464  * 1. Redistributions of source code must retain the above copyright
465  *    notice, this list of conditions and the following disclaimer.
466  * 2. Redistributions in binary form must reproduce the above copyright
467  *    notice, this list of conditions and the following disclaimer in the
468  *    documentation and/or other materials provided with the distribution.
469  * 3. All advertising materials mentioning features or use of this software
470  *    must display the following acknowledgement:
471  *	This product includes software developed by TooLs GmbH.
472  * 4. The name of TooLs GmbH may not be used to endorse or promote products
473  *    derived from this software without specific prior written permission.
474  *
475  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
476  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
477  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
478  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
479  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
480  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
481  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
482  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
483  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
484  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
485  */
486 /*
487  * Written by Paul Popelka (paulp@uts.amdahl.com)
488  *
489  * You can do anything you want with this software, just don't say you wrote
490  * it, and don't remove this notice.
491  *
492  * This software is provided "as is".
493  *
494  * The author supplies this software to be publicly redistributed on the
495  * understanding that the author is not responsible for the correct
496  * functioning of this software in any circumstances and is not liable for
497  * any damages caused by this software.
498  *
499  * October 1992
500  */
501 
502 /*
503  * Days in each month in a regular year.
504  */
505 unsigned short const regyear[] = {
506 	31, 28, 31, 30, 31, 30,
507 	31, 31, 30, 31, 30, 31
508 };
509 
510 /*
511  * Days in each month in a leap year.
512  */
513 unsigned short const leapyear[] = {
514 	31, 29, 31, 30, 31, 30,
515 	31, 31, 30, 31, 30, 31
516 };
517 
518 /*
519  * Variables used to remember parts of the last time conversion.  Maybe we
520  * can avoid a full conversion.
521  */
522 static time_t lasttime;
523 static unsigned long lastday;
524 static unsigned short lastddate;
525 static unsigned short lastdtime;
526 
527 /*
528  * Convert the unix version of time to dos's idea of time to be used in
529  * file timestamps. The passed in unix time is assumed to be in GMT.
530  */
531 void
unix2dostime(time_t t,unsigned short * ddp,unsigned short * dtp,unsigned char * dhp)532 unix2dostime(time_t t, unsigned short *ddp, unsigned short *dtp, unsigned char *dhp)
533 {
534 	time_t tt;
535 	unsigned long days;
536 	unsigned long inc;
537 	unsigned long year;
538 	unsigned long month;
539 	const unsigned short *months;
540 
541 	/*
542 	 * If the time from the last conversion is the same as now, then
543 	 * skip the computations and use the saved result.
544 	 */
545 	tt = t;
546 	t &= ~1;
547 	if (lasttime != t) {
548 		lasttime = t;
549 		lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
550 		    + (((t / 60) % 60) << DT_MINUTES_SHIFT)
551 		    + (((t / 3600) % 24) << DT_HOURS_SHIFT);
552 
553 		/*
554 		 * If the number of days since 1970 is the same as the last
555 		 * time we did the computation then skip all this leap year
556 		 * and month stuff.
557 		 */
558 		days = t / (24 * 60 * 60);
559 		if (days != lastday) {
560 			lastday = days;
561 			for (year = 1970;; year++) {
562 				inc = year & 0x03 ? 365 : 366;
563 				if (days < inc)
564 					break;
565 				days -= inc;
566 			}
567 			months = year & 0x03 ? regyear : leapyear;
568 			for (month = 0; month < 12; month++) {
569 				if (days < months[month])
570 					break;
571 				days -= months[month];
572 			}
573 			lastddate = ((days + 1) << DD_DAY_SHIFT)
574 			    + ((month + 1) << DD_MONTH_SHIFT);
575 			/*
576 			 * Remember dos's idea of time is relative to 1980.
577 			 * unix's is relative to 1970.  If somehow we get a
578 			 * time before 1980 then don't give totally crazy
579 			 * results.
580 			 */
581 			if (year > 1980)
582 				lastddate += (year - 1980) << DD_YEAR_SHIFT;
583 		}
584 	}
585 	if (dtp)
586 		*dtp = lastdtime;
587 	if (dhp)
588 		*dhp = (tt & 1) * 100;
589 
590 	*ddp = lastddate;
591 }
592 
593 /*
594  * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
595  * interval there were 8 regular years and 2 leap years.
596  */
597 #define	SECONDSTO1980	(((8 * 365) + (2 * 366)) * (24 * 60 * 60))
598 
599 static unsigned short lastdosdate;
600 static unsigned long lastseconds;
601 
602 /*
603  * Convert from dos' idea of time to unix'. This will probably only be
604  * called from the stat(), and fstat() system calls and so probably need
605  * not be too efficient.
606  */
607 void
dos2unixtime(unsigned int dd,unsigned int dt,unsigned int dh,time_t * tp)608 dos2unixtime(unsigned int dd, unsigned int dt, unsigned int dh, time_t *tp)
609 {
610 	unsigned long seconds;
611 	unsigned long m, month;
612 	unsigned long y, year;
613 	unsigned long days;
614 	const unsigned short *months;
615 
616 	if (dd == 0) {
617 		/*
618 		 * Uninitialized field, return the epoch.
619 		 */
620 		tp = 0;
621 		return;
622 	}
623 	seconds = ((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) * 2
624 	    + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
625 	    + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
626 	    + dh / 100;
627 	/*
628 	 * If the year, month, and day from the last conversion are the
629 	 * same then use the saved value.
630 	 */
631 	if (lastdosdate != dd) {
632 		lastdosdate = dd;
633 		days = 0;
634 		year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT;
635 		for (y = 0; y < year; y++)
636 			days += y & 0x03 ? 365 : 366;
637 		months = year & 0x03 ? regyear : leapyear;
638 		/*
639 		 * Prevent going from 0 to 0xffffffff in the following
640 		 * loop.
641 		 */
642 		month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
643 		if (month == 0) {
644 			printf("dos2unixtime(): month value out of range (%ld)\n",
645 			    month);
646 			month = 1;
647 		}
648 		for (m = 0; m < month - 1; m++)
649 			days += months[m];
650 		days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1;
651 		lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
652 	}
653 	*tp = seconds + lastseconds;
654 }
655