Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
e0b1bb2
update ccos-disk-utils
vklachkov Jul 23, 2026
c988d96
add bitmap block selector to custom image dialog
vklachkov Jul 23, 2026
10237e9
fix autodetect for partial hdd dumps
vklachkov Jul 24, 2026
e48a085
update panels and it's titles properly
vklachkov Jul 24, 2026
295712b
fix opening another partition
vklachkov Jul 24, 2026
6f73966
preview files
vklachkov Jul 24, 2026
e57e58e
use ugly but stable qt file dialog for extract (all) instead of native
vklachkov Jul 26, 2026
fd381f6
show LF in text preview panel
vklachkov Jul 26, 2026
b2982c5
preview all kinds of pictures from grid: raw, raw+dims, gridpaint canvas
vklachkov Jul 26, 2026
4b38020
add word wrap to text file preview
vklachkov Jul 26, 2026
105d9a3
preview worksheet files
vklachkov Jul 26, 2026
42a42dc
allow resize preview window
vklachkov Jul 26, 2026
aa017b9
escape to go up, enter to open preview
vklachkov Jul 27, 2026
dda9667
refactor canvas, worksheet preview plugins using new omf parser
vklachkov Jul 27, 2026
7d5b97a
strp pcl escape seq from worksheet titles
vklachkov Jul 27, 2026
01e632b
use yellow instead of white in canvas preview window
vklachkov Jul 27, 2026
6ce3b32
display file name in preview window title
vklachkov Jul 27, 2026
0883861
preview font files
vklachkov Jul 27, 2026
0cc750f
preview database files
vklachkov Jul 28, 2026
8cce4d5
preview basic, plm, c files as text
vklachkov Jul 28, 2026
394a8f0
preview h, task, com, asm as text
vklachkov Jul 28, 2026
a77d87a
support IMD files opening
vklachkov Jul 28, 2026
250c45f
move panel out from mainwindow to filepanel widget
vklachkov Jul 28, 2026
78cadba
rebuild menu
vklachkov Jul 28, 2026
c7bf496
do not overwrite disk label on cancelled rename
vklachkov Jul 28, 2026
5fccd58
fix hdd image closing prematurely on drag-and-drop
vklachkov Jul 29, 2026
d159d14
rewrite partitions dialog
vklachkov Jul 29, 2026
8375be1
rebuild source code structure
vklachkov Jul 29, 2026
d44eb7e
new image new dialog ui
vklachkov Jul 29, 2026
bcca060
cleanup about dialog
vklachkov Jul 29, 2026
c98cb78
redesign custom disk dialog, add hdd superblock/bitmap values
vklachkov Jul 31, 2026
ecf5ee1
rename ui/icon to ui/resources, store icons as svg
vklachkov Jul 31, 2026
ec0b249
add search ui
vklachkov Jul 31, 2026
cc2aed8
fix warning when extracting partitions with label
vklachkov Jul 31, 2026
8d29094
fix segfault when opening the same mbr disk
vklachkov Jul 31, 2026
f082956
search
vklachkov Jul 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ build/
#CMake stuff
CMakeCache.txt
CMakeFiles

research/
test data/
82 changes: 56 additions & 26 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

add_subdirectory(ccos_image)

project(GRiDISKCOM LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(ccos_image)
project(GRiDISKCOM LANGUAGES CXX C)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
Expand All @@ -23,30 +20,63 @@ if(WIN32)
set(GUI_TYPE WIN32)
endif()

include_directories(${CMAKE_SOURCE_DIR})
include_directories(ccos_image)
include_directories(ui)
include_directories(ui/dialogs)
include_directories(ui/preview)
include_directories(common)


add_executable(GRiDISKCOM ${GUI_TYPE}
main.cpp
dialogs/mainwindow.cpp
dialogs/mainwindow.h
dialogs/mainwindow.ui
dialogs/abdlg.cpp
dialogs/abdlg.h
dialogs/abdlg.ui
dialogs/chsedlg.cpp
dialogs/chsedlg.h
dialogs/chsedlg.ui
dialogs/custdlg.cpp
dialogs/custdlg.h
dialogs/custdlg.ui
dialogs/datedlg.cpp
dialogs/datedlg.h
dialogs/datedlg.ui
dialogs/rendlg.cpp
dialogs/rendlg.h
dialogs/rendlg.ui
dialogs/verdlg.cpp
dialogs/verdlg.h
dialogs/verdlg.ui
icon/icon.qrc
common/imd2raw.c
common/imd2raw.h
common/diskconstants.h
common/mbr.cpp
common/mbr.h
common/omf_record.cpp
common/omf_record.h
ui/mainwindow.cpp
ui/mainwindow.h
ui/mainwindow.ui
ui/filepanelwidget.cpp
ui/filepanelwidget.h
ui/themedicon.h
ui/dialogs/about.cpp
ui/dialogs/about.h
ui/dialogs/about.ui
ui/dialogs/customdisk.cpp
ui/dialogs/customdisk.h
ui/dialogs/customdisk.ui
ui/dialogs/imagewizard.cpp
ui/dialogs/imagewizard.h
ui/dialogs/date.cpp
ui/dialogs/date.h
ui/dialogs/date.ui
ui/dialogs/partition.cpp
ui/dialogs/partition.h
ui/dialogs/partition.ui
ui/dialogs/rename.cpp
ui/dialogs/rename.h
ui/dialogs/rename.ui
ui/dialogs/version.cpp
ui/dialogs/version.h
ui/dialogs/version.ui
ui/preview/file.h
ui/preview/dialog.cpp
ui/preview/dialog.h
ui/preview/text.cpp
ui/preview/text.h
ui/preview/canvas.cpp
ui/preview/canvas.h
ui/preview/font.cpp
ui/preview/font.h
ui/preview/worksheet.cpp
ui/preview/worksheet.h
ui/preview/database.cpp
ui/preview/database.h
ui/resources/icon.qrc
execico.rc
)

Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ git submodule init
git submodule update
```

## Building
Configure and build the project in a `build` directory with CMake:
```
cmake -S . -B build
cmake --build build
```
After building, the resulting `GRiDISKCOM` executable will be located in the `build` directory.

## Special thanks to
* [BOOtak](https://github.com/BOOtak) for first testing, bugfixes and [core library](https://github.com/BOOtak/CCOS-disk-utils) for this application.
* [vklachkov](https://github.com/vklachkov) for the current project maintenance.
Expand Down
18 changes: 18 additions & 0 deletions common/diskconstants.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef DISKCONSTANTS_H
#define DISKCONSTANTS_H

#include <cstdint>

constexpr uint16_t GRID_BUBBLE_SECTOR_SIZE = 256;
constexpr uint16_t GRID_BUBBLE_SUPERBLOCK_FID = 0x3FE;
constexpr uint16_t GRID_BUBBLE_BITMAP_FID = 0x3FD;

constexpr uint16_t GRID_FLOPPY_SECTOR_SIZE = 512;
constexpr uint16_t GRID_FLOPPY_SUPERBLOCK_FID = 0x121;
constexpr uint16_t GRID_FLOPPY_BITMAP_FID = 0x120;

constexpr uint16_t GRID_HDD_SECTOR_SIZE = 512;
constexpr uint16_t GRID_HDD_SUPERBLOCK_FID = 0x2420;
constexpr uint16_t GRID_HDD_BITMAP_FID = 0x2400;

#endif // DISKCONSTANTS_H
253 changes: 253 additions & 0 deletions common/imd2raw.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
/*
* Fixes to sort sector list so that images with skews are correct
* Verified by actually comparing IMDU /B output byte for byte
*
* David Schmidt
* December, 2022
* July, 2026: optional padding of missing sectors
*/

/* originally from the bitsavers/convergent directory
*
* Used stdin/stdout that won't work in Windows. Files
* must be opened explicity in binary mode for both input and output
*
* Testing: Converts *.IMD file identical to IMDU /B as verified
* by both size and an MD5 cryptographic hash.
*
* Tom Burnett
* December, 2013
*/
#include "imd2raw.h"

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>

/*
* IMD image format
*
* IMD v.v: dd/mm/yyy hh:mm:ss (ascii header, optional)
* comment terminated with 0x1a
* for each track
* char mode (0-5)
* char cylinder
* char head (including additional optional bits, below)
* char sector count
* char sector size (0-6)
* sector numbering map
* optional cylinder map (head & 0x40)
* optional head map (head & 0x80)
* sector data records (type) (val, or data)
*/

char *modetbl[] = { "500K FM", "300K FM", "250K FM", "500K MFM", "300K MFM", "250K MFM" };

FILE *fpin, *fpout;
int fill_missing = 0;
unsigned int highwater[7] = {0};

int comp (const void * elem1, const void * elem2)
{
unsigned char f = *((int*)elem1);
unsigned char s = *((int*)elem2);
if (f > s) return 1;
if (f < s) return -1;
return 0;
}

/* Integrated into GRiDISKCOM: this used to be main()/stdin/stdout that
* called exit() on error. It is now imd2raw_convert(infile, outfile) which
* returns a negative code on error, so it is safe to call from the GUI.
* The conversion algorithm below is unchanged. */
int imd2raw_convert(const char *infile, const char *outfile)
{
unsigned char sectormap[32];
unsigned char sectormapsorted[32];
unsigned char secdisp[32];
unsigned char secdata[64][8192];
unsigned int mode, cyl, hd, seccnt, headflags, sizecode;
unsigned int secsiz = 0;
int i, j;
unsigned char c, value, fill;

if ((fpin = fopen(infile, "rb")) == NULL) {
return -1;
}

if ((fpout = fopen(outfile, "wb")) == NULL) {
fclose(fpin);
return -2;
}

/* Turns out this is a "later" construct, earlier examples may just have a 0x1a terminated comment
if( (fgetc(fpin) != 'I') || (fgetc(fpin) != 'M') || (fgetc(fpin) != 'D') ) {
fprintf(stderr,"File doesn't start with 'IMD'\n");
leave(4);
}
*/

// Lop off initial comments
while(1) {
c = fgetc(fpin);
if(c == 0x1a)
break;
}

while(1) {
c = fgetc(fpin);
if(feof(fpin)) break;
mode = c;
if(mode > 6) {
fclose(fpin);
fclose(fpout);
return -4;
}
cyl = fgetc(fpin);
if(cyl > 80) {
fclose(fpin);
fclose(fpout);
return -5;
}
c = fgetc(fpin);
hd = c & 0x0f;
headflags = c & 0xf0;
if(hd > 1) {
fclose(fpin);
fclose(fpout);
return -6;
}
seccnt = fgetc(fpin);

sizecode = fgetc(fpin);
c = sizecode;

switch(c) {
case 0:
secsiz = 128;
break;
case 1:
secsiz = 256;
break;
case 2:
secsiz = 512;
break;
case 3:
secsiz = 1024;
break;
case 4:
secsiz = 2048;
break;
case 5:
secsiz = 4096;
break;
case 6:
secsiz = 8192;
break;
default:
break;
}

if (seccnt > highwater[sizecode])
highwater[sizecode] = seccnt;

// fprintf(stderr,"Cyl:%d Hd:%d %s %d sectors size %d\n", cyl, hd, modetbl[mode], seccnt, secsiz);

// copy sector/interleave map
for (i=0; i < seccnt; i++) {
sectormap[i] = fgetc(fpin);
sectormapsorted[i] = sectormap[i];
}
// Sort the sectors in case of skew
// qsort(sectormapsorted, seccnt, 1, comp);
// fprintf(stderr,"Tbl ");
// for (i=0; i < seccnt; i++) fprintf(stderr,"%d ",sectormap[i]);
// fprintf(stderr, "\n");
// fprintf(stderr,"Srt ");
// for (i=0; i < seccnt; i++) fprintf(stderr,"%d ",sectormapsorted[i]);
// fprintf(stderr, "\n");

if ((headflags & 64) == 64)
{
// Pull out "optional" cylinder map, discard
for (int i = 0; i < seccnt; i++)
c = fgetc(fpin);
}
if ((headflags & 128) == 128)
{
// Pull out "optional" head map, discard
for (int i = 0; i < seccnt; i++)
c = fgetc(fpin);
}

// copy sector information indexed by the sector number
for (i=0; i < seccnt; i++) {
c = fgetc(fpin);

switch(c) {
case 0: // Sector data unavailable - could not be read
case 5: // Deleted address marks
case 7: // Bad sector
secdisp[i] = 'X';
fill = 0xE5;
for(j=0; j < secsiz; j++) {
if (c > 0)
fill = fgetc(fpin); // Grab whatever IMD wrote
secdata[sectormap[i]][j] = fill;
}
// fprintf(stderr,"Cyl %d Hd %d Sec %d bad, type %d\n",cyl,hd,sectormap[i],c);
break;

case 1: // normal data 'secsiz' bytes follow
secdisp[i] = '.';
for(j=0; j < secsiz; j++)
secdata[sectormap[i]][j] = fgetc(fpin);
break;

case 3: // data with 'deleted data' address mark
secdisp[i] = 'd';
for(j=0; j < secsiz; j++)
secdata[sectormap[i]][j] = fgetc(fpin);
break;

case 2: // compressed with value in next byte
case 4:
case 6:
case 8:
secdisp[i] = 'C';
value = fgetc(fpin);
for(j=0; j < secsiz; j++)
secdata[sectormap[i]][j] = value;
// fprintf(stderr,"Cyl %d Hd %d Sec %d all %x\n",cyl,hd,sectormap[i],value);
break;
}
}

if (fill_missing && seccnt < highwater[sizecode]) {
unsigned char present[64] = {0};
for (i = 0; i < seccnt; i++)
present[sectormap[i]] = 1;
for (i = 1; i <= highwater[sizecode]; i++) {
if (!present[i]) {
for (j = 0; j < secsiz; j++)
secdata[i][j] = 0x00;
sectormap[seccnt] = i;
sectormapsorted[seccnt] = i;
secdisp[seccnt] = '0';
seccnt++;
}
}
}
qsort(sectormapsorted, seccnt, 1, comp);

for(i=0; i<seccnt; i++) {
for(j=0; j < secsiz; j++) {
fputc(secdata[sectormapsorted[i]][j], fpout);
}
}
}
fclose(fpin);
fclose(fpout);
return(0);
}
Loading