1 /*****************************************************************************
2 ** $Source: /cygdrive/d/Private/_SVNROOT/bluemsx/blueMSX/Src/IoDevice/DirAsDisk.c,v $
3 **
4 ** $Revision: 1.15 $
5 **
6 ** $Date: 2008-06-24 20:10:38 $
7 **
8 ** More info: http://www.bluemsx.com
9 **
10 ** Copyright (C) 2003-2007 Daniel Vik, Tomas Karlsson
11 **
12 ** This program is free software; you can redistribute it and/or modify
13 ** it under the terms of the GNU General Public License as published by
14 ** the Free Software Foundation; either version 2 of the License, or
15 ** (at your option) any later version.
16 **
17 ** This program is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ** GNU General Public License for more details.
21 **
22 ** You should have received a copy of the GNU General Public License
23 ** along with this program; if not, write to the Free Software
24 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 **
26 ******************************************************************************
27 */
28 #define USE_ARCH_GLOB
29 
30 #include "DirAsDisk.h"
31 
32 #pragma warning(disable: 4996)
33 #if defined(WIN32) || defined (WINDOWS_HOST)
34 #include <io.h> // not on Linux
35 #endif
36 
37 #ifdef _WIN32
38 #include <direct.h>
39 #else
40 #include <unistd.h>
41 #endif
42 
43 #include <fcntl.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <stdlib.h>
47 #include <math.h>
48 #include <string.h>
49 #include <stdio.h>
50 #include <time.h>
51 #include <ctype.h>
52 #ifdef USE_ARCH_GLOB
53 #include "ArchGlob.h"
54 #else
55 #include <windows.h>
56 #endif
57 
58 #if defined(WIN32) || defined (WINDOWS_HOST)
59 #include <io.h>
60 #else
61 #ifndef O_BINARY
62 #define O_BINARY 0
63 #endif
64 #endif
65 
66 static const unsigned char msxboot[] = {
67 	0xeb,0xfe,0x90,0x44,0x53,0x4b,0x54,0x4f,
68 	0x4f,0x4c,0x20,0x00,0x02,0x02,0x01,0x00,
69 	0x02,0x70,0x00,0xa0,0x05,0xf9,0x03,0x00,
70 	0x09,0x00,0x02,0x00,0x00,0x00,0xd0,0xed,
71 	0x53,0x59,0xc0,0x32,0xc4,0xc0,0x36,0x56,
72 	0x23,0x36,0xc0,0x31,0x1f,0xf5,0x11,0x79,
73 	0xc0,0x0e,0x0f,0xcd,0x7d,0xf3,0x3c,0xca,
74 	0x63,0xc0,0x11,0x00,0x01,0x0e,0x1a,0xcd,
75 	0x7d,0xf3,0x21,0x01,0x00,0x22,0x87,0xc0,
76 	0x21,0x00,0x3f,0x11,0x79,0xc0,0x0e,0x27,
77 	0xcd,0x7d,0xf3,0xc3,0x00,0x01,0x58,0xc0,
78 	0xcd,0x00,0x00,0x79,0xe6,0xfe,0xfe,0x02,
79 	0xc2,0x6a,0xc0,0x3a,0xc4,0xc0,0xa7,0xca,
80 	0x22,0x40,0x11,0x9e,0xc0,0x0e,0x09,0xcd,
81 	0x7d,0xf3,0x0e,0x07,0xcd,0x7d,0xf3,0x18,
82 	0xb2,0x00,0x4d,0x53,0x58,0x44,0x4f,0x53,
83 	0x20,0x20,0x53,0x59,0x53,0x00,0x00,0x00,
84 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
85 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
86 	0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x6f,
87 	0x6f,0x74,0x20,0x65,0x72,0x72,0x6f,0x72,
88 	0x0d,0x0a,0x50,0x72,0x65,0x73,0x73,0x20,
89 	0x61,0x6e,0x79,0x20,0x6b,0x65,0x79,0x20,
90 	0x66,0x6f,0x72,0x20,0x72,0x65,0x74,0x72,
91 	0x79,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,
92 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
93 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
94 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
95 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
96 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
97 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
98 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
99 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
100 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
101 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
102 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
103 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
104 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
105 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
106 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
107 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
108 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
109 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
110 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
111 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
112 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
113 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
114 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
115 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
116 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
117 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
118 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
119 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
120 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
121 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
122 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
123 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
124 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
125 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
126 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
127 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
128 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
129 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
130 	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
131 };
132 static unsigned char svi738CpmBoot[512] = {
133     0xEB,0xFE,0x90,0x41,0x53,0x43,0x20,0x20,
134     0x32,0x2E,0x32,0x00,0x00,0x00,0x00,0x00,
135     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
136     0x00,0x00,0x00,0x00,0x00,0x00,0xD0,0x21,
137     0x2D,0xC0,0x11,0x00,0x80,0x01,0x24,0x00,
138     0xED,0xB0,0xC3,0x00,0x80,0xF3,0x11,0x00,
139     0x90,0x0E,0x1A,0xCD,0x7D,0xF3,0x11,0x01,
140     0x00,0x26,0x10,0x2E,0x00,0x0E,0x2F,0xCD,
141     0x7D,0xF3,0xF3,0x21,0x00,0x90,0x11,0x00,
142     0xE2,0x01,0xD0,0x1D,0xED,0xB0,0xC3,0x00,
143     0xE2,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,
144     0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,
145     0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,
146     0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,
147     0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,
148     0xFF,0x00,0xFF,0x00,0xFF,0xFF,0xFF,0x00,
149     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
150     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
151     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
152     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
153     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
154     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
155     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
156     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
157     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
158     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
159     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
160     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
161     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
162     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
163     0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
164     0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0xFF,
165     0xE1,0xC3,0x29,0xE1,0x3A,0x42,0xD7,0xC3,
166     0x01,0xD7,0xEB,0x22,0xB1,0xE1,0xC3,0xDA,
167     0xD9,0x2A,0xBF,0xE1,0xC3,0x29,0xE1,0x2A,
168     0xAD,0xE1,0xC3,0x29,0xE1,0xCD,0x51,0xE0,
169     0xCD,0x3B,0xDC,0xC3,0x01,0xDB,0x2A,0xBB,
170     0xE1,0x22,0x45,0xD7,0xC9,0x3A,0xD6,0xE1,
171     0xFE,0xFF,0xC2,0x3B,0xE1,0x3A,0x41,0xD7,
172     0xC3,0x01,0xD7,0xE6,0x1F,0x32,0x41,0xD7,
173     0xC9,0xCD,0x51,0xE0,0xC3,0x93,0xDF,0xCD,
174     0x51,0xE0,0xC3,0x9C,0xDF,0xCD,0x51,0xE0,
175     0xC3,0xD2,0xDF,0x2A,0x43,0xD7,0x7D,0x2F,
176     0x5F,0x7C,0x2F,0x2A,0xAF,0xE1,0xA4,0x57,
177     0x7D,0xA3,0x5F,0x2A,0xAD,0xE1,0xEB,0x22,
178     0xAF,0xE1,0x7D,0xA3,0x6F,0x7C,0xA2,0x67,
179     0x22,0xAD,0xE1,0xC9,0x3A,0xDE,0xE1,0xB7,
180     0xCA,0x91,0xE1,0x2A,0x43,0xD7,0x36,0x00,
181     0x3A,0xE0,0xE1,0xB7,0xCA,0x91,0xE1,0x77,
182     0x3A,0xDF,0xE1,0x32,0xD6,0xE1,0xCD,0x45,
183     0xE0,0x2A,0x0F,0xD7,0xF9,0x2A,0x45,0xD7,
184     0x7D,0x44,0xC9,0xCD,0x51,0xE0,0x3E,0x02,
185     0x32,0xD5,0xE1,0x0E,0x00,0xCD,0x07,0xDF,
186     0xCC,0x03,0xDE,0xC9,0xE5,0x00,0x00,0x00,
187     0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
188     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
189     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
190     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
191     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
192     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
193     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
194     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
195     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
196     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
197 };
198 static unsigned char msx2cpm3boot[512] = {
199     0xE9,0x00,0x00,0x52,0x56,0x53,0x20,0x64,
200     0x61,0x74,0x61,0x00,0x02,0x02,0x01,0x00,
201     0x02,0x70,0x00,0xD0,0x02,0xF8,0x02,0x00,
202     0x09,0x00,0x01,0x00,0x00,0x00,0xD0,0xF3,
203     0x31,0x1F,0xF5,0x21,0x00,0xC0,0x11,0x00,
204     0x80,0x01,0xFF,0x3F,0xED,0xB0,0xC3,0x31,
205     0x80,0x21,0x00,0xC1,0x06,0x00,0xDB,0xA8,
206     0xE6,0x3F,0x57,0xD3,0xA8,0x3A,0xFF,0xFF,
207     0x2F,0x4F,0xE6,0x3F,0x5F,0x32,0xFF,0xFF,
208     0x97,0x3D,0xD3,0xFF,0x77,0x20,0xFA,0xD3,
209     0xFF,0xBE,0x20,0x04,0x3C,0x20,0xF8,0x3D,
210     0xB8,0xDA,0x61,0x80,0xED,0x53,0x70,0x80,
211     0x47,0x7B,0xC6,0x40,0x30,0xDE,0x79,0x32,
212     0xFF,0xFF,0x7A,0xC6,0x40,0x30,0xCB,0x11,
213     0x00,0x00,0x7A,0xD3,0xA8,0x7B,0x32,0xFF,
214     0xFF,0x78,0x32,0xFF,0x00,0xD9,0x3E,0x03,
215     0xD3,0xFF,0x21,0x00,0x00,0x11,0x00,0xC0,
216     0x01,0x00,0x01,0xED,0xB0,0x3E,0x00,0xD3,
217     0xFF,0x21,0x00,0x80,0x11,0x00,0xC0,0x01,
218     0xFF,0x3F,0xED,0xB0,0xD9,0xC3,0xA0,0xC0,
219     0x7A,0xCD,0xE5,0xC0,0xD3,0xA8,0x7B,0xCD,
220     0xE5,0xC0,0x32,0xFF,0xFF,0x57,0xE6,0x03,
221     0x4F,0x06,0x00,0x21,0xC5,0xFC,0x09,0x72,
222     0x3E,0x50,0x32,0xAE,0xF3,0xFD,0x2A,0xC0,
223     0xFC,0xDD,0x21,0x6C,0x00,0xCD,0x1C,0x00,
224     0x1E,0x01,0x0E,0x1B,0xCD,0x7D,0xF3,0x11,
225     0x00,0x02,0x0E,0x1A,0xCD,0x7D,0xF3,0x11,
226     0x03,0x00,0x21,0x00,0x06,0x0E,0x2F,0xCD,
227     0x7D,0xF3,0xC3,0x00,0x02,0xE6,0xC0,0x47,
228     0x0F,0x0F,0xB0,0x47,0x0F,0x0F,0x0F,0x0F,
229     0xB0,0xC9,0x00,0x00,0x00,0x00,0x00,0x00,
230     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
231     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
232     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
233     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
234     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
235     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
236     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
237     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
238     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
239     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
240     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
241     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
242     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
243     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
244     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
245     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
246     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
247     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
248     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
249     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
250     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
251     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
252     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
253     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
254     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
255     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
256     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
257     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
258     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
259     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
260     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
261     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
262     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
263 };
264 
265 typedef unsigned char byte;
266 typedef unsigned short word;
267 typedef struct {
268   char name[9];
269   char ext[4];
270   int size;
271   int hour,min,sec;
272   int day,month,year;
273   int first;
274   int pos;
275   int attr;
276 } fileinfo;
277 
278 static int dskimagesize = 0;
279 static byte *dskimage=NULL;
280 static byte *fat;
281 static byte *direc;
282 static byte *cluster;
283 static int sectorsperfat,numberoffats,reservedsectors;
284 static int bytespersector,direlements,fatelements;
285 static int availsectors;
286 
287 static int alBlockNo;
288 
load_dsk_svi(int diskType)289 static void load_dsk_svi(int diskType)
290 {
291     int imageSize = 0;
292     int dirOff = 0;
293     byte fatData = 0;
294 
295     switch (diskType) {
296     case 7:         // MSX2 CP/M 3 DSDD
297         imageSize = 720;
298         alBlockNo = 1;
299         break;
300     case 6:         // MSX2 CP/M 3 SSDD
301         imageSize = 360;
302         alBlockNo = 1;
303         break;
304     case 3:         // SVI-738 CP/M SSDD
305         imageSize = 360;
306         alBlockNo = 1;
307         break;
308     case 5:         // SVI-328 Disk Basic DSDD
309         dirOff = 0x2A000;
310         fatData = 0xFF;
311     case 2:         // SVI-328 CP/M DSDD
312         imageSize = 338;
313         alBlockNo = 1;
314         break;
315     case 4:         // SVI-328 Disk Basic SSDD
316         dirOff = 0x14C00;
317         fatData = 0xFE;
318     case 1:         // SVI-328 CP/M SSDD
319         imageSize = 168;
320         alBlockNo = 2;
321         break;
322     }
323 
324     dskimage = (byte *) calloc (1, imageSize * 1024);
325     memset(dskimage, 0xe5, imageSize * 1024);
326     dskimagesize = imageSize * 1024;
327 
328     if (diskType == 3) {
329         memcpy(dskimage, svi738CpmBoot, 512);
330     }
331     if (diskType == 6 || diskType == 7) {
332         memcpy(dskimage, msx2cpm3boot, 512);
333         if (diskType == 7) {
334             dskimage[dirOff + 0x13] = 0xA0;
335         }
336     }
337 
338     if (diskType == 4 || diskType == 5) {
339         memset(dskimage + dirOff, 0xFF, 17 * 256);
340         memset(dskimage + dirOff + 13 * 256, 0x00, 256);
341 
342         memset(dskimage + dirOff + 14 * 256, 0xFF, 40);
343         memset(dskimage + dirOff + 14 * 256 + 40, fatData, 40);
344         memset(dskimage + dirOff + 14 * 256, 0xFE, 3);
345         dskimage[dirOff + 14 * 256 + 20] = 0xFE;
346         memset(dskimage + dirOff + 14 * 256 + 80, 0x20, 48);
347         memset(dskimage + dirOff + 14 * 256 + 128, 0x00, 128);
348 
349         memcpy(dskimage + dirOff + 15 * 256, dskimage + dirOff + 14 * 256, 256);
350         memcpy(dskimage + dirOff + 16 * 256, dskimage + dirOff + 14 * 256, 256);
351     }
352 }
353 
load_dsk_msx(void)354 static void load_dsk_msx(void) {
355     dskimagesize = 720*1024;
356     dskimage=(byte *) calloc (1,720*1024);
357     memset (dskimage,0,720*1024);
358     memcpy (dskimage,msxboot,512);
359     reservedsectors=*(word *)(dskimage+0x0E);
360     numberoffats=*(dskimage+0x10);
361     sectorsperfat=*(word *)(dskimage+0x16);
362     bytespersector=*(word *)(dskimage+0x0B);
363     direlements=*(word *)(dskimage+0x11);
364     fat=dskimage+bytespersector*reservedsectors;
365     direc=fat+bytespersector*(sectorsperfat*numberoffats);
366     cluster=direc+direlements*32;
367     availsectors=80*9*2-reservedsectors-sectorsperfat*numberoffats;
368     availsectors-=direlements*32/bytespersector;
369     fatelements=availsectors/2;
370     fat[0]=0xF9;
371     fat[1]=0xFF;
372     fat[2]=0xFF;
373 }
374 
getfileinfo(int pos)375 static fileinfo *getfileinfo(int pos) {
376   fileinfo *file;
377   byte *dir;
378   int i;
379 
380   dir=direc+pos*32;
381   if (*dir<0x20 || *dir>=0x80) return NULL;
382 
383   file=(fileinfo *) malloc (sizeof (fileinfo));
384   for (i=0; i<8; i++)
385     file->name[i]=dir[i]==0x20?0:dir[i];
386   file->name[8]=0;
387 
388   for (i=0; i<3; i++)
389     file->ext[i]=dir[i+8]==0x20?0:dir[i+8];
390   file->ext[3]=0;
391 
392   file->size=*(int *)(dir+0x1C);
393 
394   i=*(word *)(dir+0x16);
395   file->sec=(i&0x1F)<<1;
396   file->min=(i>>5)&0x3F;
397   file->hour=i>>11;
398 
399   i=*(word *)(dir+0x18);
400   file->day=i&0x1F;
401   file->month=(i>>5)&0xF;
402   file->year=1980+(i>>9);
403 
404   file->first=*(word *)(dir+0x1A);
405   file->pos=pos;
406   file->attr=*(dir+0xB);
407 
408   return file;
409 }
410 
getfilelength(int fd)411 static int getfilelength(int fd) {
412     int cur = lseek(fd, 0, SEEK_CUR);
413     int length = lseek(fd, 0, SEEK_END);
414     lseek(fd, cur, SEEK_SET);
415     return length;
416 }
417 
match(fileinfo * file,char * name)418 static int match(fileinfo *file, char *name) {
419   char *p=file->name;
420   int status=0,i;
421 
422   for (i=0; i<8; i++) {
423     if (!*name)
424       break;
425     if (*name=='*') {
426       status=1;
427       name++;
428       break;
429     }
430     if (*name=='.')
431       break;
432     if (toupper (*name++)!=toupper (*p++))
433       return 0;
434   }
435   if (!status && i<8 && *p!=0)
436     return 0;
437   p=file->ext;
438   if (!*name && !*p) return 1;
439   if (*name++!='.') return 0;
440   for (i=0; i<3; i++) {
441     if (*name=='*')
442       return 1;
443     if (toupper (*name++)!=toupper (*p++))
444       return 0;
445   }
446   return 1;
447 }
448 
next_link(int link)449 static int next_link(int link) {
450   int pos;
451 
452   pos=(link>>1)*3;
453   if (link&1)
454     return (((int)(fat[pos+2]))<<4)+(fat[pos+1]>>4);
455   else
456     return (((int)(fat[pos+1]&0xF))<<8)+fat[pos];
457 }
458 
bytes_free(void)459 static int bytes_free(void) {
460   int i,avail=0;
461 
462   for (i=2; i<2+fatelements; i++)
463     if (!next_link (i)) avail++;
464   return avail*1024;
465 }
466 
remove_link(int link)467 static int remove_link(int link) {
468   int pos;
469   int current;
470 
471   pos=(link>>1)*3;
472   if (link&1) {
473     current=(((int)(fat[pos+2]))<<4)+(fat[pos+1]>>4);
474     fat[pos+2]=0;
475     fat[pos+1]&=0xF;
476     return current;
477   }
478   else  {
479     current=(((int)(fat[pos+1]&0xF))<<8)+fat[pos];
480     fat[pos]=0;
481     fat[pos+1]&=0xF0;
482     return current;
483   }
484 }
485 
wipe(fileinfo * file)486 static void wipe(fileinfo *file) {
487   int current;
488 
489   current=file->first;
490   do {
491     current=remove_link (current);
492   } while (current!=0xFFF);
493   direc[file->pos*32]=0xE5;
494 }
495 
get_free(void)496 static int get_free(void) {
497   int i;
498 
499   for (i=2; i<2+fatelements; i++)
500     if (!next_link (i)) return i;
501   //printf ("Internal error\n");
502   //exit (5);
503   return 0;
504 }
505 
get_next_free(void)506 static int get_next_free(void) {
507   int i,status=0;
508 
509   for (i=2; i<2+fatelements; i++)
510     if (!next_link (i))
511       if (status)
512         return i;
513       else
514         status=1;
515   //printf ("Internal error\n");
516   //exit (5);
517   return 0;
518 }
519 
store_fat(int link,int next)520 static void store_fat(int link, int next) {
521   int pos;
522 
523   pos=(link>>1)*3;
524   if (link&1) {
525     fat[pos+2]=next>>4;
526     fat[pos+1]&=0xF;
527     fat[pos+1]|=(next&0xF)<<4;
528   }
529   else  {
530     fat[pos]=next&0xFF;
531     fat[pos+1]&=0xF0;
532     fat[pos+1]|=next>>8;
533   }
534 }
535 
add_single_file(char * name,const char * pathname)536 static int add_single_file(char *name, const char *pathname) {
537   int i,total;
538   fileinfo *file;
539   int fileid;
540   byte *buffer;
541   byte *b;
542   int size;
543   struct stat s;
544   struct tm *t;
545   int first;
546   int current;
547   int next;
548   int pos;
549   char *p;
550   char fullname[250];
551   int result;
552 
553   strcpy (fullname,pathname);
554   strcat (fullname,"/");
555   strcat (fullname,name);
556   fileid=open (fullname,O_BINARY|O_RDONLY);
557 
558   if (fileid < 0) {
559       return -1;
560   }
561 
562   for (i=0; i<direlements; i++) {
563     if ((file=getfileinfo (i))!=NULL) {
564       if (match (file,name)) {
565         wipe (file);
566       }
567       free (file);
568     }
569   }
570 
571   if ((size=getfilelength(fileid))>bytes_free())
572   {
573     close (fileid);
574     return 1;
575   }
576 
577   for (i=0; i<direlements; i++)
578     if (direc[i*32]<0x20 || direc[i*32]>=0x80)
579       break;
580   if (i==direlements)
581   {
582     close (fileid);
583     return 2;
584   }
585 
586   pos=i;
587 
588   b = buffer=(byte *) malloc ((size+1023)&(~1023));
589   read (fileid,buffer,size);
590 
591   close (fileid);
592 
593   total=(size+1023)>>10;
594   current=first=get_free ();
595 
596   for (i=0; i<total;) {
597     memcpy (cluster+(current-2)*1024,buffer,1024);
598     buffer+=1024;
599     if (++i==total)
600       next=0xFFF;
601     else
602       next=get_next_free ();
603     store_fat (current,next);
604     current=next;
605   }
606 
607   memset (direc+pos*32,0,32);
608   memset (direc+pos*32,0x20,11);
609   i=0;
610   for (p=name;*p;p++) {
611     if (*p=='.') {
612       i=8;
613       continue;
614     }
615     direc[pos*32+i++]=toupper (*p);
616   }
617 
618   result = stat(fullname, &s);
619 
620   t = localtime(&s.st_mtime);
621   if (t == NULL) {
622       time_t tmp = time(NULL);
623       t = localtime(&tmp);
624   }
625 ;
626   if (t == NULL) {
627       result = -1;
628   }
629   else {
630     *(word *)(direc+pos*32+0x1A)=first;
631     *(int *)(direc+pos*32+0x1C)=size;
632     *(word *)(direc+pos*32+0x16)=
633         (t->tm_sec>>1)+(t->tm_min<<5)+(t->tm_hour<<11);
634     *(word *)(direc+pos*32+0x18)=
635         (t->tm_mday)+(t->tm_mon<<5)+((t->tm_year-1980)<<9);
636   }
637   free (b);
638   return result;
639 }
640 
641 /* strupr is not a standard ANSI function, so define our own version */
my_strupr(char * s)642 static char* my_strupr(char* s)
643 {
644     char* p = s;
645     while (*p) {
646         *p = toupper(*p);
647         ++p;
648     }
649     return s;
650 }
651 
add_single_file_svi(int diskType,char * name,const char * pathname)652 static int add_single_file_svi(int diskType, char *name, const char *pathname)
653 {
654     typedef struct
655     {
656         char name[6];
657         char ext[3];
658         byte attrib;
659         byte fatpointer;
660         byte reserved[5];
661     } DirectoryEntry;
662 
663     FILE *fpImport;
664     char fullname[250];
665     char filename[80];
666     char extension[10];
667     char *pname;
668     char *pext;
669     char myname[250];
670     byte fileBuf[17 * 256];
671     int bytesRead;
672     int fileDone;
673     int dirOff;
674     int dirEntryNo = 0;
675     int dirFound = 0;
676     DirectoryEntry myDir;
677     int fatCounter = 0;
678     int fatFound = 0;
679     int nextTrack;
680     int sides;
681     int side = 0;
682     int track = 0;
683     int offset;
684 
685     switch (diskType) {
686     case 5:
687         dirOff = 0x2A000;
688         sides = 2;
689         break;
690     case 4:
691         dirOff = 0x14C00;
692         sides = 1;
693         break;
694     }
695 
696     strcpy(fullname, pathname);
697     strcat(fullname, "/");
698     strcat(fullname, name);
699 
700     strcpy(myname, name);
701     memset(&filename, 0x20, sizeof(filename));
702     memset(&extension, 0x20, sizeof(extension));
703     pname = strtok(name, ".");
704     if (pname != NULL) {
705         memcpy(filename, pname, strlen(pname));
706         pext = strrchr(myname, '.');
707         if (pext != NULL) {
708             memcpy(extension, pext + 1, strlen(pext));
709         }
710     }
711     else {
712         memcpy(filename, myname, strlen(myname));
713     }
714 
715     do {
716         if (dskimage[dirOff + 16 * dirEntryNo] == 0xff) {
717             dirFound = 1;
718         }
719         else {
720             dirEntryNo++;
721         }
722     }
723     while (dirEntryNo < 16 * 13 && !dirFound);
724 
725     if (!dirFound) {
726         return 1;
727     }
728 
729     do {
730         if (dskimage[dirOff + 14 * 256 + fatCounter] == 0xff) {
731             fatFound = 1;
732         }
733         else {
734             fatCounter++;
735         }
736     }
737     while (fatCounter < 80 && !fatFound);
738 
739     if (!fatFound) {
740         return 1;
741     }
742 
743     fpImport = fopen(fullname, "rb");
744     if (!fpImport) {
745         return 1;
746     }
747 
748     memset(&myDir, 0xff, sizeof(myDir));
749     memcpy(&myDir.name, filename, 6);
750     memcpy(&myDir.ext, extension, 3);
751     myDir.fatpointer = fatCounter;
752     myDir.attrib = 0;
753 
754     pext = my_strupr(extension);
755     if (0 == strncmp(extension, "BAS ", 3))
756         myDir.attrib = 0x80;
757     else if (0 == strncmp(extension, "BIN ", 3))
758         myDir.attrib = 0x01;
759     else if (0 == strncmp(extension, "DAT ", 3))
760         myDir.attrib = 0x40;
761     else if (0 == strncmp(extension, "SCR ", 3))
762         myDir.attrib = 0xA0;
763     else
764         myDir.attrib = 0;
765 
766     do {
767         memset(&fileBuf, 0x00, sizeof(fileBuf));
768 
769         bytesRead = fread(fileBuf, 1, sizeof(fileBuf), fpImport);
770         fileDone = (bytesRead != sizeof(fileBuf));
771 
772         track = fatCounter;
773         if (track > 39) {
774             side = 1;
775             track = 80 - fatCounter;
776         }
777         offset = ((track * sides + side) * 17 + 1 - 1) * 256 - 2048;
778         memcpy(dskimage + offset, &fileBuf, bytesRead);
779 
780         if (!fileDone) {
781             nextTrack = fatCounter;
782             nextTrack++;
783             if (nextTrack == 20) {
784                 nextTrack++;
785             }
786             dskimage[dirOff + 14 * 256 + fatCounter] = nextTrack;
787             fatCounter = nextTrack;
788         }
789     }
790     while (!fileDone);
791 
792     memcpy(dskimage + dirOff + dirEntryNo * 16, &myDir, sizeof(myDir));
793 
794     dskimage[dirOff + 14 * 256 + fatCounter] = 0xC0 | (int)ceil(bytesRead / 256.00);
795 
796     memcpy(dskimage + dirOff + 15 * 256, dskimage + dirOff + 14 * 256, 256);
797     memcpy(dskimage + dirOff + 16 * 256, dskimage + dirOff + 14 * 256, 256);
798 
799     fclose(fpImport);
800     return 0;
801 }
802 
add_single_file_cpm(int diskType,char * name,const char * pathname)803 static int add_single_file_cpm(int diskType, char *name, const char *pathname)
804 {
805     typedef struct
806     {
807         byte status;    // UU
808         char name[8];   // Fn
809         char ext[3];    // Tn
810         byte extnol;    // EX
811         byte lrc;       // S2
812         byte extnoh;    // S1
813         byte blkcnt;    // RC
814         byte pointers[16];  // AL
815     } DirectoryEntry;
816 
817     DirectoryEntry myDir;
818     FILE *fpImport;
819     char fullname[250];
820     int drm = 0;
821     int drmFound = 0;
822     byte fileBuf[2048];
823     int fileSize;
824     char myname[250];
825     char filename[80];
826     char extension[10];
827     char *pname;
828     char *pext;
829     int fileDone;
830     int dskDataOffset;
831     int alCount = 0;
832     int extent = 0;
833     int fileRead;
834     word dirOffset;
835     int dpbBLS;
836     int sides;
837     int trackOffset;
838     switch (diskType) {
839     case 7:     // MSX2 CP/M 3 DSDD
840         dirOffset = 0x2400;
841         dpbBLS = 2048;
842         sides = 1;
843         break;
844     case 6:     // MSX2 CP/M 3 SSDD
845         dirOffset = 0x2400;
846         dpbBLS = 2048;
847         sides = 0;
848         break;
849     case 3:     // SVI-738 CP/M SSDD
850         dirOffset = 0x3600;
851         dpbBLS = 2048;
852         sides = 0;
853         break;
854     case 2:     // SVI-328 CP/M DSDD
855         dirOffset = 0x5E00;
856         dpbBLS = 2048;
857         sides = 1;
858         break;
859     case 1:     // SVI-328 CP/M SSDD
860     default:
861         dirOffset = 0x2B00;
862         dpbBLS = 1024;
863         sides = 0;
864         break;
865     }
866 
867     strcpy(fullname, pathname);
868     strcat(fullname, "/");
869     strcat(fullname, name);
870 
871     name = my_strupr(name);
872     strcpy(myname, name);
873 
874     memset(filename, 0x20, sizeof(filename));
875     memset(extension, 0x20, sizeof(extension));
876 
877     pname = strtok(name, ".");
878     if (pname != NULL) {
879         memcpy(filename, pname, strlen(pname));
880         pext = strrchr(myname, '.');
881         if (pext != NULL) {
882             memcpy(extension, pext + 1, strlen(pext));
883         }
884     }
885     else {
886         memcpy(filename, myname, strlen(myname));
887     }
888 
889     fpImport = fopen(fullname, "rb");
890     if (!fpImport) {
891         return 1;
892     }
893 
894     fseek(fpImport, 0, SEEK_END);
895     fileSize = ftell(fpImport);
896     if (fileSize > 0x27500) {
897         fclose(fpImport);
898         return 1;
899     }
900 
901     do {
902         if (dskimage[dirOffset + drm * 0x20] == 0xe5) {
903             drmFound = 1;
904         }
905         else {
906             drm++;
907         }
908     }
909     while (drm < 0x40 && !drmFound);
910 
911     if (!drmFound)
912     {
913         fclose(fpImport);
914         return 1;
915     }
916 
917     memset(&myDir, 0, sizeof(myDir));
918     memcpy(&myDir.name, filename, 8);
919     memcpy(&myDir.ext, extension, 3);
920 
921     rewind(fpImport);
922     do {
923         memset(&fileBuf, 0, dpbBLS);
924         myDir.pointers[alCount] = alBlockNo;
925 
926 //        trackOffset = ((alBlockNo - 1) & 0x02) ? (4352 * sides) : (4352 * sides + 4352);
927         trackOffset = ((alBlockNo - 1) & 0x02) ? (4352 * sides) : (4352 * sides);
928         dskDataOffset = (dirOffset + (alBlockNo * dpbBLS)) + trackOffset;
929 //        dskDataOffset = dirOffset + (alBlockNo * dpbBLS);
930 
931         fileRead = fread(fileBuf, 1, dpbBLS, fpImport);
932         fileDone = (fileRead != dpbBLS);
933 
934         memcpy(&dskimage[dskDataOffset], &fileBuf, dpbBLS);
935 
936         alBlockNo++;
937         alCount++;
938         if (alCount > 15) {
939             myDir.blkcnt = 0x80;
940             memcpy(&dskimage[dirOffset + drm * sizeof(myDir)], &myDir, sizeof(myDir));
941             memset(&myDir.pointers, 0, sizeof(myDir.pointers));
942             alCount = 0;
943             extent++;
944             myDir.extnol = extent;
945             drm++;
946         }
947     }
948     while (!fileDone);
949 
950     fclose(fpImport);
951 
952     myDir.blkcnt = (int)ceil((alCount * dpbBLS - (dpbBLS - fileRead)) / 128.00);
953 
954     memcpy(&dskimage[dirOffset + drm * sizeof(myDir)], &myDir, sizeof(myDir));
955 
956     return 0;
957 }
958 
959 #ifdef USE_ARCH_GLOB
dirLoadFile(DirDiskType diskType,const char * directory,int * size)960 void* dirLoadFile(DirDiskType diskType, const char* directory, int* size)
961 {
962     ArchGlob* glob;
963     static char filename[512];
964 
965     if (diskType == 0) {
966         load_dsk_msx();
967     }
968     else {
969         load_dsk_svi(diskType);
970     }
971 
972     sprintf(filename, "%s/*", directory);
973 
974     glob = archGlob(filename, ARCH_GLOB_FILES);
975 
976     if (glob != NULL) {
977         int rv;
978         int i;
979         for (i = 0; i < glob->count; i++) {
980             char* fileName = strrchr(glob->pathVector[i], '/');
981             if (fileName == NULL) {
982                 fileName = strrchr(glob->pathVector[i], '\\');
983             }
984             if (fileName == NULL) {
985                 continue;
986             }
987             fileName++;
988             if (diskType == 0) {
989                 rv = add_single_file(fileName, directory);
990             }
991             else if (diskType == 4 || diskType == 5) {
992                 rv = add_single_file_svi(diskType, fileName, directory);
993             }
994             else {
995                 rv = add_single_file_cpm(diskType, fileName, directory);
996             }
997 
998             if (rv) {
999                 free(dskimage);
1000                 dskimage = NULL;
1001                 break;
1002             }
1003         }
1004 
1005         archGlobFree(glob);
1006     }
1007 
1008     *size = dskimagesize;
1009 
1010     return dskimage;
1011 }
1012 #else
dirLoadFile(DirDiskType diskType,const char * directory,int * size)1013 void* dirLoadFile(DirDiskType diskType, const char* directory, int* size)
1014 {
1015 	WIN32_FIND_DATA fileData;
1016     HANDLE hFile;
1017     static char filename[512];
1018     int success;
1019     int rv;
1020 
1021     if (diskType == 0) {
1022         load_dsk_msx();
1023     }
1024     else {
1025         load_dsk_svi(diskType);
1026     }
1027 
1028     sprintf(filename, "%s" DIR_SEPARATOR "*.*", directory);
1029 
1030     hFile = FindFirstFile(filename,&fileData);
1031     success = hFile != INVALID_HANDLE_VALUE;
1032     while (success) {
1033         if (fileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) {
1034             if (diskType == 0) {
1035                 rv = add_single_file(fileName, directory);
1036             }
1037             else if (diskType == 4 || diskType == 5) {
1038                 rv = add_single_file_svi(diskType, fileName, directory);
1039             }
1040             else {
1041                 rv = add_single_file_cpm(diskType, fileName, directory);
1042             }
1043 
1044             if (rv) {
1045                 free(dskimage);
1046                 dskimage = NULL;
1047                 break;
1048             }
1049         }
1050         success = FindNextFile(hFile, &fileData);
1051 	}
1052 
1053     if (hFile != INVALID_HANDLE_VALUE) {
1054         FindClose(hFile);
1055     }
1056 
1057     *size = dskimagesize;
1058 
1059     return dskimage;
1060 }
1061 #endif
1062