1 /*
2     NIBSCAN - part of the NIBTOOLS package for 1541/1571 disk image nibbling
3 	by Peter Rittwage <peter(at)rittwage(dot)com>
4 */
5 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <time.h>
10 #include <ctype.h>
11 
12 #include "mnibarch.h"
13 #include "gcr.h"
14 #include "nibtools.h"
15 #include "prot.h"
16 #include "md5.h"
17 #include "lz.h"
18 
19 int _dowildcard = 1;
20 
21 char bitrate_range[4] = { 43 * 2, 31 * 2, 25 * 2, 18 * 2 };
22 
23 int load_image(char *filename, BYTE *track_buffer, BYTE *track_density, size_t *track_length);
24 int compare_disks(void);
25 int scandisk(void);
26 int raw_track_info(BYTE *gcrdata, size_t length);
27 int dump_headers(BYTE * gcrdata, size_t length);
28 size_t check_fat(int track);
29 size_t check_rapidlok(int track);
30 
31 BYTE compressed_buffer[(MAX_HALFTRACKS_1541 + 2) * NIB_TRACK_LENGTH];
32 BYTE file_buffer[(MAX_HALFTRACKS_1541 + 2) * NIB_TRACK_LENGTH];
33 BYTE track_buffer[(MAX_HALFTRACKS_1541 + 2) * NIB_TRACK_LENGTH];
34 BYTE track_buffer2[(MAX_HALFTRACKS_1541 + 2) * NIB_TRACK_LENGTH];
35 size_t track_length[MAX_HALFTRACKS_1541 + 2];
36 size_t track_length2[MAX_HALFTRACKS_1541 + 2];
37 BYTE track_density[MAX_HALFTRACKS_1541 + 2];
38 BYTE track_density2[MAX_HALFTRACKS_1541 + 2];
39 BYTE track_alignment[MAX_HALFTRACKS_1541 + 2];
40 BYTE track_alignment2[MAX_HALFTRACKS_1541 + 2];
41 
42 size_t fat_tracks[MAX_HALFTRACKS_1541 + 2];
43 size_t rapidlok_tracks[MAX_HALFTRACKS_1541 + 2];
44 size_t badgcr_tracks[MAX_HALFTRACKS_1541 + 2];
45 
46 int start_track, end_track, track_inc;
47 int imagetype, mode;
48 int align, force_align;
49 int file_buffer_size;
50 int fix_gcr;
51 int reduce_sync;
52 int reduce_badgcr;
53 int reduce_gap;
54 int waitkey = 0;
55 int gap_match_length;
56 int cap_relax;
57 int verbose;
58 int rpm_real;
59 int auto_capacity_adjust;
60 int skew;
61 int align_disk;
62 int ihs;
63 int unformat_passes;
64 int capacity_margin;
65 int align_delay;
66 int cap_min_ignore;
67 int increase_sync = 0;
68 int presync = 0;
69 BYTE fillbyte = 0x55;
70 BYTE drive = 8;
71 char * cbm_adapter = "";
72 int use_floppycode_srq = 0;
73 int extra_capacity_margin=5;
74 int sync_align_buffer=0;
75 int fattrack=0;
76 int track_match=0;
77 int old_g64=0;
78 
79 unsigned char md5_hash_result[16];
80 unsigned char md5_dir_hash_result[16];
81 unsigned char md5_hash_result2[16];
82 unsigned char md5_dir_hash_result2[16];
83 int crc, crc_dir, crc2, crc2_dir;
84 
85 int ARCH_MAINDECL
main(int argc,char * argv[])86 main(int argc, char *argv[])
87 {
88 	char file1[256];
89 	char file2[256];
90 	int i;
91 
92 	start_track = 1 * 2;
93 	end_track = 42 * 2;
94 	track_inc = 2;
95 	align = ALIGN_NONE;
96 	force_align = ALIGN_NONE;
97 	fix_gcr = 0;
98 	gap_match_length = 7;
99 	cap_relax = 0;
100 	mode = 0;
101 	reduce_sync = 4;
102 	reduce_badgcr = 0;
103 	reduce_gap = 0;
104 	rpm_real = 296;
105 	verbose = 1;
106 	cap_min_ignore = 0;
107 
108 	fprintf(stdout,
109 		"\nnibscan - Commodore disk image scanner / comparator\n"
110 		AUTHOR "Revision %d - " VERSION "\n\n", SVN);
111 
112 	/* we can do nothing with no switches */
113 	if (argc < 2)
114 		usage();
115 
116 	/* clear heap buffers */
117 	memset(compressed_buffer, 0x00, sizeof(compressed_buffer));
118 	memset(file_buffer, 0x00, sizeof(file_buffer));
119 	memset(track_buffer, 0x00, sizeof(track_buffer));
120 	memset(track_buffer2, 0x00, sizeof(track_buffer2));
121 
122 	/* default is to reduce sync */
123 	memset(reduce_map, REDUCE_SYNC, MAX_TRACKS_1541+2);
124 
125 	while (--argc && (*(++argv)[0] == '-'))
126 		parseargs(argv);
127 
128 	if (argc < 0)	usage();
129 	strcpy(file1, argv[0]);
130 
131 	if (argc > 1)
132 	{
133 		mode = 1;	//compare
134 		strcpy(file2, argv[1]);
135 	}
136 	printf("\n");
137 
138 	if (mode == 1) 	// compare images
139 	{
140 		if(!(load_image(file1, track_buffer, track_density, track_length))) exit(0);
141 		if(!(load_image(file2,  track_buffer2, track_density2, track_length2))) exit(0);
142 
143 		compare_disks();
144 
145 		/* disk 1 */
146 		printf("\n1: %s\n", file1);
147 
148 		crc_dir = crc_dir_track(track_buffer, track_length);
149 		printf("BAM/DIR CRC:\t\t\t0x%X\n", crc_dir);
150 		crc = crc_all_tracks(track_buffer, track_length);
151 		printf("Full CRC:\t\t\t0x%X\n", crc);
152 
153 		memset(md5_dir_hash_result, 0 , sizeof(md5_dir_hash_result));
154 		md5_dir_track(track_buffer, track_length, md5_dir_hash_result);
155 		printf("BAM/DIR MD5:\t\t\t0x");
156 		for (i = 0; i < 16; i++)
157 		 	printf ("%02x", md5_dir_hash_result[i]);
158 		printf("\n");
159 
160 		memset(md5_hash_result, 0 , sizeof(md5_hash_result));
161 		md5_all_tracks(track_buffer, track_length, md5_hash_result);
162 		printf("Full MD5:\t\t\t0x");
163 		for (i = 0; i < 16; i++)
164 			printf ("%02x", md5_hash_result[i]);
165 		printf("\n");
166 
167 		/* disk 2 */
168 		printf("\n2: %s\n", file2);
169 		crc2_dir = crc_dir_track(track_buffer2, track_length2);
170 		printf("BAM/DIR CRC:\t\t\t0x%X\n", crc2_dir);
171 		crc2 = crc_all_tracks(track_buffer2, track_length2);
172 		printf("Full CRC:\t\t\t0x%X\n", crc2);
173 
174 		memset(md5_dir_hash_result2, 0 , sizeof(md5_dir_hash_result2));
175 		md5_dir_track(track_buffer2, track_length2, md5_dir_hash_result2);
176 		printf("BAM/DIR MD5:\t\t\t0x");
177 		for (i = 0; i < 16; i++)
178 		 	printf ("%02x", md5_dir_hash_result2[i]);
179 		printf("\n");
180 
181 		memset(md5_hash_result2, 0 , sizeof(md5_hash_result2));
182 		md5_all_tracks(track_buffer2, track_length2, md5_hash_result2);
183 		printf("Full MD5:\t\t\t0x");
184 		for (i = 0; i < 16; i++)
185 			printf ("%02x", md5_hash_result2[i]);
186 		printf("\n\n");
187 
188 		/* compare summary */
189 		if(crc_dir == crc2_dir)
190 			printf("BAM/DIR CRC matches.\n");
191 		else
192 			printf("BAM/DIR CRC does not match.\n");
193 
194 		if( memcmp(md5_dir_hash_result, md5_dir_hash_result2, 16 ) == 0 )
195 			printf("BAM/DIR MD5 matches.\n");
196 		else
197 			printf("BAM/DIR MD5 does not match.\n");
198 
199 		if(crc == crc2)
200 			printf("All decodable sectors have CRC matches.\n");
201 		else
202 			printf("All decodable sectors do not have CRC matches.\n");
203 
204 		if( memcmp(md5_hash_result, md5_hash_result2, 16 ) == 0 )
205 			printf("All decodable sectors have MD5 matches.\n");
206 		else
207 			printf("All decodable sectors do not have MD5 matches.\n");
208 	}
209 	else 	// just scan for errors, etc.
210 	{
211 		if(!load_image(file1, track_buffer, track_density, track_length)) exit(0);
212 
213 		scandisk();
214 
215 		printf("\n%s\n", file1);
216 
217 		crc = crc_dir_track(track_buffer, track_length);
218 		printf("BAM/DIR CRC:\t0x%X\n", crc);
219 		crc = crc_all_tracks(track_buffer, track_length);
220 		printf("Full CRC:\t0x%X\n", crc);
221 
222 		memset(md5_hash_result, 0 , sizeof(md5_hash_result));
223 		md5_dir_track(track_buffer, track_length, md5_hash_result);
224 		printf("BAM/DIR MD5:\t0x");
225 		for (i = 0; i < 16; i++)
226 		 	printf ("%02x", md5_hash_result[i]);
227 		printf("\n");
228 
229 		memset(md5_hash_result, 0 , sizeof(md5_hash_result));
230 		md5_all_tracks(track_buffer, track_length, md5_hash_result);
231 		printf("Full MD5:\t0x");
232 		for (i = 0; i < 16; i++)
233 			printf ("%02x", md5_hash_result[i]);
234 		printf("\n");
235 	}
236 
237 	exit(0);
238 }
239 
load_image(char * filename,BYTE * track_buffer,BYTE * track_density,size_t * track_length)240 int load_image(char *filename, BYTE *track_buffer, BYTE *track_density, size_t *track_length)
241 {
242 	if (compare_extension(filename, "D64"))
243 	{
244 		if(!(read_d64(filename, track_buffer, track_density, track_length))) return 0;
245 	}
246 	else if (compare_extension(filename, "G64"))
247 	{
248 		if(!(read_g64(filename, track_buffer, track_density, track_length))) return 0;
249 		if(sync_align_buffer)	sync_tracks(track_buffer, track_density, track_length, track_alignment);
250 	}
251 	else if (compare_extension(filename, "NBZ"))
252 	{
253 		printf("Uncompressing NBZ...\n");
254 		if(!(file_buffer_size = load_file(filename, compressed_buffer))) return 0;
255 		if(!(file_buffer_size = LZ_Uncompress(compressed_buffer, file_buffer, file_buffer_size))) return 0;
256 		if(!(read_nib(file_buffer, file_buffer_size, track_buffer, track_density, track_length))) return 0;
257 		align_tracks(track_buffer, track_density, track_length, track_alignment);
258 		search_fat_tracks(track_buffer, track_density, track_length);
259 	}
260 	else if (compare_extension(filename, "NIB"))
261 	{
262 		if(!(file_buffer_size = load_file(filename, file_buffer))) return 0;
263 		if(!(read_nib(file_buffer, file_buffer_size, track_buffer, track_density, track_length))) return 0;
264 		align_tracks(track_buffer, track_density, track_length, track_alignment);
265 		search_fat_tracks(track_buffer, track_density, track_length);
266 	}
267 	else if (compare_extension(filename, "NB2"))
268 	{
269 		if(!(read_nb2(filename, track_buffer, track_density, track_length))) return 0;
270 		align_tracks(track_buffer, track_density, track_length, track_alignment);
271 		search_fat_tracks(track_buffer, track_density, track_length);
272 	}
273 	else
274 	{
275 		printf("Unknown image type = %s!\n", filename);
276 		return 0;
277 	}
278 	return 1;
279 }
280 
281 int
compare_disks(void)282 compare_disks(void)
283 {
284 	int track;
285 	size_t numtracks = 0;
286 	size_t numsecs = 0;
287 	size_t gcr_match = 0;
288 	size_t sec_match = 0;
289 	size_t dens_mismatch = 0;
290 	size_t gcr_total = 0;
291 	size_t sec_total = 0;
292 	size_t trk_total = 0;
293 	size_t errors_d1 = 0, errors_d2 = 0;
294 	size_t gcr_percentage;
295 	char gcr_mismatches[256];
296 	char sec_mismatches[256];
297 	char gcr_matches[256];
298 	char sec_matches[256];
299 	char dens_mismatches[256];
300 	char tmpstr[16];
301 	char errorstring[0x1000];
302 	BYTE id[3], id2[3], cid[3], cid2[3];
303 
304 	gcr_mismatches[0] = '\0';
305 	sec_mismatches[0] = '\0';
306 	gcr_matches[0] = '\0';
307 	sec_matches[0] = '\0';
308 	dens_mismatches[0] = '\0';
309 
310 	/* ignore halftracks in compare */
311 	track_inc = 2;
312 
313 	// extract disk id's from track 18
314 	memset(id, 0, 3);
315 	extract_id(track_buffer + (36 * NIB_TRACK_LENGTH), id);
316 	memset(id2, 0, 3);
317 	extract_id(track_buffer2 + (36 * NIB_TRACK_LENGTH), id2);
318 
319 	memset(cid, 0, 3);
320 	extract_cosmetic_id(track_buffer + (36 * NIB_TRACK_LENGTH), cid);
321 	memset(cid2, 0, 3);
322 	extract_cosmetic_id(track_buffer2 + (36 * NIB_TRACK_LENGTH), cid2);
323 
324 	if(waitkey) getchar();
325 	printf("\nComparing...\n");
326 
327 	for (track = start_track; track <= end_track; track ++)
328 	{
329 		if(!check_formatted(track_buffer + (track * NIB_TRACK_LENGTH), track_length[track]))
330 		{
331 			track_length[track] = 0;
332 			//printf("1 - UNFORMATTED!\n");
333 			continue;
334 		}
335 
336 		if(!check_formatted(track_buffer2 + (track * NIB_TRACK_LENGTH), track_length2[track]))
337 		{
338 			track_length2[track] = 0;
339 			//printf("2 - UNFORMATTED!\n");
340 			continue;
341 		}
342 
343 		printf("%4.1f, Disk 1: (%d) %d\n",
344 		 	(float)track/2, track_density[track]&3, track_length[track]);
345 
346 		printf("%4.1f, Disk 2: (%d) %d\n",
347 		 	(float)track/2, track_density2[track]&3, track_length2[track]);
348 
349 		numtracks++;
350 
351 		// check for gcr match (unlikely)
352 		gcr_match =
353 		  compare_tracks(
354 			track_buffer + (track * NIB_TRACK_LENGTH),
355 			track_buffer2 + (track * NIB_TRACK_LENGTH),
356 			track_length[track],
357 			track_length2[track],
358 			0,
359 			errorstring);
360 
361 		printf("%s", errorstring);
362 
363 		if(gcr_match)
364 		{
365 			gcr_percentage = (gcr_match*100)/track_length[track];
366 
367 			if (gcr_percentage >= 98)
368 			{
369 				gcr_total++;
370 				printf("\n[*>%d%% GCR MATCH*]\n", (gcr_match*100)/track_length[track]);
371 				sprintf(tmpstr, "%d,", track/2);
372 				strcat(gcr_matches, tmpstr);
373 			}
374 			else
375 			{
376 				printf("\n[*>%d%% GCR MATCH*]\n", (gcr_match*100)/track_length[track]);
377 				sprintf(tmpstr, "%d,", track/2);
378 				strcat(gcr_mismatches, tmpstr);
379 			}
380 		}
381 
382 		if(track/2 <= 35)
383 		{
384 			errors_d1 += check_errors(track_buffer + (NIB_TRACK_LENGTH * track), track_length[track], track, id, errorstring);
385 			errors_d2 += check_errors(track_buffer2 + (NIB_TRACK_LENGTH * track), track_length2[track], track, id2, errorstring);
386 		}
387 
388 		/* check for DOS sector matches */
389 		if(track/2 <= 35)
390 		{
391 			sec_match = compare_sectors(
392 										track_buffer + (track * NIB_TRACK_LENGTH),
393 										track_buffer2 + (track * NIB_TRACK_LENGTH),
394 										track_length[track],
395 										track_length2[track],
396 										id,
397 										id2,
398 										track,
399 										errorstring
400 										);
401 
402 			printf("%s", errorstring);
403 
404 			sec_total += sec_match;
405 			numsecs += sector_map[track/2];
406 
407 			if (sec_match == sector_map[track/2])
408 			{
409 				trk_total++;
410 				printf("[*Data MATCH*]\n");
411 				sprintf(tmpstr, "%d,", track / 2);
412 				strcat(sec_matches, tmpstr);
413 			}
414 			else
415 			{
416 				printf("[*Data MISmatch*]\n");
417 				sprintf(tmpstr, "%d,", track / 2);
418 				strcat(sec_mismatches, tmpstr);
419 			}
420 		}
421 
422 		if(track_density[track] != track_density2[track])
423 		{
424 			printf("[Densities do not match: %d != %d]\n", track_density[track], track_density2[track]);
425 			dens_mismatch++;
426 			sprintf(tmpstr, "%d,", track / 2);
427 			strcat(dens_mismatches, tmpstr);
428 		}
429 		printf("\n");
430 
431 		if((!sec_match) || (track_density[track] != track_density2[track]))
432 			if( waitkey) getchar();
433 	}
434 
435 	printf("\n---------------------------------------------------------------------\n");
436 	printf("%d/%d tracks had at least 98%% GCR match\n", gcr_total, numtracks);
437 	//printf("Matches (%s)\n", gcr_matches);
438 	//printf("Mismatches (%s)\n", gcr_mismatches);
439 	//printf("\n");
440 	printf("%d/%d of likely formatted tracks matched all sector data\n", trk_total, numtracks);
441 	//printf("Matches (%s)\n", sec_matches);
442 	//printf("Mismatches (%s)\n", sec_mismatches);
443 	//printf("\n");
444 	printf("%d/%d total sectors (or errors) matched (%d mismatched)\n", sec_total, numsecs, numsecs-sec_total);
445 	printf("CBM DOS errors (d1/%d - d2/%d)\n",errors_d1, errors_d2);
446 	printf("%d tracks had mismatched densities (%s)\n", dens_mismatch, dens_mismatches);
447 
448 	if(!(id[0]==id2[0] && id[1]==id2[1]))
449 		printf("\nFormat ID's do not match!:\t(%s != %s)", id, id2);
450 	else
451 		printf("\nFormat ID's match:\t\t(%s = %s)", id, id2);
452 
453 	if(!(cid[0]==cid2[0] && cid[1]==cid2[1]))
454 		printf("\nCosmetic ID's do not match:\t(%s != %s)\n", cid, cid2);
455 	else
456 		printf("\nCosmetic ID's match:\t\t(%s = %s)\n", cid, cid2);
457 
458 	printf("---------------------------------------------------------------------\n");
459 
460 	return 1;
461 }
462 
463 int
scandisk(void)464 scandisk(void)
465 {
466 	BYTE id[3], cosmetic_id[3];
467 	int track = 0;
468 	int totalfat = 0;
469 	int totalrl = 0;
470 	int added_sync;
471 	size_t totalgcr = 0;
472 	int total_wrong_density = 0;
473 	size_t empty = 0, temp_empty = 0;
474 	size_t errors = 0, temp_errors = 0;
475 	int defdensity;
476 	char errorstring[0x1000];
477 	char testfilename[16];
478 	FILE *trkout;
479 
480 	// clear buffers
481 	memset(badgcr_tracks, 0, sizeof(badgcr_tracks));
482 	memset(fat_tracks, 0, sizeof(fat_tracks));
483 	memset(rapidlok_tracks, 0, sizeof(rapidlok_tracks));
484 	errorstring[0] = '\0';
485 
486 	printf("\nScanning...\n");
487 
488 	// extract disk id from track 18
489 	memset(id, 0, 3);
490 	extract_id(track_buffer + (36 * NIB_TRACK_LENGTH), id);
491 	printf("\ndisk id: %s\n", id);
492 
493 	// collect and print "cosmetic" disk id for comparison
494 	memset(cosmetic_id, 0, 3);
495 	extract_cosmetic_id(track_buffer + (36 * NIB_TRACK_LENGTH), cosmetic_id);
496 	printf("cosmetic disk id: %s\n", cosmetic_id);
497 
498 	if(waitkey) getchar();
499 
500 	// check each track for various things
501 	for (track = start_track; track <= end_track; track ++)
502 	{
503 		if(!check_formatted(track_buffer + (track * NIB_TRACK_LENGTH), track_length[track]))
504 			//printf("UNFORMATTED");
505 			continue;
506 		else
507 			printf("%4.1f: %d",(float) track/2, track_length[track]);
508 
509 		if (track_length[track] > 0)
510 		{
511 			track_density[track] = check_sync_flags(track_buffer + (track * NIB_TRACK_LENGTH),
512 				track_density[track]&3, track_length[track]);
513 
514 			printf("(%d", track_density[track]&3);
515 
516 			if (track_density[track] & BM_NO_SYNC)
517 				printf(":NOSYNC");
518 			else if (track_density[track] & BM_FF_TRACK)
519 				printf(":KILLER");
520 
521 			// establish default density and warn
522 			defdensity = speed_map[track/2];
523 
524 			if ((track_density[track] & 3) != defdensity)
525 			{
526 				printf("!=%d?) ", defdensity);
527 				if(track < 36*2) total_wrong_density++;
528 				if(waitkey) getchar();
529 			}
530 			else
531 				printf(") ");
532 
533 			if(increase_sync)
534 			{
535 				added_sync = lengthen_sync(track_buffer + (NIB_TRACK_LENGTH * track),
536 					track_length[track], NIB_TRACK_LENGTH);
537 
538 				printf("[sync:%d] ", added_sync);
539 				track_length[track] += added_sync;
540 			}
541 
542 			// detect bad GCR '000' bits
543 			//if (fix_gcr)
544 			{
545 				badgcr_tracks[track] =
546 				  check_bad_gcr(track_buffer + (NIB_TRACK_LENGTH * track), track_length[track]);
547 
548 				if (badgcr_tracks[track])
549 				{
550 					//printf("weak:%d ", badgcr_tracks[track]);
551 					totalgcr += badgcr_tracks[track];
552 				}
553 			}
554 
555 			/* check for rapidlok track
556 			rapidlok_tracks[track] = check_rapidlok(track);
557 
558 			if (rapidlok_tracks[track]) totalrl++;
559 			if ((totalrl) && (track == 72))
560 			{
561 				printf("RAPIDLOK KEYTRACK ");
562 				rapidlok_tracks[track] = 1;
563 			}
564 			*/
565 
566 			/* check for FAT track */
567 			if (track < end_track - track_inc)
568 			{
569 				fat_tracks[track] = check_fat(track);
570 				if (fat_tracks[track]) totalfat++;
571 			}
572 
573 			/* check for regular disk errors
574 				"second half" of fat track will always have header
575 				errors since it's encoded for the wrong track number.
576 				rapidlok tracks are not standard gcr
577 				tracks above 35 are always CBM errors
578 			*/
579 			if(track/2 <= 35)
580 				temp_errors = check_errors(track_buffer + (NIB_TRACK_LENGTH * track), track_length[track], track, id, errorstring);
581 			else /* everything is a CBM error above track 35 */
582 				temp_errors = 0;
583 
584 			if (temp_errors)
585 			{
586 				errors += temp_errors;
587 				printf("%s", errorstring);
588 				if(waitkey) getchar();
589 			}
590 
591 			temp_empty = check_empty(track_buffer + (NIB_TRACK_LENGTH * track), track_length[track], track, id, errorstring);
592 			if (temp_empty)
593 			{
594 				empty += temp_empty;
595 				if(verbose>1) printf(" %s", errorstring);
596 			}
597 
598 			if (verbose>1)
599 			{
600 					dump_headers(track_buffer + (NIB_TRACK_LENGTH * track), track_length[track]);
601 					raw_track_info(track_buffer + (NIB_TRACK_LENGTH * track), track_length[track]);
602 			}
603 		}
604 		printf("\n");
605 
606 		// process and dump to disk for manual compare
607 		//track_length[track] = compress_halftrack(track, track_buffer + (track * NIB_TRACK_LENGTH), track_density[track], track_length[track]);
608 
609 		sprintf(testfilename, "raw/tr%.1fd%d", (float) track/2, (track_density[track] & 3));
610 		if(NULL != (trkout = fopen(testfilename, "w")))
611 		{
612 			fwrite(track_buffer + (track * NIB_TRACK_LENGTH), track_length[track], 1, trkout);
613 			fclose(trkout);
614 		}
615 	}
616 	printf("\n---------------------------------------------------------------------\n");
617 	printf("%d unrecognized sectors (CBM disk errors) detected\n", errors);
618 	printf("%d known empty sectors detected\n", empty);
619 	printf("%d bad GCR bytes detected\n", totalgcr);
620 	printf("%d fat tracks detected\n", totalfat);
621 	printf("%d rapidlok tracks detected\n", totalrl);
622 	printf("%d tracks with non-standard density\n", total_wrong_density);
623 	return 1;
624 }
625 
626 int
dump_headers(BYTE * gcrdata,size_t length)627 dump_headers(BYTE * gcrdata, size_t length)
628 {
629 	BYTE header[10];
630 	BYTE *gcr_ptr, *gcr_end;
631 
632 	gcr_ptr = gcrdata;
633 	gcr_end = gcrdata + length;
634 
635 	do
636 	{
637 		if (!find_sync(&gcr_ptr, gcr_end))
638 			return 0;
639 
640 		convert_4bytes_from_GCR(gcr_ptr, header);
641 		convert_4bytes_from_GCR(gcr_ptr + 5, header + 4);
642 
643 		if(header[0] == 0x08) // only parse headers
644 			printf("\n%.2x %.2x %.2x %.2x = typ:%.2x -- blh:%.2x -- trk:%.2x -- sec:%.2x -- id:%c%c",
645 				*gcr_ptr, *(gcr_ptr+1), *(gcr_ptr+2), *(gcr_ptr+3), header[0], header[1], header[3], header[2], header[5], header[4]);
646 		else // data block should follow
647 			printf("\n%.2x %.2x %.2x %.2x = typ:%.2x",
648 				*gcr_ptr, *(gcr_ptr+1), *(gcr_ptr+2), *(gcr_ptr+3), header[0]);
649 
650 	} while (gcr_ptr < (gcr_end - 10));
651 
652 	printf("\n");
653 
654 	return 1;
655 }
656 
657 
658 int
raw_track_info(BYTE * gcrdata,size_t length)659 raw_track_info(BYTE * gcrdata, size_t length)
660 {
661 	size_t sync_cnt = 0;
662 	size_t sync_len[NIB_TRACK_LENGTH];
663 	/*
664 	int gap_cnt = 0;
665 	int gap_len[NIB_TRACK_LENGTH];
666 	*/
667 	size_t bad_cnt = 0;
668 	size_t bad_len[NIB_TRACK_LENGTH];
669 	size_t i, locked;
670 
671 	memset(sync_len, 0, sizeof(sync_len));
672 	/* memset(gap_len, 0, sizeof(gap_len)); */
673 	memset(bad_len, 0, sizeof(bad_len));
674 
675 	/* count syncs/lengths */
676 	for (locked = 0, i = 0; i < length - 1; i++)
677 	{
678 		if (locked)
679 		{
680 			if (gcrdata[i] == 0xff)
681 				sync_len[sync_cnt]++;
682 			else
683 				locked = 0;
684 		}
685 		//else if (gcrdata[i] == 0xff) /* not full sync, only last 8 bits */
686 		else if(((gcrdata[i] & 0x03) == 0x03) && (gcrdata[i+1] == 0xff))
687 		{
688 			locked = 1;
689 			sync_cnt++;
690 			sync_len[sync_cnt] = 1;
691 		}
692 	}
693 
694 	printf("\nSYNCS:%d (", sync_cnt);
695 	for (i = 1; i <= sync_cnt; i++)
696 		printf("%d-", sync_len[i]);
697 	printf(")");
698 
699 	/* count gaps/lengths - this code is innacurate, since gaps are of course not always 0x55 - they rarely are */
700 	/*
701 	for (locked = 0, i = 0; i < length - 1; i++)
702 	{
703 		if (locked)
704 		{
705 			if (gcrdata[i] == 0x55)
706 				gap_len[gap_cnt]++;
707 			else
708 				locked = 0;
709 		}
710 		else if ((gcrdata[i] == 0x55) && (gcrdata[i + 1] == 0x55))
711 		{
712 			locked = 1;
713 			gap_cnt++;
714 			gap_len[gap_cnt] = 2;
715 		}
716 	}
717 
718 	printf("\nGAPS :%d (", gap_cnt);
719 	for (i = 1; i <= gap_cnt; i++)
720 		printf("%d-", gap_len[i]);
721 	printf(")");
722 	*/
723 
724 	/* count bad gcr lengths */
725 	for (locked = 0, i = 0; i < length - 1; i++)
726 	{
727 		if (locked)
728 		{
729 			if (is_bad_gcr(gcrdata, length, i))
730 				bad_len[bad_cnt]++;
731 			else
732 				locked = 0;
733 		}
734 		else if (is_bad_gcr(gcrdata, length, i))
735 		{
736 			locked = 1;
737 			bad_cnt++;
738 			bad_len[bad_cnt] = 1;
739 		}
740 	}
741 
742 	printf("\nBADGCR:%d (", bad_cnt);
743 	for (i = 1; i <= bad_cnt; i++)
744 		printf("%d-", bad_len[i]);
745 	printf(")");
746 
747 	return 1;
748 }
749 
check_fat(int track)750 size_t check_fat(int track)
751 {
752 	size_t diff = 0;
753 	char errorstring[0x1000];
754 
755 	if (track_length[track] > 0 && track_length[track+2] > 0 && track_length[track] != 8192 && track_length[track+2] != 8192)
756 	{
757 		diff = compare_tracks(
758 		  track_buffer + (track * NIB_TRACK_LENGTH),
759 		  track_buffer + ((track+2) * NIB_TRACK_LENGTH),
760 		  track_length[track],
761 		  track_length[track+2], 1, errorstring);
762 
763 		if(verbose>1) printf("%s",errorstring);
764 
765 		if (diff<=10)
766 		{
767 			printf("*FAT diff=%d*",track/2,(int)diff);
768 			return 1;
769 		}
770 		else if (diff<=35)
771 		{
772 			printf("*Possible FAT diff=%d*",track/2,(int)diff);
773 			return 1;
774 		}
775 		else
776 			if(verbose>1) printf("diff=%d",(int)diff);
777 	}
778 	return 0;
779 }
780 
781 /*
782 	tries to detect and fixup rapidlok track, as the gcr routines
783 	don't assemble them quite right.
784 	this is innaccurate!
785 */
786 
check_rapidlok(int track)787 size_t check_rapidlok(int track)
788 {
789 	size_t i;
790 	size_t end_key = 0;
791 	size_t end_sync = 0;
792 	size_t synclen = 0;
793 	size_t keylen = 0;		// extra sector with # of 0x7b
794 	size_t tlength = track_length[track];
795 	BYTE *gcrdata = track_buffer + (track * NIB_TRACK_LENGTH);
796 
797 	// extra sector is at the end.
798 	// count the extra-sector (key) bytes.
799 	for (i = 0; i < 200; i++)
800 	{
801 		if (gcrdata[tlength - i] == 0x7b)
802 		{
803 			keylen++;
804 			if (end_key)
805 				end_key = tlength - i;	// move marked end of key bytes
806 		}
807 		else if (keylen)
808 			break;
809 	}
810 
811 	if (gcrdata[tlength - i] != 0xff)
812 	{
813 		keylen++;
814 		end_key++;
815 	}
816 
817 	// only rapidlok tracks contain lots of these at start
818 	if (keylen < 0x8)
819 		return (0);
820 
821 	for (i = end_key + 1; i < end_key + 0x100; i++)
822 	{
823 		if (gcrdata[i] == 0xff)
824 		{
825 			synclen++;
826 			end_sync = i + 1;	// mark end of sync
827 		}
828 		else if (synclen)
829 			break;
830 	}
831 
832 	printf("RAPIDLOK! ");
833 	printf("key:%d, sync:%d...", keylen, synclen);
834 
835 #if 0
836 	// recreate key sector
837 	memset(extra_sector, 0xff, 0x14);
838 	memset(extra_sector + 0x14, 0x7b, keylen);
839 
840 	// create initial sync, then copy all sector data
841 	// if directory track no fancy stuff
842 	if(halftrack != 0x24)
843 	{
844 		memset(gcrdata, 0xff, 0x29);
845 		memcpy(gcrdata + 0x29, gcrdata + end_sync, length - end_sync);
846 		memcpy(gcrdata + 0x29 + (length - end_sync), extra_sector,
847 		  keylen + 0x14);
848 	}
849 	else
850 	{
851 		memcpy(gcrdata, gcrdata + end_key, length - end_key);
852 		memcpy(gcrdata + (length - end_key), extra_sector, keylen + 0x14);
853 	}
854 #endif // 0
855 
856 	return keylen;
857 }
858 
859 void
usage(void)860 usage(void)
861 {
862 	fprintf(stderr, "usage: nibscan [options] <filename1> [filename2]\n\n");
863 	switchusage();
864 	exit(1);
865 }
866 
867