1 /*
2   Hatari - createBlankImage.c
3 
4   This file is distributed under the GNU General Public License, version 2
5   or at your option any later version. Read the file gpl.txt for details.
6 
7   Create blank .ST/.MSA disk images.
8 */
9 const char CreateBlankImage_fileid[] = "Hatari createBlankImage.c : " __DATE__ " " __TIME__;
10 
11 #include "main.h"
12 #include "configuration.h"
13 #include "dim.h"
14 #include "file.h"
15 #include "floppy.h"
16 #include "log.h"
17 #include "msa.h"
18 #include "st.h"
19 #include "createBlankImage.h"
20 
21 /*-----------------------------------------------------------------------*/
22 /*
23            40 track SS   40 track DS   80 track SS   80 track DS
24  0- 1   Branch instruction to boot program if executable
25  2- 7   'Loader'
26  8-10   24-bit serial number
27 11-12   BPS    512           512           512           512
28 13      SPC     1             2             2             2
29 14-15   RES     1             1             1             1
30 16      FAT     2             2             2             2
31 17-18   DIR     64           112           112           112
32 19-20   SEC    360           720           720          1440
33 21      MEDIA  $FC           $FD           $F8           $F9  (isn't used by ST-BIOS)
34 22-23   SPF     2             2             5             5
35 24-25   SPT     9             9             9             9
36 26-27   SIDE    1             2             1             2
37 28-29   HID     0             0             0             0
38 510-511 CHECKSUM
39 */
40 
41 
42 /*-----------------------------------------------------------------------*/
43 /**
44  * Calculate the size of a disk in dialog.
45  */
CreateBlankImage_GetDiskImageCapacity(int nTracks,int nSectors,int nSides)46 static int CreateBlankImage_GetDiskImageCapacity(int nTracks, int nSectors, int nSides)
47 {
48 	/* Find size of disk image */
49 	return nTracks*nSectors*nSides*NUMBYTESPERSECTOR;
50 }
51 
52 
53 /*-----------------------------------------------------------------------*/
54 /**
55  * Write a short integer to addr using little endian byte order
56  * (needed for 16 bit values in the bootsector of the disk image).
57  */
WriteShortLE(void * addr,Uint16 val)58 static inline void WriteShortLE(void *addr, Uint16 val)
59 {
60 	Uint8 *p = (Uint8 *)addr;
61 
62 	p[0] = (Uint8)val;
63 	p[1] = (Uint8)(val >> 8);
64 }
65 
66 
67 /*-----------------------------------------------------------------------*/
68 /**
69  * Create .ST/.MSA disk image according to 'Tracks,Sector,Sides' and save
70  * it under given filename.
71  * Return true if saving succeeded, false otherwise.
72  */
CreateBlankImage_CreateFile(const char * pszFileName,int nTracks,int nSectors,int nSides)73 bool CreateBlankImage_CreateFile(const char *pszFileName, int nTracks, int nSectors, int nSides)
74 {
75 	Uint8 *pDiskFile;
76 	unsigned long nDiskSize;
77 	unsigned short int SPC, nDir, MediaByte, SPF;
78 	bool bRet = false;
79 	int drive;
80 
81 	/* HD/ED disks are all double sided */
82 	if (nSectors >= 18)
83 		nSides = 2;
84 
85 	/* Calculate size of disk image */
86 	nDiskSize = CreateBlankImage_GetDiskImageCapacity(nTracks, nSectors, nSides);
87 
88 	/* Allocate space for our 'file', and blank */
89 	pDiskFile = malloc(nDiskSize);
90 	if (pDiskFile == NULL)
91 	{
92 		perror("Error while creating blank disk image");
93 		return false;
94 	}
95 	memset(pDiskFile, 0, nDiskSize);                      /* Clear buffer */
96 
97 	/* Fill in boot-sector */
98 	pDiskFile[0] = 0xE9;                                  /* Needed for MS-DOS compatibility */
99 	memset(pDiskFile+2, 0x4e, 6);                         /* 2-7 'Loader' */
100 
101 	WriteShortLE(pDiskFile+8, rand());                    /* 8-10 24-bit serial number */
102 	pDiskFile[10] = rand();
103 
104 	WriteShortLE(pDiskFile+11, NUMBYTESPERSECTOR);        /* 11-12 BPS */
105 
106 	if ((nTracks == 40) && (nSides == 1))
107 		SPC = 1;
108 	else
109 		SPC = 2;
110 	pDiskFile[13] = SPC;                                  /* 13 SPC */
111 
112 	WriteShortLE(pDiskFile+14, 1);                        /* 14-15 RES */
113 	pDiskFile[16] = 2;                                    /* 16 FAT */
114 
115 	if (SPC==1)
116 		nDir = 64;
117 	else if (nSectors < 18)
118 		nDir = 112;
119 	else
120 		nDir = 224;
121 	WriteShortLE(pDiskFile+17, nDir);                     /* 17-18 DIR */
122 
123 	WriteShortLE(pDiskFile+19, nTracks*nSectors*nSides);  /* 19-20 SEC */
124 
125 	if (nSectors >= 18)
126 		MediaByte = 0xF0;
127 	else
128 	{
129 		if (nTracks <= 42)
130 			MediaByte = 0xFC;
131 		else
132 			MediaByte = 0xF8;
133 		if (nSides == 2)
134 			MediaByte |= 0x01;
135 	}
136 	pDiskFile[21] = MediaByte;                            /* 21 MEDIA */
137 
138 	if (nSectors >= 18)
139 		SPF = 9;
140 	else if (nTracks >= 80)
141 		SPF = 5;
142 	else
143 		SPF = 2;
144 	WriteShortLE(pDiskFile+22, SPF);                      /* 22-23 SPF */
145 
146 	WriteShortLE(pDiskFile+24, nSectors);                 /* 24-25 SPT */
147 	WriteShortLE(pDiskFile+26, nSides);                   /* 26-27 SIDE */
148 	WriteShortLE(pDiskFile+28, 0);                        /* 28-29 HID */
149 
150 	/* Set correct media bytes in the 1st FAT: */
151 	pDiskFile[512] = MediaByte;
152 	pDiskFile[513] = pDiskFile[514] = 0xFF;
153 	/* Set correct media bytes in the 2nd FAT: */
154 	pDiskFile[512 + SPF * 512] = MediaByte;
155 	pDiskFile[513 + SPF * 512] = pDiskFile[514 + SPF * 512] = 0xFF;
156 
157 	/* Ask if OK to overwrite, if exists? */
158 	if (File_QueryOverwrite(pszFileName))
159 	{
160 		drive = 0;				/* drive is not used for ST/MSA/DIM, set it to 0 */
161 		/* Save image to file */
162 		if (MSA_FileNameIsMSA(pszFileName, true))
163 			bRet = MSA_WriteDisk(drive, pszFileName, pDiskFile, nDiskSize);
164 		else if (ST_FileNameIsST(pszFileName, true))
165 			bRet = ST_WriteDisk(drive, pszFileName, pDiskFile, nDiskSize);
166 		else if (DIM_FileNameIsDIM(pszFileName, true))
167 			bRet = DIM_WriteDisk(drive, pszFileName, pDiskFile, nDiskSize);
168 		else
169 			Log_AlertDlg(LOG_ERROR, "Unknown floppy image filename extension!");
170 
171 		/* Did create successfully? */
172 		if (bRet)
173 		{
174 			/* Say OK */
175 			Log_AlertDlg(LOG_INFO, "Disk image '%s' created.", pszFileName);
176 		}
177 		else
178 		{
179 			/* Warn user we were unable to create image */
180 			Log_AlertDlg(LOG_ERROR, "Unable to create disk image '%s'!", pszFileName);
181 		}
182 	}
183 
184 	/* Free image */
185 	free(pDiskFile);
186 	return bRet;
187 }
188