/* UNPACK.CPP Copyright 1997, Project Pluto */ /* All rights reserved. This source code may be used freely for */ /* non-commercial uses. */ #include #include #include #include #include #include "crunch.h" /* This code provides an _example_ as to how to decompress Guide's GSC */ /* data. It produces files in the original ASCII format used by STScI */ /* on their 2-CD version. It works with all Guide versions, 1.0 */ /* and later. Do note that the index files moved from version to */ /* version, and that Guide checks for all of them as needed! Also */ /* note that, due to an unfortunate oversight, there is no HEADER.GSC */ /* on the 1.0 and 2.0 CDs; you can copy one to your hard drive from a */ /* 3.0 or higher, and UNPACK will use it. */ #ifdef __WATCOMC__ #define BUFF_SIZE 200000U #else #define BUFF_SIZE 10000U #endif int gsc_star_uncrunch( GSC_STAR *star, GSC_HEADER *hdr, unsigned char *buff); static char *zone_names[24] = { "N0000", "N0730", "N1500", "N2230", "N3000", "N3730", "N4500", "N5230", "N6000", "N6730", "N7500", "N8230", "S0000", "S0730", "S1500", "S2230", "S3000", "S3730", "S4500", "S5230", "S6000", "S6730", "S7500", "S8230" }; static int zone_start[25] = { 1, 594, 1178, 1729, 2259, 2781, 3246, 3652, 4014, 4294, 4492, 4615, 4663, 5260, 5838, 6412, 6989, 7523, 8022, 8464, 8840, 9134, 9346, 9490, 9538 }; int gsc_unpack( const int cd_drive_letter, const int tile_no, const int fix_numbers) { int line_no = 0, rval, zone; unsigned pad_lines, i, prev_n = 0, big_oloc = 0, big_osize = 1024; char *buff, *tptr, filename[100], obuff[46], prev_obuff[46]; char *big_obuff = NULL; long bytes_left, loc[2]; FILE *ifile, *ofile, *sample; GSC_HEADER hdr; GSC_STAR star; if( cd_drive_letter != '!') { /* first, get the offset in the file */ /* On the 4.0 CD, the index is gscdata2.idx... */ sprintf( filename, "%c:\\text\\gscdata2.idx", cd_drive_letter); ifile = fopen( filename + 8, "rb"); /* check on local drive... */ if( !ifile) ifile = fopen( filename, "rb"); /* ...then on CD */ /* If we're using the Guide 3.0 CD, the file to check is... */ sprintf( filename, "%c:\\text\\gscdata.idx", cd_drive_letter); if( !ifile) ifile = fopen( filename + 8, "rb"); /* check on local drive... */ if( !ifile) ifile = fopen( filename, "rb"); /* ...then on CD */ /* On the 1.0 and 2.0 CDs, GSCDATA.IDX is in the root dir */ sprintf( filename, "%c:\\gscdata.idx", cd_drive_letter); if( !ifile) ifile = fopen( filename, "rb"); /* check on local drive... */ if( ifile) { fseek( ifile, (long)(tile_no + 731) << 3, SEEK_SET); fread( loc, 2, sizeof( long), ifile); fclose( ifile); } else loc[0] = -1L; /* determine its 7.5 degree zone */ for( zone = 24; zone_start[zone] > tile_no; zone--); sprintf( filename, "%c:\\gsc\\%s.lmp", cd_drive_letter, zone_names[zone]); ifile = fopen( filename, "rb"); if( !ifile) return( -2); /* Worst-case: if no GSCDATA.IDX is found, we */ if( loc[0] == -1L) /* can still get the offset and size data from */ { /* the .LMP itself: */ fseek( ifile, 16L + (long)( tile_no-zone_start[zone]) * 22L,SEEK_SET); fread( loc, 2, sizeof( long), ifile); } fseek( ifile, loc[0], SEEK_SET); } else /* just decompressing a 'plain' .GSE tile */ { sprintf( filename, "%04d.gse", tile_no); ifile = fopen( filename, "rb"); if( !ifile) return( -2); } sprintf( filename, "%04d.gsc", tile_no); ofile = fopen( filename, "wb"); if( !ofile) return( -3); fread( (char *)&hdr, sizeof( GSC_HEADER), 1, ifile); pad_lines = hdr.total_lines - hdr.n_entries - 192; hdr.prev_n = 0; buff = (char *)malloc( BUFF_SIZE); if( !buff) return( -4); while( !big_obuff) { big_osize >>= 1; big_obuff = (char *)calloc( big_osize, 45); } sprintf( filename, "%c:\\compress\\header.gsc", cd_drive_letter); /* Guide 1.0 and 2.0 lack a header.gsc; for these, one must */ /* check the local drive. */ sample = fopen( filename, "rb"); if( !sample) sample = fopen( "header.gsc", "rb"); if( !sample) { free( buff); free( big_obuff); return( -5); } rval = fread( buff, 192, 45, sample); fclose( sample); sprintf( buff + 3225, "%5d", hdr.n_entries); buff[3230] = ' '; sprintf( buff + 3622, "%05d", hdr.area_no); buff[3627] = '\''; sprintf( buff + 3648, "%05d", hdr.area_no); buff[3653] = ' '; fwrite( buff, 192, 45, ofile); tptr = buff; bytes_left = hdr.filesize - (long)sizeof( GSC_HEADER); if( bytes_left > (long)BUFF_SIZE) fread( buff, BUFF_SIZE, 1, ifile); else fread( buff, (unsigned)bytes_left, 1, ifile); memset( &star, 0, sizeof( GSC_STAR)); i = 0; #ifdef CODE_NOT_USED_ANYMORE if( argc > 3) /* show header info */ { printf( "Area %d: %ld bytes compressed\n", hdr.area_no, hdr.filesize); printf( "%d plates in this area\n", hdr.n_plates); printf( "RA: %ld to %ld; dec: %ld to %ld\n", hdr.ra_min, hdr.ra_max, hdr.dec_min, hdr.dec_max); printf( "%u stars; %u entries; %u lines\n", hdr.n_stars, hdr.n_entries, hdr.total_lines); printf( "%lu bytes uncompressed: compression factor %4.2lf:1\n", (long)hdr.total_lines * 45L, (double)hdr.total_lines * 45. / (double)hdr.filesize); } #endif while( bytes_left) { if( tptr > buff + BUFF_SIZE - 50) /* getting close to buffer end */ { unsigned n_valid, readsize; n_valid = BUFF_SIZE - (tptr - buff); readsize = (( (long)(tptr - buff) > bytes_left) ? (unsigned)bytes_left : tptr - buff); printf( "%u bytes left in buffer; %lu to go\n", n_valid, bytes_left); memmove( buff, tptr, n_valid); tptr = buff; fread( buff + n_valid, readsize, 1, ifile); } rval = gsc_star_uncrunch( &star, &hdr, (unsigned char *)tptr); /* n ra.ra dec.dec perr mag. merr ban c pl add*/ sprintf( obuff, "%05u%3ld.%05ld%3ld.%05ld%3u.%1u%2u.%02u%1u.%02u%2u%u%s%c", star.n, star.x / 100000L, star.x % 100000L, star.y / 100000L, labs( star.y) % 100000L, star.posn_err / 10, star.posn_err % 10, star.mag / 100, star.mag % 100, star.mag_err / 100, star.mag_err % 100, star.mag_band, star.obj_type, hdr.plates + star.plate_id_no * 5, star.is_a_dup? 'T' : 'F'); if( star.y < 0L && star.y > -100000L) obuff[15] = '-'; if( hdr.area_no == 593 && star.x == 0L) { /* special fix for area 593 peculiarity */ obuff[5] = '3'; obuff[6] = '6'; } /* Due to a bug, the 10000s place for the */ if( !fix_numbers) /* GSC numbers on the original GSC 1.x CDs is */ obuff[0] = '0'; /* always 0, even on the (rare) occasions */ /* when it should actually be 1. */ if( (long)rval > bytes_left) return( -6); if( !star.mag) /* mag zeroed to indicate 'phantom' star */ obuff[0] = '\0'; if( star.n == prev_n) prev_obuff[44] = 'T'; prev_n = star.n; if( i && *prev_obuff) { memcpy( big_obuff + big_oloc * 45, prev_obuff, 45); big_oloc++; if( big_oloc == big_osize) { fwrite( big_obuff, 45, big_oloc, ofile); big_oloc = 0; } } memcpy( prev_obuff, obuff, 45); line_no++; tptr += rval; bytes_left -= (long)rval; i++; } fwrite( big_obuff, 45, big_oloc, ofile); fwrite( obuff, 45, 1, ofile); free( buff); free( big_obuff); memset( obuff, ' ', 45); while( pad_lines--) fwrite( obuff, 45, 1, ofile); fclose( ifile); fclose( ofile); return( 0); } #ifdef TEST_PROGRAM #include #include #define BUFFSIZE 8192 int make_comparison( int tile_no, int compare_drive) { int zone, n_read1 = 1, n_read2 = 1, compare = 0; char filename[50]; char *buff1 = (char *)malloc( 2 * BUFFSIZE); char *buff2 = buff1 + BUFFSIZE; FILE *ifile1, *ifile2; if( !buff1) return( -4); for( zone = 24; zone_start[zone] > tile_no; zone--); sprintf( filename, "%c:\\gsc\\%s\\%04d.gsc", (char)compare_drive, zone_names[zone], tile_no); ifile1 = fopen( filename, "rb"); if( !ifile1) { printf( "Didn't open %s\n", filename); return( -2); } ifile2 = fopen( filename + 13, "rb"); if( !ifile2) { printf( "Didn't open %s\n", filename + 13); return( -3); } while( n_read1 && n_read2 == n_read1 && !compare) { n_read1 = fread( buff1, 1, BUFFSIZE, ifile1); n_read2 = fread( buff2, 1, BUFFSIZE, ifile2); if( n_read1 && n_read1 == n_read2) compare = memcmp( buff1, buff2, n_read1); } fclose( ifile1); fclose( ifile2); unlink( filename + 13); free( buff1); if( n_read1 != n_read2) compare = -9; return( compare); } void main( int argc, char **argv) { time_t t; int rval, fix_numbers = 0, start, end, n_args, i, compare_drive = 0; if( argc >= 3) n_args = sscanf( argv[2], "%d,%d", &start, &end); if( argc < 3 || n_args < 1) { printf( "UNPACK is a utility for extracting Hubble Guide Star Catalog\n"); printf( "tiles in their original form from the compressed GUIDE data.\n"); printf( "UNPACK needs to know the CD drive letter and the number of the\n"); printf( "zone you want. For example, to get tile 3588 with the GUIDE\n"); printf( "CD in drive e:, type:\n\nUNPACK E 3588\n\n"); printf( "The resulting 3588.GSC file will be created.\n"); exit( 0); } if( argc == 4 && !strcmp( argv[3], "#")) fix_numbers = 1; if( argc == 4 && argv[3][0] == '#') compare_drive = argv[3][1]; if( n_args == 1) /* only one tile to decompress */ end = start; for( i = start; i <= end; i++) { printf( "Decompressing GSC tile %d\n", i); rval = gsc_unpack( argv[1][0], i, fix_numbers); switch( rval) { case -1: printf( "Couldn't open index file\n"); break; case -2: printf( "Couldn't open data file\n"); break; case -3: printf( "Couldn't open output file\n"); break; case -4: printf( "Not enough memory\n"); break; case -5: printf( "Couldn't open HEADER.GSC\n"); break; case -6: printf( "Error in reading compressed data\n"); break; case 0: t = time( NULL); printf( "finished %d at %s\n", i, ctime( &t)); break; default: printf( "Unrecognized error code %d\n", rval); break; } if( compare_drive) { if( rval) getch( ); rval = make_comparison( i, compare_drive); if( rval) { printf( "Comparison: rval %d\n", rval); getch( ); } } } } #endif