From 86014d5c8f8d622481e259c371bdc072edd98f78 Mon Sep 17 00:00:00 2001 From: Mark Sproul Date: Sat, 23 Mar 2024 12:29:33 -0400 Subject: [PATCH] Build 175 added support for reading PDS images --- src_pds/PDS.typedefs.h | 163 +++ src_pds/PDS_ReadNASAfiles.c | 1072 ++++++++++++++++++ src_pds/PDS_ReadNASAfiles.h | 18 + src_pds/PDS_decompress.c | 336 ++++++ src_pds/PDS_decompress.c.maybe | 312 +++++ src_pds/PDS_decompress.h | 26 + src_pds/iso9660.c | 874 ++++++++++++++ src_pds/mac_code.c | 1948 ++++++++++++++++++++++++++++++++ 8 files changed, 4749 insertions(+) create mode 100644 src_pds/PDS.typedefs.h create mode 100644 src_pds/PDS_ReadNASAfiles.c create mode 100644 src_pds/PDS_ReadNASAfiles.h create mode 100644 src_pds/PDS_decompress.c create mode 100644 src_pds/PDS_decompress.c.maybe create mode 100644 src_pds/PDS_decompress.h create mode 100644 src_pds/iso9660.c create mode 100644 src_pds/mac_code.c diff --git a/src_pds/PDS.typedefs.h b/src_pds/PDS.typedefs.h new file mode 100644 index 0000000..b60d365 --- /dev/null +++ b/src_pds/PDS.typedefs.h @@ -0,0 +1,163 @@ +//***************************************************************************** +//#include "PDS.typedefs.h" + +#ifndef _PDS_TYPEDEFS_H_ +#define _PDS_TYPEDEFS_H_ + +#define MaxVolCount 16 + +//*************************************** +//* Volume prefixes for CD-ROM series +//* Voyager = VG_0001 -> VG_0012 +//* Viking = VO_1001 -> VO_1008 +//* Viking = VO_2001 -> VO_2007 +//* Magellan = MG_0001 -> MG_0067 +//* Magellan = MG_2001 -> MG_2015 +//* Magellan = MG_3001 + +//*************************************** +enum +{ + VOYAGER = 1, + VIKING_1, + VIKING_2, +// MAGELLAN, + MAGELLAN_0, + MAGELLAN_1, + MAGELLAN_2, + MAGELLAN_3, + GALILEO, + JEDI +}; + +//************************************************** +//* types of PDS labels +enum +{ + LABEL_UNKNOWN = 0, + VARIABLE_LENGTH, + FIXED_LENGTH, + STREAM + }; + +//************************************************** +typedef struct +{ + bool vOK; + char vName[36]; + int vIndex; + int vRefNum; +} diskNames; + +//************************************************** +typedef struct + { + bool vOnLine; + char vName[8]; + char dirName[10]; +//+ Rect MgRect; + } MagellanRectangles; + +//************************************************** +enum +{ + Browse = 0, + Image +}; + + +//************************************************************ +// PDS file types +enum +{ +//* Non image types + notImage = 0, + PDSLabelText, //* label or text files + +//* Image types + VoyagerBrowse, //* 200 x 200, 3200 byte offset, non compressed + VoyagerFull, //* 800 x 800 compressed, header and image + VikingBrowse, //* 300 x 264, 3300 byte offset, non compressed + VikingFull, //* ? x ? compressed, header and image + MagellanVenusMercator, //* + MagellanBrowse, //* 1024 x 896 non compressed + MagellanFull, //* 1024 x 1024 non compressed + JEDIHaleyComet, //* 256 x 256 may vary + + +//* DataBase types + + Voyager_db_ImageDBase, //* INDEX:IMGINDEX.TAB;1 + Viking_db_ImageDBase, //* INDEX:IMGINDEX.TAB;1 + Magellan_db_MDIR_Geometry, //* GEOM.TAB;1 Geometry file for one MIDR (useless) + Magellan_db_Venus_Features, //* GEO.TAB;1 Venus Features + Magellan_db_CD_Contents, //* CONTENTS.TAB;1 contents of current CD only + Magellan_db_MDIR_Products_list, //* MCUMDIR.TAB;1 cumulative directory + Magellan_db_FrameLatLong_List, //* FRAME.TAB;1 frame lat long + dbase_last + + }; + +#define kHistogramEntries 256 +#define HISTOGRAM_SIZE 511 + +//***************************************************************************** +typedef struct +{ + char headerLine[88]; +} TYPE_HeaderTxt; + +#define kMaxHeaderLineCnt 200 + +//***************************************************************************** +typedef struct +{ + int cdROMtype; + char volumeName[64]; //* Name of CD-Rom + char imageFileName[512]; //* file name if the image is a separate file + int record_Type; //* type of record : Variable, ? + int record_Bytes; //* number of bytes per record (after un-compressing) + int file_records; //* total number of records in file + int label_records; //* number of records in label (header) + char spaceCraft_name[64]; //* name of space craft + //* image information + int scanLines; //* number of scan lines in image + int lineSamples; //* number of samples per line + int imageLocationFlag; //* location of image 0 = means this file, 1 = other file + int imageOffset; //* offset record for image + int histogramOffset; //* offset record for histogram + uint32_t imgHistogram[kHistogramEntries]; + + uint8_t *imageData; + + size_t labelSize; + int lineSuffixBytes; + int linePrefixBytes; + size_t headerBytesRead; + char targetBody[64]; + + //* compression information + bool imageIsCompressed; + int encodeHistOffset; + uint32_t encodingHistogram[HISTOGRAM_SIZE + 100]; + + TYPE_HeaderTxt HeaderData[kMaxHeaderLineCnt]; + int HeaderLineCnt; + +} PDS_header_data; + +//./src_pds/PDS_ReadNASAfiles.c : 770 [PDS_ReadHeaderAndImage] OBJECT = ENCODING_HISTOGRAM +//./src_pds/PDS_ReadNASAfiles.c : 770 [PDS_ReadHeaderAndImage] ITEMS = 511 +//./src_pds/PDS_ReadNASAfiles.c : 770 [PDS_ReadHeaderAndImage] ITEM_TYPE = VAX_INTEGER +//./src_pds/PDS_ReadNASAfiles.c : 770 [PDS_ReadHeaderAndImage] ITEM_BITS = 32 +//./src_pds/PDS_ReadNASAfiles.c : 770 [PDS_ReadHeaderAndImage] END_OBJECT + + +//#ifndef MAIN +// #define EXTERN extern +//#else +// #define EXTERN +//#endif +//EXTERN short PDS_readingFileType; + +#endif // _PDS_TYPEDEFS_H_ diff --git a/src_pds/PDS_ReadNASAfiles.c b/src_pds/PDS_ReadNASAfiles.c new file mode 100644 index 0000000..68d2038 --- /dev/null +++ b/src_pds/PDS_ReadNASAfiles.c @@ -0,0 +1,1072 @@ +//***************************************************************************** +//* File: PDS_ReadNASAfiles.c +//* Voyager Image Decompression Program +//* Adapted by Mark Sproul +//* January 1992 +//* for using in my graphics programs +//* +//* The orginal source code was obtained from the CD-ROMs +//* "NASA Voyagers to the Outer Planets" +//* "USA_NASA_PDS_VG_001" +//* +//* Routine "OpenVoyagerPDSfile" (C) by Mark Sproul, 1992 +//* "OpenVoyagerPDSfile" opens a file and reads it into +//* a Macintosh OffScreen bit map. +//* +//* Routine "OpenPDSdatabaseFile" (C) by Mark Sproul, 1992 +//* "OpenPDSdatabaseFile" opens a database file from the CD-ROM +//* about the PDS data files +//* +//* Many other support routines are also (C) by Mark Sproul, 1992 +//* +//* Some of the other code is from the CD-ROM and is believed to be +//* in the public domain. +//* +//***************************************************************************** +//* Edit history +//***************************************************************************** +//* Jan 26, 1992 Reading of PDS files into Mac program from CD working +//* Mar 14, 1992 Starting on more detailed interpretation of label (header) +//* Mar 16, 1992 Changed number of displayed bytes from 836 to 800 +//* Apr 4, 1992 Working on text window again. +//* Apr 4, 1992 Text from labels and headers reading into text windows nicely +//* Apr 19, 1992 Working on database window etc. +//* Apr 20, 1992 PDS database file working fantastically +//* Apr 21, 1992 Cleaning up and bullet proofing the database window stuff +//* Jun 22, 1992 Received 60 CD-ROMs from NASA +//* Vol 9-12 of Voyager +//* Vol 1-8 of Viking Orbiter of Mars +//* Vol 1-48 of MaMagellan Mission to Venus +//* Jun 22, 1992 Reading Viking Browse files (300 x 264) +//* Jun 22, 1992 Reading Magellan "F" files (uncompressed) +//* Jun 25, 1992 Working real good with Viking and Magellan CD-ROMs +//* Jun 25, 1992 Crash occasionally when reading .TAB files +//* Jun 25, 1992 Working on more .TAB handling (data base stuff) +//* Jul 9, 1992 Feature database working +//* Jul 10, 1992 Multiple databases open at the same time working +//* Jul 11, 1992 Added code to close window routine to dispose of the database ptrs +//* Sep 7, 1992 Started implemented"Open PDS Database" menu, auto dim working +//* Nov 6, 1992 Minor bugs fixed in voyager browse stuff +//* Apr 15, 1993 Received 47 CD-ROMs from NASA +//* Vol 49-67 of MaMagellan Mission to Venus +//* Vol 2001-2013 of MaMagellan Mission to Venus +//* Vol 2001-2013 of Viking Orbiter of Mars +//* Nov 17, 2022 Resurrected PDS file code +//* Nov 17, 2022 Added PDS_ReadImage() +//* Nov 18, 2022 Magellan MG_0xxx (.img) images working +//* Nov 18, 2022 Magellan VO_2xxx (.img) images working +//* Nov 19, 2022 Voyager VG_00xx (.img) images working +//***************************************************************************** + + +#include +#include +#include +#include +#include + +#define _ENABLE_CONSOLE_DEBUG_ +#include "ConsoleDebug.h" + + +#define nil NULL +#include "PDS.typedefs.h" +#include "PDS_decompress.h" + +#include "PDS_ReadNASAfiles.h" + + + +//#include +//#include "PICTprocessor.h" +//#include "PICTprocessor.menus.h" +//#include "PICTprocessor.typedefs.h" +//#include "PICTprocessor.dialogs.h" +//#include "PICTprocessor.globals.h" +//#include "PP.prototypes.h" +//#include "TextWindow.h" +//#include "PDS.prototypes.h" + +int gImagesRead = 0; + +//***************************************************************************** +//* C-language Considerations +//* ------------------------- +//* +//* The C-language versions of the decompression subroutines are more +//* portable than the equivalent FORTRAN versions. These routines have +//* been tested on a VAX 750 running under version 4.6 of VMS, a +//* Micro-VAX running under version 2.2 of ULTRIX, a SUN workstation +//* running under version 4.2 (release 3.4) of UNIX, and an IBM PC +//* running under MSDOS using versions 4.0 and 3.0 of MICROSOFT C. +//* +//* The C-language version of the decompression software resides in the +//* DECOMP.C file. This file contains the decmpinit and decompress +//* routines, and the working routines dcmprs, huff_tree, and sort_freq. +//* Also, there is a main program, located in the DETEST.C file, which +//* tests the performance of the decompression software. If you are +//* adapting the software to your paricular hardware and operating system +//* environment, then this program will be useful for testing the +//* software. +//* +//***************************************************************************** +//***************************************************************************** +//* +//* hist - Buffer to contain 511 elements of the encoding histogram. +//* The encoding histogram is extracted from the image area. +//* nsi - Number of bytes obtained from the read of a compressed +//* line. +//* nso - Number of output samples after decompression. For Voyager +//* images, this value is 836. +//* linei - Buffer containing the input compressed line. +//* lineo - Buffer to contain the restored line after decompression. +//* nl - Number of lines in the image array. For Voyager images, +//* this value is 800. +//* il - Loop counter for processing image lines. +//****************************************************************** +#define VOYAGER_LINES 800 +#define VOYAGER_PIXELS 800 +#define VOYAGER_RECORD_BYTES 836 + +//* PDSLabelTextHeight is for the line of text at the top of the image +#define PDSLabelTextHeight 15 + + + +long gPDS_Info_BytesPerRecord; +short gPDScdROMtype; +short gPDSdBASEtype; +//char gCurrentVolName[64]; //* current Volumne Name +PDS_header_data PDSheader; + +//***************************************************************************** +static int PDS_GetCDROMtype(const char *filePath, char *volumeName) +{ +int cdROMtype; +int volChars; +char *slashPtr; +char myVolName[512]; +char tempString[512]; + + CONSOLE_DEBUG(__FUNCTION__); + CONSOLE_DEBUG_W_STR("filePath=", filePath); + + strcpy(volumeName, ""); + strcpy(myVolName, filePath); + slashPtr = strchr(myVolName, '/'); + cdROMtype = -1; + while (slashPtr != NULL) + { + slashPtr++; + strcpy(tempString, slashPtr); //* strcpy does not like to copy into itself + strcpy(myVolName, tempString); + +// CONSOLE_DEBUG_W_STR("myVolName\t=", myVolName); + volChars = (myVolName[0] << 24); + volChars += (myVolName[1] << 16); + volChars += (myVolName[2] << 8); + volChars += (myVolName[3]); + + if (volChars == 'VG_0') cdROMtype = VOYAGER; + if (volChars == 'VO_1') cdROMtype = VIKING_1; + if (volChars == 'VO_2') cdROMtype = VIKING_2; + if (volChars == 'MG_0') cdROMtype = MAGELLAN_0; + if (volChars == 'MG_1') cdROMtype = MAGELLAN_1; + if (volChars == 'MG_2') cdROMtype = MAGELLAN_2; + if (volChars == 'MG_3') cdROMtype = MAGELLAN_3; + if (volChars == 'GO_0') cdROMtype = GALILEO; + if (volChars == 'JEDI') cdROMtype = JEDI; + + if (cdROMtype > 0) + { + slashPtr = strchr(myVolName, '/'); + if (slashPtr != NULL) + { + *slashPtr = 0; + } + strcpy(volumeName, myVolName); +// CONSOLE_DEBUG_W_STR("volumeName\t=", volumeName); +// CONSOLE_DEBUG_W_NUM("cdROMtype \t=", cdROMtype); + break; + } + slashPtr = strchr(myVolName, '/'); + } + return(cdROMtype); +} + +#if 0 +//***************************************************************************** +static int PDS_GetDBASEtype(const char *filePath, char *volumeName) +{ +int dbaseType; +//int volChars; +char theFileName[32]; +char *slashPtr; +int iii; +int myCDROMtype; + +// CONSOLE_DEBUG(__FUNCTION__); + + dbaseType = 0; + + myCDROMtype = PDS_GetCDROMtype(filePath, volumeName); + CONSOLE_DEBUG_W_STR("volumeName \t=", volumeName); + CONSOLE_DEBUG_W_NUM("myCDROMtype\t=", myCDROMtype); + + + //* check for long path names and pull out the file name only + while ((slashPtr = strchr(theFileName, '/')) != nil) + { + iii = 0; + while ((iii<32) && (slashPtr[iii + 1] != 0x00)) + { + theFileName[iii] = slashPtr[iii + 1]; + iii++; + } + theFileName[iii] = 0; + } + + +// CONSOLE_DEBUG_W_NUM("myCDROMtype\t=", myCDROMtype); + switch (myCDROMtype) + { + case VOYAGER: + dbaseType = Voyager_db_ImageDBase; //* IMGINDEX.TAB;1 + gPDS_Info_BytesPerRecord = 512; + break; + + case VIKING_1: + case VIKING_2: + dbaseType = Viking_db_ImageDBase; //* IMGINDEX.TAB;1 + gPDS_Info_BytesPerRecord = 512; + break; + + case MAGELLAN_0: + case MAGELLAN_1: + case MAGELLAN_2: + case MAGELLAN_3: + if (strncmp(theFileName, "GEOM", 4) ==0) + { + dbaseType = Magellan_db_MDIR_Geometry; + gPDS_Info_BytesPerRecord = 90; + } + else if (strncmp(theFileName, "GEO", 3) ==0) //* note, this is DIFFERENT the "GEOM" + { + dbaseType = Magellan_db_Venus_Features; + gPDS_Info_BytesPerRecord = 284; + } + else if (strncmp(theFileName, "CONTENTS", 8) ==0) + { + dbaseType = Magellan_db_CD_Contents; + gPDS_Info_BytesPerRecord = 80; + } + else if (strncmp(theFileName, "MCUMDIR", 7) ==0) + { + dbaseType = Magellan_db_MDIR_Products_list; + gPDS_Info_BytesPerRecord = 80; + } + else if (strncmp(theFileName, "FRAME", 5) ==0) + { + dbaseType = Magellan_db_FrameLatLong_List; + gPDS_Info_BytesPerRecord = 80; + } + + break; + + default: + gPDS_Info_BytesPerRecord = 512; + break; + } + return(dbaseType); +} +#endif // 0 + +//***************************************************************************** +//* set default values for PDS header info +//***************************************************************************** +static void PDS_InitHeader(PDS_header_data *pdsHeaderPtr) +{ + CONSOLE_DEBUG(__FUNCTION__); + + memset(pdsHeaderPtr, 0, sizeof(PDS_header_data)); + pdsHeaderPtr->record_Type = 0; //* type of record : Variable, Fixed + pdsHeaderPtr->record_Bytes = -1; //* number of bytes per record (after uncompressing) + pdsHeaderPtr->file_records = 0; //* total number of records in file + pdsHeaderPtr->label_records = 0; //* number of records in label (header) + pdsHeaderPtr->spaceCraft_name[0]= 0; //* name of space craft + pdsHeaderPtr->scanLines = -1; //* number of scan lines in image + pdsHeaderPtr->lineSamples = -1; //* number of samples per line + pdsHeaderPtr->histogramOffset = -1; //* offset record for histogram + pdsHeaderPtr->imageLocationFlag = 0; //* location of image 0 = means this file, 1 = other file + pdsHeaderPtr->imageOffset = 0; //* offset record for image + pdsHeaderPtr->imageFileName[0] = 0; //* file name if the image is a seperate file +} + +//***************************************************************************** +static void PDS_DumpHeader(PDS_header_data *pdsHeaderPtr) +{ + CONSOLE_DEBUG("--------------------------------------"); + + CONSOLE_DEBUG_W_NUM( "cdROMtype \t=", pdsHeaderPtr->cdROMtype); + CONSOLE_DEBUG_W_STR( "volumeName \t=", pdsHeaderPtr->volumeName); + CONSOLE_DEBUG_W_STR( "imageFileName \t=", pdsHeaderPtr->imageFileName); + CONSOLE_DEBUG_W_STR( "spaceCraft_name \t=", pdsHeaderPtr->spaceCraft_name); + CONSOLE_DEBUG_W_STR( "targetBody \t=", pdsHeaderPtr->targetBody); + CONSOLE_DEBUG_W_NUM( "record_Type \t=", pdsHeaderPtr->record_Type); + CONSOLE_DEBUG_W_NUM( "record_Bytes \t=", pdsHeaderPtr->record_Bytes); + CONSOLE_DEBUG_W_NUM( "file_records \t=", pdsHeaderPtr->file_records); + CONSOLE_DEBUG_W_NUM( "label_records \t=", pdsHeaderPtr->label_records); + CONSOLE_DEBUG_W_NUM( "scanLines \t=", pdsHeaderPtr->scanLines ); + CONSOLE_DEBUG_W_NUM( "lineSamples \t=", pdsHeaderPtr->lineSamples); + CONSOLE_DEBUG_W_NUM( "imageLocationFlag\t=", pdsHeaderPtr->imageLocationFlag); + CONSOLE_DEBUG_W_LONG( "labelSize \t=", pdsHeaderPtr->labelSize); + CONSOLE_DEBUG_W_NUM( "lineSuffixBytes \t=", pdsHeaderPtr->lineSuffixBytes); + CONSOLE_DEBUG_W_NUM( "histogramOffset \t=", pdsHeaderPtr->histogramOffset); + CONSOLE_DEBUG_W_NUM( "encodeHistOffset \t=", pdsHeaderPtr->encodeHistOffset); + CONSOLE_DEBUG_W_NUM( "imageOffset \t=", pdsHeaderPtr->imageOffset); + CONSOLE_DEBUG_W_BOOL( "imageIsCompressed\t=", pdsHeaderPtr->imageIsCompressed); + CONSOLE_DEBUG_W_NUM( "gImagesRead \t=", gImagesRead); + CONSOLE_DEBUG("--------------------------------------"); +} + +//***************************************************************************** +//* subroutines to Read PDS Labels - read and parse the PDS label +//* returns TRUE for EOF +//***************************************************************************** +static bool PDS_ProcessLabelOneLine(const char *lineBuff, PDS_header_data *pdsHeaderPtr) +{ +bool eofFlag; +int iii; +char *equalsPtr; +char *argPtr; +char argString[80]; +int ccc; +char keyWord[80]; + + + eofFlag = false; + + //---------------------------------------------------------- + //* extract the keyword + iii = 0; + //* fist skip leading spaces + while (lineBuff[iii] == 0x20) + { + iii++; + } + ccc = 0; + while ((lineBuff[iii] > 0x20) && (lineBuff[iii] != '=')) + { + keyWord[ccc++] = lineBuff[iii]; + iii++; + } + keyWord[ccc] = 0; + +// CONSOLE_DEBUG_W_STR("keyWord\t=", keyWord); + + strcpy(argString, ""); + equalsPtr = strchr(lineBuff, '='); + if (equalsPtr != NULL) + { + argPtr = equalsPtr + 1; + while ((*argPtr <= 0x20) && (*argPtr > 0x0)) + { + argPtr++; + } + strcpy(argString, argPtr); + } + + //---------------------------------------------------------- + if (strcmp(keyWord, "RECORD_TYPE") == 0) + { + if (strncmp(argString, "VARIABLE_LENGTH", 15) == 0) + { + pdsHeaderPtr->record_Type = VARIABLE_LENGTH; + } + else + { + pdsHeaderPtr->record_Type = FIXED_LENGTH; + } + } + else if (strcmp(keyWord, "RECORD_BYTES") == 0) + { + pdsHeaderPtr->record_Bytes = atoi(argString); + } + else if (strcmp(keyWord, "FILE_RECORDS") == 0) + { + pdsHeaderPtr->file_records = atoi(argString); + } + else if (strcmp(keyWord, "LABEL_RECORDS") == 0) + { + pdsHeaderPtr->label_records = atoi(argString); + if (pdsHeaderPtr->imageOffset <= 0) + { + pdsHeaderPtr->imageOffset = pdsHeaderPtr->label_records; + } + } + else if (strcmp(keyWord, "SPACECRAFT_NAME") == 0) + { + strcpy(pdsHeaderPtr->spaceCraft_name, argString); + } + else if (strcmp(keyWord, "LINES") == 0) + { + pdsHeaderPtr->scanLines = atoi(argString); + } + else if (strcmp(keyWord, "LINE_SAMPLES") == 0) + { + pdsHeaderPtr->lineSamples = atoi(argString); + } + else if (strcmp(keyWord, "IMAGE_ID") == 0) + { + strcpy(pdsHeaderPtr->imageFileName, argString); + } + else if (strcmp(keyWord, "^IMAGE_HISTOGRAM") == 0) + { + pdsHeaderPtr->histogramOffset = atoi(argString); + } + else if (strcmp(keyWord, "^IMAGE") == 0) + { + if (argString[0] == 0x28) // left parren + { + argPtr = argString; + pdsHeaderPtr->imageLocationFlag = 1; //* location of image, 1 = other file + argPtr++; // skip left parren + if (argPtr[0] == '"') argPtr++; // skip any quotes + iii = 0; + while ((argPtr[0] != '"') && (argPtr[0] != ',')) + { + pdsHeaderPtr->imageFileName[iii++] = argPtr[0]; //* file name if the image is a seperate file + argPtr++; + } + if (argPtr[0] == '"') argPtr++; // skip any quotes + if (argPtr[0] == ',') argPtr++; // skip any commas + } + else + { + pdsHeaderPtr->imageLocationFlag = 0; //* location of image, 1 = other file + } + pdsHeaderPtr->imageOffset = atoi(argString); + } + else if ((strcmp(keyWord, "END")) == 0) + { + eofFlag = true; + } + + else if ((strcmp(keyWord, "LBLSIZE")) == 0) + { + pdsHeaderPtr->labelSize = atoi(argString); + } + //======================================================== + //* these are for MG_0 + else if ((strcmp(keyWord, "LBLSIZE")) == 0) + { + pdsHeaderPtr->labelSize = atoi(argString); + } + else if ((strcmp(keyWord, "NL")) == 0) + { + pdsHeaderPtr->scanLines = atoi(argString); + } + else if ((strcmp(keyWord, "NS")) == 0) + { + pdsHeaderPtr->lineSamples = atoi(argString); + if (pdsHeaderPtr->record_Bytes > pdsHeaderPtr->lineSamples) + { + pdsHeaderPtr->lineSuffixBytes = pdsHeaderPtr->record_Bytes - pdsHeaderPtr->lineSamples; + } + } + else if ((strcmp(keyWord, "RECSIZE")) == 0) + { + pdsHeaderPtr->record_Bytes = atoi(argString); + pdsHeaderPtr->imageOffset = pdsHeaderPtr->labelSize / pdsHeaderPtr->record_Bytes; + + } + //======================================================== + //* these are for voyager + else if ((strcmp(keyWord, "IMAGE_LINES")) == 0) + { + pdsHeaderPtr->scanLines = atoi(argString); + } + else if ((strcmp(keyWord, "LINE_SUFFIX_BYTES")) == 0) + { + pdsHeaderPtr->lineSuffixBytes = atoi(argString); + CONSOLE_DEBUG_W_NUM("imageOffset\t=", pdsHeaderPtr->imageOffset); + } + else if ((strcmp(keyWord, "TARGET_BODY")) == 0) + { + strcpy(pdsHeaderPtr->targetBody, argString); + } + else if ((strcmp(keyWord, "TARGET_NAME")) == 0) + { + strcpy(pdsHeaderPtr->targetBody, argString); + } + else if ((strcmp(keyWord, "^ENCODING_HISTOGRAM")) == 0) + { + pdsHeaderPtr->encodeHistOffset = atoi(argString); + } + else if ((strcmp(keyWord, "OBJECT")) == 0) + { + if (strcmp(argString, "ENCODING_HISTOGRAM") == 0) + { + pdsHeaderPtr->imageIsCompressed = true; + } + } + +//./src_pds/PDS_ReadNASAfiles.c : 770 [PDS_ReadHeaderAndImage] OBJECT = ENCODING_HISTOGRAM + + //======================================================== + //* these are for Galileo + else if ((strcmp(keyWord, "NBB")) == 0) + { + pdsHeaderPtr->linePrefixBytes = atoi(argString); + } + else if ((strcmp(keyWord, "MISSION")) == 0) + { + strcpy(pdsHeaderPtr->spaceCraft_name, argString); + } + else if ((strcmp(keyWord, "TARGET")) == 0) + { + strcpy(pdsHeaderPtr->targetBody, argString); + } + + + + +// //******** This part to be replaced or deleted later +// if ( (strncmp(lineBuff,"SPACECRAFT",10) == 0) +// || (strncmp(lineBuff,"MISSION",7) == 0) +// || (strncmp(lineBuff,"TARGET",6) == 0) +// || (strncmp(lineBuff,"IMAGE_NUMBER",12) == 0)) +// { +// +// strncat(PDSlabelData, lineBuff, length); +// strncat(PDSlabelData, " *\r", 3); +// } + + return(eofFlag); +} + +//********************************************************************* +//* Read variable length records from input file +//********************************************************************* +static int PDS_ReadVariableRecord(FILE *filePointer, uint8_t *dataBuffer, bool verbose) +{ +int dataLength; +int bytesRead; +int charsRead; + + //* variable length record + charsRead = -1; + bytesRead = fread(dataBuffer, 1, 2, filePointer); + if (bytesRead == 2) + { + if (verbose) + { + CONSOLE_DEBUG_W_HEX("dataBuffer[0]\t=", dataBuffer[0]); + CONSOLE_DEBUG_W_HEX("dataBuffer[1]\t=", dataBuffer[1]); + } + dataLength = dataBuffer[1] << 8; + dataLength += dataBuffer[0]; + //* the dataLength has to be an even number + if ((dataLength % 2) == 1) + { + dataLength += 1; + } + if (verbose) + { + CONSOLE_DEBUG_W_NUM("dataLength\t=", dataLength); + } + charsRead = fread(dataBuffer, 1, dataLength, filePointer); + dataBuffer[charsRead] = 0; + } + return(charsRead); +} + +//***************************************************************************** +//* returns the number of chars read, -1 if error +//***************************************************************************** +static int PDS_ReadOneLineFromHeader(FILE *filePointer, const int cdROMtype, char *lineBuff) +{ +int charsRead; +uint8_t dataBuffer[16]; +size_t bytesRead; +int ccc; +int singleQuoteCtr; +bool keepGoing; +char theChar; + +// CONSOLE_DEBUG_W_NUM("cdROMtype\t=", cdROMtype); + + charsRead = -1; + switch(cdROMtype) + { + case VOYAGER: + case VIKING_1: + //* variable length record + charsRead = PDS_ReadVariableRecord(filePointer, (uint8_t *)lineBuff, false); + break; + +// case -1: + case MAGELLAN_0: + case MAGELLAN_1: + case MAGELLAN_2: + case MAGELLAN_3: + case GALILEO: + singleQuoteCtr = 0; + ccc = 0; + keepGoing = true; + charsRead = 0; + while (keepGoing) + { + //* read 1 byte at a time + bytesRead = fread(dataBuffer, 1, 1, filePointer); + charsRead += bytesRead; + theChar = dataBuffer[0]; + if (theChar == '\'') + { + singleQuoteCtr++; + } + if ((theChar == 0x20) && (ccc == 0)) + { + //* do nothing + } + else if ((theChar != 0x20) || ((theChar == 0x20) && ((singleQuoteCtr % 2) == 1))) + { + if (ccc < 80) + { + lineBuff[ccc] = theChar; + lineBuff[ccc + 1] = 0; + ccc++; + } + else + { + CONSOLE_DEBUG("Buffer overflow"); + keepGoing = false; + } + } + else if (theChar == 0x20) + { + keepGoing = false; + } + } + break; + + default: + if (fgets(lineBuff, 100, filePointer)) + { + charsRead = strlen(lineBuff); + } + break; + + } + return(charsRead); +} + +//***************************************************************************** +static bool PDS_ReadUncompressedImage(FILE *filePointer, PDS_header_data *pdsHeaderPtr) +{ +bool returnFlag; +//int histogramBytesRead; +int imageBytesRead; +long currentOffset; +size_t filePositionOffset; +size_t recordsRead; + + CONSOLE_DEBUG(__FUNCTION__); + + filePositionOffset = (pdsHeaderPtr->imageOffset -1) * pdsHeaderPtr->record_Bytes; + if (pdsHeaderPtr->labelSize > filePositionOffset) + { + filePositionOffset = pdsHeaderPtr->labelSize; + } + if (pdsHeaderPtr->linePrefixBytes > 0) + { + filePositionOffset += pdsHeaderPtr->linePrefixBytes; + } + currentOffset = fseek(filePointer, filePositionOffset, SEEK_SET); + currentOffset = ftell(filePointer); + CONSOLE_DEBUG_W_LONG( "currentOffset \t=", currentOffset); + CONSOLE_DEBUG_W_LONG( "filePositionOffset\t=", filePositionOffset); + CONSOLE_DEBUG_W_NUM( "imageOffset \t=", pdsHeaderPtr->imageOffset); + CONSOLE_DEBUG_W_NUM( "record_Bytes \t=", pdsHeaderPtr->record_Bytes); + CONSOLE_DEBUG_W_LONG( "labelSize \t=", pdsHeaderPtr->labelSize); + +// CONSOLE_DEBUG_W_NUM("lineSamples\t=", pdsHeaderPtr->lineSamples); +// CONSOLE_DEBUG_W_NUM("scanLines \t=", pdsHeaderPtr->scanLines); + + if (pdsHeaderPtr->lineSuffixBytes > 0) + { + uint8_t *pixelRowPtr; + int yyy; + uint8_t suffixBuffer[256]; + + //* we have to read the image in one line at a time + imageBytesRead = 0; + pixelRowPtr = pdsHeaderPtr->imageData; + for (yyy=0; yyyscanLines; yyy++) + { + imageBytesRead += fread(pixelRowPtr, 1, pdsHeaderPtr->lineSamples, filePointer); + imageBytesRead += fread(suffixBuffer, 1, pdsHeaderPtr->lineSuffixBytes, filePointer); + + pixelRowPtr += pdsHeaderPtr->lineSamples; + } + } + else + { + recordsRead = fread(pdsHeaderPtr->imageData, pdsHeaderPtr->lineSamples, pdsHeaderPtr->scanLines, filePointer); + imageBytesRead = recordsRead * pdsHeaderPtr->lineSamples; + } +// CONSOLE_DEBUG_W_LONG("filePositionOffset\t=", filePositionOffset); +// CONSOLE_DEBUG_W_LONG("currentOffset \t=", currentOffset); +// CONSOLE_DEBUG_W_LONG("image recordsRead \t=", recordsRead); + + //------------------------------------------------------- + //* lets try adjusting the image + //int pixelCount; + //int pixelValue; + // pixelCount = pdsHeaderPtr->lineSamples * pdsHeaderPtr->scanLines; + // for (iii=0; iiiimageData[iii] & 0x00ff; + // pixelValue = pixelValue + (pixelValue/ 2); + // if (pixelValue > 255) + // { + // pixelValue = 255; + // } + // pdsHeaderPtr->imageData[iii] = pixelValue; + // } + + returnFlag = true; + + return(returnFlag); +} + +//***************************************************************************** +static void StepThroughAllVariableRecords(FILE *filePointer) +{ +int recordCount; +int dataLength; +long currentOffset; +long totalBytesRead; +bool keepGoing; +char dataBuffer[4096]; + + currentOffset = fseek(filePointer, 0, SEEK_SET); + totalBytesRead = 0; + recordCount = 1; + keepGoing = true; + + while (keepGoing && (recordCount < 75)) + { + dataLength = PDS_ReadVariableRecord(filePointer, (uint8_t *)dataBuffer, false); + if (dataLength < 0) + { + keepGoing = false; + } + + if (recordCount < 60) + { + printf("Record #%4d Length=%4d data=%s\r\n", recordCount, dataLength, dataBuffer); + } + else + { + printf("Record #%4d Length=%4d\r\n", recordCount, dataLength); + } + +// CONSOLE_DEBUG_W_NUM("dataLength\t=", dataLength); + + + totalBytesRead += dataLength; + recordCount++; + } + CONSOLE_DEBUG_W_NUM("recordCount\t=", recordCount); + + currentOffset = fseek(filePointer, 0, SEEK_SET); + currentOffset = ftell(filePointer); + CONSOLE_DEBUG_W_LONG("currentOffset\t=", currentOffset); +} + +//***************************************************************************** +static void SetFilePositionVariableRec(FILE *filePointer, int desiredRecordNumber) +{ +int recordCount; +int dataLength; +char dataBuffer[4096]; +long currentOffset; + +// CONSOLE_DEBUG_W_NUM(__FUNCTION__, desiredRecordNumber); + + currentOffset = fseek(filePointer, 0, SEEK_SET); + if (currentOffset != 0) + { + CONSOLE_DEBUG("fseek() failed"); + } + recordCount = 1; + dataLength = 0; + while ((recordCount < desiredRecordNumber) && (dataLength >= 0)) + { + dataLength = PDS_ReadVariableRecord(filePointer, (uint8_t *)dataBuffer, false); + recordCount++; + } +} + +//***************************************************************************** +static bool PDS_ReadCompressedImage(FILE *filePointer, PDS_header_data *pdsHeaderPtr) +{ +bool returnFlag; +int scanLineIdx; +int dataLength; +uint8_t compressedDataBuff[4096]; +char imagebuff[4096]; +int out_bytes; +uint8_t *pdsPixelPtr; +uint8_t *encodingHistPtr; + +// CONSOLE_DEBUG(__FUNCTION__); + +// StepThroughAllVariableRecords(filePointer); + + //----------------------------------------------------------------------------- + //* check for compressed image + if (pdsHeaderPtr->encodeHistOffset > 0) + { + SetFilePositionVariableRec(filePointer, pdsHeaderPtr->encodeHistOffset); + memset(pdsHeaderPtr->encodingHistogram, 0, sizeof(pdsHeaderPtr->encodingHistogram)); + + if (pdsHeaderPtr->record_Bytes == 836) + { + // CONSOLE_DEBUG("Reading compression histogram (836) 3 records"); + encodingHistPtr = pdsHeaderPtr->encodingHistogram; + dataLength = PDS_ReadVariableRecord(filePointer, (encodingHistPtr), false); + dataLength = PDS_ReadVariableRecord(filePointer, (encodingHistPtr + 836), false); + dataLength = PDS_ReadVariableRecord(filePointer, (encodingHistPtr + 1672), false); +// length = read_variableRecord(fRefNum, (char *)hist); +// length = read_variableRecord(fRefNum, (char *)hist+836); +// length = read_variableRecord(fRefNum, (char *)hist+1672); + } + else + { + dataLength = PDS_ReadVariableRecord(filePointer, (char *)pdsHeaderPtr->encodingHistogram, false); + dataLength = PDS_ReadVariableRecord(filePointer, (char *)pdsHeaderPtr->encodingHistogram+1204, false); +// length = read_variableRecord(fRefNum, (char *)hist); +// length = read_variableRecord(fRefNum, (char *)hist+1204); + } + } + else + { + CONSOLE_DEBUG("Did not read image incoding histogram"); + } + + decmpinit(pdsHeaderPtr->encodingHistogram); + + //----------------------------------------------------------------------------- + //* position to start of image + SetFilePositionVariableRec(filePointer, pdsHeaderPtr->imageOffset); + + pdsPixelPtr = pdsHeaderPtr->imageData; //* pointer to the image data + for (scanLineIdx=1; scanLineIdx < pdsHeaderPtr->scanLines; scanLineIdx++) + { + dataLength = PDS_ReadVariableRecord(filePointer, compressedDataBuff, false); + if (dataLength <= 0) + { + break; + } + + out_bytes = VOYAGER_RECORD_BYTES; + out_bytes = pdsHeaderPtr->record_Bytes; + + decompress(compressedDataBuff, imagebuff, &dataLength, &out_bytes); + + //* now copy it over to the PDS image buffer + memcpy(pdsPixelPtr, imagebuff, pdsHeaderPtr->lineSamples); + + pdsPixelPtr += pdsHeaderPtr->lineSamples; + } + DecompressFreeMemory(); + returnFlag = true; + + CONSOLE_DEBUG(__FUNCTION__); + return(returnFlag); +} + +//***************************************************************************** +static bool PDS_ReadHeaderAndImage(const char *filePath, PDS_header_data *pdsHeaderPtr) +{ +bool returnFlag; +FILE *filePointer; +int linesRead; +char lineBuff[512]; +bool keepReading; +bool eofFlag; +int slen; +int totalBytesRead; +int headerBytesRead; +int histogramBytesRead; +int imageBytesRead; +int charsRead; + + CONSOLE_DEBUG_W_STR(__FUNCTION__, filePath); +// CONSOLE_DEBUG_W_NUM("cdROMtype\t=", pdsHeaderPtr->cdROMtype); + returnFlag = false; + filePointer = fopen(filePath, "r"); + if (filePointer != NULL) + { + totalBytesRead = 0; + headerBytesRead = 0; + histogramBytesRead = 0; + imageBytesRead = 0; + linesRead = 0; + keepReading = true; + + //* read the header + while (keepReading && (linesRead < 100)) + { + charsRead = PDS_ReadOneLineFromHeader(filePointer, pdsHeaderPtr->cdROMtype, lineBuff); + if (charsRead >= 0) + { + + pdsHeaderPtr->headerBytesRead += charsRead; + + //* get rid of any CR/LF at the end + slen = strlen(lineBuff); + headerBytesRead += slen; + while ((slen > 0) && (lineBuff[slen - 1] < 0x20)) + { + lineBuff[slen - 1] = 0; + slen = strlen(lineBuff); + } + CONSOLE_DEBUG(lineBuff); + + //* save a copy of the header line + strcpy(pdsHeaderPtr->HeaderData[linesRead].headerLine, lineBuff); + + eofFlag = PDS_ProcessLabelOneLine(lineBuff, pdsHeaderPtr); + if (eofFlag) + { + keepReading = false; + } + + //* now check for other type + if (pdsHeaderPtr->labelSize > 0) + { +// CONSOLE_DEBUG_W_NUM("headerBytesRead\t=", pdsHeaderPtr->headerBytesRead); + if (pdsHeaderPtr->headerBytesRead >= pdsHeaderPtr->labelSize) + { + CONSOLE_DEBUG("Done with header"); + keepReading = false; + } + } + linesRead++; + } + else + { + CONSOLE_DEBUG_W_NUM("End of header, charsRead=", charsRead); + keepReading = false; + } + } + pdsHeaderPtr->HeaderLineCnt = linesRead; + CONSOLE_DEBUG_W_NUM("header lines read\t=", linesRead); + CONSOLE_DEBUG_W_NUM("header bytes read\t=", headerBytesRead); +// //-------------------------------------------------------- +// if (pdsHeaderPtr->histogramOffset > 0) +// { +// int iii; +// //* read the histogram +// filePositionOffset = (pdsHeaderPtr->histogramOffset -1) * pdsHeaderPtr->record_Bytes; +// currentOffset = fseek(filePointer, filePositionOffset, SEEK_SET); +// currentOffset = ftell(filePointer); +// recordsRead = fread(pdsHeaderPtr->histogram, (kHistogramEntries * sizeof(uint32_t)), 1, filePointer); +// histogramBytesRead = recordsRead * (kHistogramEntries * sizeof(uint32_t)); +// +//// for (iii=0; iiihistogram[iii]); +//// } +// } + + + PDS_DumpHeader(pdsHeaderPtr); + + //-------------------------------------------------------- + //* see if we have enough data to describe the image + if ((pdsHeaderPtr->record_Bytes > 0) && + (pdsHeaderPtr->scanLines > 0) && + (pdsHeaderPtr->lineSamples > 0) && + (pdsHeaderPtr->imageOffset > 0)) + + { + pdsHeaderPtr->imageData = calloc(pdsHeaderPtr->scanLines, pdsHeaderPtr->lineSamples); + if (pdsHeaderPtr->imageData != NULL) + { + if (pdsHeaderPtr->imageIsCompressed) + { + returnFlag = PDS_ReadCompressedImage(filePointer, pdsHeaderPtr); + } + else + { + returnFlag = PDS_ReadUncompressedImage(filePointer, pdsHeaderPtr); + } + } + else + { + CONSOLE_DEBUG_W_STR("Not enough info to open image:", filePath); + } + } + fclose(filePointer); +// totalBytesRead = headerBytesRead + histogramBytesRead + imageBytesRead; +// CONSOLE_DEBUG_W_NUM("header bytes read \t=", headerBytesRead); +// CONSOLE_DEBUG_W_NUM("histogram bytes read\t=", histogramBytesRead); +// CONSOLE_DEBUG_W_NUM("image bytes read \t=", imageBytesRead); +// CONSOLE_DEBUG_W_NUM("total bytes read \t=", totalBytesRead); + } + else + { + returnFlag = false; + CONSOLE_DEBUG("Failed to open file"); + } + + gImagesRead++; + return(returnFlag); +} + +//***************************************************************************** +bool PDS_ReadImage(const char *filePath, PDS_header_data *pdsHeaderPtr) +{ +bool returnFlag; +char volumeName[32]; + + PDS_InitHeader(pdsHeaderPtr); + + pdsHeaderPtr->cdROMtype = PDS_GetCDROMtype(filePath, volumeName); +// pdsHeaderPtr->dBaseType = PDS_GetDBASEtype(filePath, volumeName); + strcpy(pdsHeaderPtr->volumeName, volumeName); + + CONSOLE_DEBUG_W_STR("volumeName\t=", volumeName); + CONSOLE_DEBUG_W_NUM("cdROMtype \t=", pdsHeaderPtr->cdROMtype); +// CONSOLE_DEBUG_W_NUM("dBaseType \t=", dBaseType); + + returnFlag = PDS_ReadHeaderAndImage(filePath, pdsHeaderPtr); + + return(returnFlag); +} + +#ifdef _INCLUDE_MAIN_ + +//***************************************************************************** +int main(int argc, char *argv[]) +{ +int iii; +PDS_header_data pdsHeader; + + CONSOLE_DEBUG("NASA CD-ROM read"); + CONSOLE_DEBUG_W_NUM("argc\t=", argc); + + for (iii=1; iii After MANY years (30) working on code again +//* Nov 19, 2022 "long" used to be 32 bits, now its 64, this routine needs 32 bit +//* Nov 19, 2022 Added DecompressFreeMemory() +//******************************************************************** + +#include +#include + +#define _ENABLE_CONSOLE_DEBUG_ +#include "ConsoleDebug.h" + +#include "PDS_decompress.h" + + +//************************************************************************** +//* Declare the tree pointer. This pointer will hold the root of the tree +//* once the tree is created by the accompanying routine huff_tree. +//*************************************************************************** + +NODE *gTree = NULL; + + +//**************************************************************************** +//*_TITLE new_node - allocates a NODE structure and returns a pointer to it +//**************************************************************************** +NODE *new_node(short value) //* I Value to assign to DN field +{ +NODE *temp; //* Pointer to the memory block + + //*************************************************************************** + // Allocate the memory and initialize the fields. + //*************************************************************************** + + temp = (NODE *) malloc(sizeof(NODE)); + + if (temp != NULL) + { + temp->right = NULL; + temp->dn = value; + temp->left = NULL; + } + else + { + printf("\nOut of memory in new_node!\n"); + exit(1); + } + return(temp); +} + +//**************************************************************************** +//*_TITLE sort_freq - sorts frequency and node lists in increasing freq. order* +//*_ARGS TYPE NAME I/O DESCRIPTION +//**************************************************************************** +void sort_freq( LONG *freq_list, //* I Pointer to frequency list + NODE **node_list, //* I Pointer to array of node pointers + LONG num_freq) //* I Number of values in freq list +{ +register LONG *i; //* primary pointer into freq_list +register LONG *j; //* secondary pointer into freq_list +register NODE **k; //* primary pointer to node_list +register NODE **l; //* secondary pointer into node_list +LONG temp1; //* temporary storage for freq_list +NODE *temp2; //* temporary storage for node_list +register LONG cnt; //* count of list elements + + + //************************************************************************ + //* Save the current element - starting with the second - in temporary + //* storage. Compare with all elements in first part of list moving + //* each up one element until the element is larger. Insert current + //* element at this point in list. + //************************************************************************** + + if (num_freq <= 0) return; //* If no elements or invalid, return + + for (i=freq_list, k=node_list, cnt=num_freq ; --cnt ; *j=temp1, *l=temp2) + { + temp1 = *(++i); + temp2 = *(++k); + + for (j = i, l = k ; *(j-1) > temp1 ; ) + { + *j = *(j-1); + *l = *(l-1); + j--; + l--; + if ( j <= freq_list) break; + } + } +} + +//**************************************************************************** +//*_TITLE huff_tree - constructs the Huffman tree; returns pointer to root +//*_ARGS TYPE NAME I/O DESCRIPTION +//**************************************************************************** +NODE *huff_tree(LONG *hist) //* I First difference histogram +{ +LONG freq_list[512]; //* Histogram frequency list +NODE **node_list; //* DN pointer array list +register LONG *fp; //* Frequency list pointer +register NODE **np; //* Node list pointer +register LONG num_freq; //* Number non-zero frequencies in histogram +register short num_nodes; //* Counter for DN initialization +register short cnt; //* Miscellaneous counter +//LONG sum; //* Sum of all frequencies +short znull = -1; //* Null node value +register NODE *temp; //* Temporary node pointer + + +//*************************************************************************** +// Allocate the array of nodes from memory and initialize these with numbers +// corresponding with the frequency list. There are only 511 possible +// permutations of first difference histograms. There are 512 allocated +// here to adhere to the FORTRAN version. +//*************************************************************************** + + fp = freq_list; + node_list = (NODE **) malloc(sizeof(temp) * 512); + if (node_list == NULL) + { + printf("\nOut of memory in huff_tree!\n"); + exit(1); + } + np = node_list; + + for (num_nodes=1, cnt=512 ; cnt-- ; num_nodes++) + { + //************************************************************************** + // The following code has been added to standardize the VAX byte order + // for the "long int" type. This code is intended to make the routine + // as machine independent as possible. + //*************************************************************************** + unsigned char *cp = (unsigned char *) hist++; + unsigned LONG j; + short int i; + for (i=4 ; --i >= 0 ; j = (j << 8) | *(cp+i)); + + //* Now make the assignment + *fp++ = j; + temp = new_node(num_nodes); + *np++ = temp; + } + + (*--fp) = 0; //* Ensure the last element is zeroed out. + + //*************************************************************************** + // Now, sort the frequency list and eliminate all frequencies of zero. + //**************************************************************************** + + num_freq = 512; + sort_freq(freq_list,node_list,num_freq); + + fp = freq_list; + np = node_list; + + for (num_freq=512 ; (*fp) == 0 && (num_freq) ; fp++, np++, num_freq--); + + + //*************************************************************************** + // Now create the tree. Note that if there is only one difference value, + // it is returned as the root. On each iteration, a new node is created + // and the least frequently occurring difference is assigned to the right + // pointer and the next least frequency to the left pointer. The node + // assigned to the left pointer now becomes the combination of the two + // nodes and it's frequency is the sum of the two combining nodes. + //**************************************************************************** + for (temp=(*np) ; (num_freq--) > 1 ; ) + { + temp = new_node(znull); + temp->right = (*np++); + temp->left = (*np); + *np = temp; + *(fp+1) = *(fp+1) + *fp; + *fp++ = 0; + sort_freq(fp,np,num_freq); + } + return(temp); +} + +//*************************************************************************** +//* TITLE decmpinit - initializes the Huffman tree * +//* _ARGS TYPE NAME I/O DESCRIPTION +//*************************************************************************** +void decmpinit(LONG *hist) ///* I First-difference histogram. +{ + //**************************************************************************** + // Simply call the huff_tree routine and return. + //***************************************************************************** + + gTree = huff_tree(hist); +} + + + +//**************************************************************************** +//*_TITLE dcmprs - decompresses Huffman coded compressed image lines +//*_ARGS TYPE NAME I/O DESCRIPTION +//**************************************************************************** +void dcmprs(char *ibuf, //* I Compressed data buffer + char *obuf, //* O Decompressed image line + LONG *nin, //* I Number of bytes on input buffer + LONG *nout, //* I Number of bytes in output buffer + NODE *root) //* I Huffman coded tree +{ +register NODE *ptr = root; //* pointer to position in tree +register unsigned char test; //* test byte for bit set +register unsigned char idn; //* input compressed byte +register char odn; //* last dn value decompressed +char *ilim = ibuf + *nin; //* end of compressed bytes +char *olim = obuf + *nout; //* end of output buffer + + //************************************************************************** + // Check for valid input values for nin, nout and make initial assignments. + //*************************************************************************** + + if (ilim > ibuf && olim > obuf) + { + odn = *obuf++ = *ibuf++; + } + else + { + printf("\nInvalid byte count in dcmprs!\n"); + exit(1); + } + + //************************************************************************** + // Decompress the input buffer. Assign the first byte to the working + // variable, idn. An arithmatic and (&) is performed using the variable + // 'test' that is bit shifted to the right. If the result is 0, then + // go to right else go to left. + //*************************************************************************** + + for (idn=(*ibuf) ; ibuf < ilim ; idn =(*++ibuf)) + { + for (test=0x80 ; test ; test >>= 1) + { + ptr = (test & idn) ? ptr->left : ptr->right; + + if (ptr->dn != -1) + { + if (obuf >= olim) return; + odn -= ptr->dn + 256; + *obuf++ = odn; + ptr = root; + } + } + } +} + +//**************************************************************************** +//*_TITLE decompress - decompresses image lines stored in compressed format +//*_ARGS TYPE NAME I/O DESCRIPTION +//**************************************************************************** +void decompress(char *ibuf, //* I Compressed data buffer + char *obuf, //* O Decompressed image line + LONG *nin, //* I Number of bytes on input buffer + LONG *nout) //* I Number of bytes in output buffer +{ +//************************************************************************* +// This routine is fairly simple as it's only function is to call the +// routine dcmprs. +//************************************************************************** + + dcmprs(ibuf, obuf, nin, nout, gTree); +} + + +int gFreeNodeCounter; +int gFreeNodeDepth; +int gFreeNodeMaxDepth; +//************************************************************************** +static void FreeNode(NODE *nodePtr) +{ + gFreeNodeCounter++; + gFreeNodeDepth++; + if (gFreeNodeDepth > gFreeNodeMaxDepth) + { + gFreeNodeMaxDepth = gFreeNodeDepth; + } + if (nodePtr != NULL) + { + if (nodePtr->left != NULL) + { + FreeNode(nodePtr->left); + free(nodePtr->left); + nodePtr->left = NULL; + } + if (nodePtr->right != NULL) + { + FreeNode(nodePtr->right); + free(nodePtr->right); + nodePtr->right = NULL; + } + } + gFreeNodeDepth--; +} + +//************************************************************************** +//* attempt to free up the memory used for the tree +//************************************************************************** +void DecompressFreeMemory(void) +{ + CONSOLE_DEBUG(__FUNCTION__); + gFreeNodeCounter = 0; + gFreeNodeDepth = 0; + gFreeNodeMaxDepth = 0; + + if (gTree != NULL) + { + FreeNode(gTree); + free(gTree); + gTree = NULL; + } + CONSOLE_DEBUG_W_NUM("gFreeNodeCounter \t=", gFreeNodeCounter); + CONSOLE_DEBUG_W_NUM("gFreeNodeMaxDepth\t=", gFreeNodeMaxDepth); +} diff --git a/src_pds/PDS_decompress.c.maybe b/src_pds/PDS_decompress.c.maybe new file mode 100644 index 0000000..cc9832e --- /dev/null +++ b/src_pds/PDS_decompress.c.maybe @@ -0,0 +1,312 @@ +//******************************************************************** +//* Voyager Image Decompression Program +//* Adapted by Mark Sproul +//* January 1992 +//* for using in my graphics programs +//* +//* This source code was obtained from the CD-ROMs +//* "NASA Voyagers to the Outer Planets" +//* +//******************************************************************** +//******************************************************************** +//* Voyager Image Decompression Program - C Version for PC, VAX, +//* UNIX and Macintosh systems. +//* +//* Decompresses images using Kris Becker's subroutine DECOMP.C +//* which is included in this program in a shortened version. +//* +//******************************************************************** + +#include +#include + + +//******************************************************************** +typedef struct leaf +{ + struct leafg *right; + short int dn; + struct leaf *left; +} NODE; + +//******************************************************************** +// Declare the tree pointer. This pointer will hold the root of the tree +// once the tree is created by the accompanying routine huff_tree. +//******************************************************************** + +NODE *tree; + + +//******************************************************************** +// _TITLE new_node - allocates a NODE structure and returns a pointer to it +// _ARGS TYPE NAME I/O DESCRIPTION +// short int value; I Value to assign to DN field +//******************************************************************** +NODE *new_node(short int value) +{ +NODE *temp; //* Pointer to the memory block +//-char *malloc(); //* Memory allocation function + + //******************************************************************** + // Allocate the memory and intialize the fields. + //******************************************************************** + + temp = (NODE *) malloc(sizeof(NODE)); + + if (temp != NULL) + { + temp->right = NULL; + temp->dn = value; + temp->left = NULL; + } + else + { + printf("\nOut of memory in new_node!\n"); + exit(1); + } + + return temp; +} + +//******************************************************************** +// _TITLE sort_freq - sorts frequency and node lists in increasing freq. order +// _ARGS TYPE NAME I/O DESCRIPTION +//******************************************************************** +void sort_freq( long int *freq_list, //* I Pointer to frequency list + NODE **node_list, //* I Pointer to array of node pointers + long int num_freq) //* I Number of values in freq list +{ + /* Local Variables */ + register long int *i; //* primary pointer into freq_list */ + register long int *j; //* secondary pointer into freq_list */ + + register NODE **k; //* primary pointer to node_list */ + register NODE **l; //* secondary pointer into node_list */ + + long int temp1; //* temporary storage for freq_list */ + NODE *temp2; //* temporary storage for node_list */ + + register long int cnt; //* count of list elements */ + + +/************************************************************************ + Save the current element - starting with the second - in temporary + storage. Compare with all elements in first part of list moving + each up one element until the element is larger. Insert current + element at this point in list. +*************************************************************************/ + + if (num_freq <= 0) return; //* If no elements or invalid, return */ + + for (i=freq_list, k=node_list, cnt=num_freq ; --cnt ; *j=temp1, *l=temp2) + { + temp1 = *(++i); + temp2 = *(++k); + + for (j = i, l = k ; *(j-1) > temp1 ; ) + { + *j = *(j-1); + *l = *(l-1); + j--; + l--; + if ( j <= freq_list) break; + } + + } + return; + } + + +NODE *huff_tree(hist) +/**************************************************************************** +*_TITLE huff_tree - constructs the Huffman tree; returns pointer to root * +*_ARGS TYPE NAME I/O DESCRIPTION */ + long int *hist; /* I First difference histogram */ +{ + //* Local variables used */ + long int freq_list[512]; /* Histogram frequency list */ + NODE **node_list; /* DN pointer array list */ + + register long int *fp; /* Frequency list pointer */ + register NODE **np; /* Node list pointer */ + + register long int num_freq; /* Number non-zero frequencies in histogram */ + long int sum; /* Sum of all frequencies */ + + register short int num_nodes; /* Counter for DN initialization */ + register short int cnt; /* Miscellaneous counter */ + + short int znull = -1; /* Null node value */ + + register NODE *temp; /* Temporary node pointer */ + + /* Functions called */ +//- char *malloc(); + +/*************************************************************************** + Allocate the array of nodes from memory and initialize these with numbers + corresponding with the frequency list. There are only 511 possible + permutations of first difference histograms. There are 512 allocated + here to adhere to the FORTRAN version. +****************************************************************************/ + + fp = freq_list; + node_list = (NODE **) malloc(sizeof(temp)*512); + if (node_list == NULL) + { + printf("\nOut of memory in huff_tree!\n"); + exit(1); + } + np = node_list; + + for (num_nodes=1, cnt=512 ; cnt-- ; num_nodes++) + { +/************************************************************************** + The following code has been added to standardize the VAX byte order + for the "long int" type. This code is intended to make the routine + as machine independant as possible. +***************************************************************************/ + unsigned char *cp = (unsigned char *) hist++; + unsigned long int j; + short int i; + for (i=4 ; --i >= 0 ; j = (j << 8) | *(cp+i)); + +/* Now make the assignment */ + *fp++ = j; + temp = new_node(num_nodes); + *np++ = temp; + } + + (*--fp) = 0; /* Ensure the last element is zeroed out. */ + +/*************************************************************************** + Now, sort the frequency list and eliminate all frequencies of zero. +****************************************************************************/ + + num_freq = 512; + sort_freq(freq_list,node_list,num_freq); + + fp = freq_list; + np = node_list; + + for (num_freq=512 ; (*fp) == 0 && (num_freq) ; fp++, np++, num_freq--); + + +/*************************************************************************** + Now create the tree. Note that if there is only one difference value, + it is returned as the root. On each interation, a new node is created + and the least frequently occurring difference is assigned to the right + pointer and the next least frequency to the left pointer. The node + assigned to the left pointer now becomes the combination of the two + nodes and it's frequency is the sum of the two combining nodes. +****************************************************************************/ + + for (temp=(*np) ; (num_freq--) > 1 ; ) + { + temp = new_node(znull); + temp->right = (*np++); + temp->left = (*np); + *np = temp; + *(fp+1) = *(fp+1) + *fp; + *fp++ = 0; + sort_freq(fp,np,num_freq); + } + + return temp; + } + +void decmpinit(hist) +/*************************************************************************** +*_TITLE decmpinit - initializes the Huffman tree * +*_ARGS TYPE NAME I/O DESCRIPTION */ + long int *hist; /* I First-difference histogram. */ +{ +/**************************************************************************** + Simply call the huff_tree routine and return. +*****************************************************************************/ + + tree = huff_tree(hist); + + return; +} + + +void dcmprs(ibuf,obuf,nin,nout,root) +/**************************************************************************** +*_TITLE dcmprs - decompresses Huffman coded compressed image lines * +*_ARGS TYPE NAME I/O DESCRIPTION */ + char *ibuf; //* I Compressed data buffer */ + char *obuf; //* O Decompressed image line */ + long int *nin; //* I Number of bytes on input buffer */ + long int *nout; //* I Number of bytes in output buffer */ + NODE *root; //* I Huffman coded tree */ + +{ + /* Local Variables */ + register NODE *ptr = root; //* pointer to position in tree */ + register unsigned char test; //* test byte for bit set */ + register unsigned char idn; /* input compressed byte */ + + register char odn; /* last dn value decompressed */ + + char *ilim = ibuf + *nin; //* end of compressed bytes */ + char *olim = obuf + *nout; /* end of output buffer */ + +/************************************************************************** + Check for valid input values for nin, nout and make initial assignments. +***************************************************************************/ + + if (ilim > ibuf && olim > obuf) + { + odn = *obuf++ = *ibuf++; + } + else + { + printf("\nInvalid byte count in dcmprs!\n"); + exit(1); + } + +/************************************************************************** + Decompress the input buffer. Assign the first byte to the working + variable, idn. An arithmatic and (&) is performed using the variable + 'test' that is bit shifted to the right. If the result is 0, then + go to right else go to left. +***************************************************************************/ + + for (idn=(*ibuf) ; ibuf < ilim ; idn =(*++ibuf)) + { + for (test=0x80 ; test ; test >>= 1) + { + ptr = (test & idn) ? ptr->left : ptr->right; + + if (ptr->dn != -1) + { + if (obuf >= olim) return; + odn -= ptr->dn + 256; + *obuf++ = odn; + ptr = root; + } + } + } + return; +} + +void decompress(ibuf,obuf,nin,nout) +/**************************************************************************** +*_TITLE decompress - decompresses image lines stored in compressed format * +*_ARGS TYPE NAME I/O DESCRIPTION */ + char *ibuf; //* I Compressed data buffer */ + char *obuf; //* O Decompressed image line */ + long int *nin; //* I Number of bytes on input buffer */ + long int *nout; //* I Number of bytes in output buffer */ + +{ +/************************************************************************* + This routine is fairly simple as it's only function is to call the + routine dcmprs. +**************************************************************************/ + + dcmprs(ibuf,obuf,nin,nout,tree); + + return; +} diff --git a/src_pds/PDS_decompress.h b/src_pds/PDS_decompress.h new file mode 100644 index 0000000..bcb8db2 --- /dev/null +++ b/src_pds/PDS_decompress.h @@ -0,0 +1,26 @@ +//************************************************************************** +//#include "PDS_decompress.c" + +//* the LONG's defined here must be 32 bit +#define LONG int + +//************************************************************************** +typedef struct leaf +{ +// struct leaf *right; + void *right; + short dn; +// struct leaf *left; + void *left; +} NODE; + + +NODE *new_node(short value); +void sort_freq(LONG *freq_list, NODE **node_list, LONG num_freq); +NODE *huff_tree(LONG *hist); +void decmpinit(LONG *hist); +void dcmprs(char *ibuf, char *obuf, LONG *nin, LONG *nout, NODE *root); +void decompress(char *ibuf, char *obuf, LONG *nin, LONG *nout); + + +void DecompressFreeMemory(void); diff --git a/src_pds/iso9660.c b/src_pds/iso9660.c new file mode 100644 index 0000000..a531eb8 --- /dev/null +++ b/src_pds/iso9660.c @@ -0,0 +1,874 @@ +//***************************************************************************** +//* iso9660.c +// https://en.wikipedia.org/wiki/ISO_9660 +// https://wiki.osdev.org/ISO_9660 +//***************************************************************************** +//* Edit history Mark Sproul, msproul@skychariot.com +//***************************************************************************** +//* Nov 20, 2022 Started on ISO reader to read old style NASA CD-roms +//* Nov 23, 2022 Cleaned up directory reading code, one block at a time +//***************************************************************************** + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _ENABLE_CONSOLE_DEBUG_ +#include "ConsoleDebug.h" + +#pragma pack(1) +//* LSBMSB -> Least Significatn Byte first / Most Significant Byte first +//***************************************************************************** +typedef struct +{ + uint32_t LSB; + uint32_t MSB; +} TYPE_LSBMSB; + +//***************************************************************************** +typedef struct +{ + uint16_t LSB; + uint16_t MSB; +} TYPE_LSBMSB16; + +//***************************************************************************** +typedef struct +{ + char directoryName[64]; +} TYPE_DirectoryPath; + +//***************************************************************************** +typedef struct +{ + uint8_t Length; + uint8_t ExtAttRecordLength; + TYPE_LSBMSB ExtentLocation; + TYPE_LSBMSB DataLength; + char RecordingDate[7]; + uint8_t FileFlags; + uint8_t FileUnitSize; + uint8_t InterleaveGap; + TYPE_LSBMSB16 VolumeSeqNum; + uint8_t FileIdentifierLength; + char FileIndetifier[1]; +} DirectoryRecord; + +//***************************************************************************** +typedef struct +{ + DirectoryRecord DirRecord; + char filename[256]; + void *SubDirectory; +} TYPE__DirectoryEntry; + +//***************************************************************************** +typedef struct +{ + uint8_t VolumeDescriptorType; + char StandardIdentifier[5]; + uint8_t VolumeDescriptorVersion; + char UnusedField1; + char SystemIdentifier[32]; + char VolumeIdentifier[32]; + char UnusedField2[8]; + TYPE_LSBMSB VolumeSpaceSize; + char UnusedField3[32]; + TYPE_LSBMSB16 VolumeSetSize; + TYPE_LSBMSB16 VolumeSequenceNumber; + TYPE_LSBMSB16 LogicalBlockSize; + TYPE_LSBMSB PathTableSize; + uint32_t TypeLPathTable; + uint32_t TypeLPathTable_O; + uint32_t TypeMPathTable; + uint32_t TypeMPathTable_O; + DirectoryRecord DirRecordRootDirectory; + char VolumeSetIdentifier[128]; + char PublisherIdentifier[128]; + char DataPreparerIdentifier[128]; + char ApplicationIdentifier[128]; + char CopyrightFileIdentifier[37]; + char AbstractFileIdentifier[37]; + char BibliographicFileIdentifier[37]; + + + char VolumeCreationDateTime[17]; + char VolumeModificationDateTime[17]; + char VolumeExpirationDateTime[17]; + char VolumeEffectiveDateTime[17]; + uint8_t FileStructureVersion; + uint8_t Unused; + char ApplicationUsed[512]; + char ReservedFutureStandardization[653]; + +// char filler[2048]; +} PrimaryVolumeDescriptor; +#pragma pack(0) + +PrimaryVolumeDescriptor gPVD; + +#define kMaxDirEntries 600 +#define kMaxLevelsDeep 8 +TYPE__DirectoryEntry gRootDirectory[kMaxDirEntries]; +TYPE_DirectoryPath gDirectoryPathTree[kMaxLevelsDeep]; +int gTotalBytesWritten = 0; +bool gCreateFlag = false; +bool gDisplayDirectoryFlag = false; +bool gProcessRecursive = true; +bool gVerboseFlag = false; + + +//***************************************************************************** +void StripTrailingSpaces(char *theString, int maxSLen) +{ +int ccc; + +// CONSOLE_DEBUG_W_NUM("maxSLen\t=", maxSLen); + ccc = maxSLen - 1; + while ((ccc > 0) && (theString[ccc] == 0x20)) + { + theString[ccc] = 0; + ccc--; + } +} + +//***************************************************************************** +static void Swap4Bytes(int *value) +{ +int byte1; +int byte2; +int byte3; +int byte4; +int newValue; + + byte1 = (*value >> 24) & 0x00ff; + byte2 = (*value >> 16) & 0x00ff; + byte3 = (*value >> 8) & 0x00ff; + byte4 = (*value) & 0x00ff; + + newValue = byte4 << 24; + newValue += byte3 << 16; + newValue += byte2 << 8; + newValue += byte1; + + *value = newValue; + +} + + +//***************************************************************************** +void PrintDirectoryRecord(DirectoryRecord *dirRec) +{ +int year; +int month; +int day; +char dateString[32]; +int iii; +char *dataPtr; + + year = 1900 + (dirRec->RecordingDate[0] & 0x00ff); + month = (dirRec->RecordingDate[1] & 0x00ff); + day = (dirRec->RecordingDate[2] & 0x00ff); + sprintf(dateString, "%04d-%02d-%02d", year, month, day); + + + CONSOLE_DEBUG_W_NUM( "Length \t=", dirRec->Length); + CONSOLE_DEBUG_W_NUM( "ExtAttRecordLength \t=", dirRec->ExtAttRecordLength); + CONSOLE_DEBUG_W_NUM( "ExtentLocation \t=", dirRec->ExtentLocation.LSB); + CONSOLE_DEBUG_W_NUM( "DataLength \t=", dirRec->DataLength.LSB); + CONSOLE_DEBUG_W_STR( "RecordingDate \t=", dateString); + CONSOLE_DEBUG_W_HEX( "FileFlags \t=", dirRec->FileFlags); + CONSOLE_DEBUG_W_NUM( "FileUnitSize \t=", dirRec->FileUnitSize); + CONSOLE_DEBUG_W_NUM( "InterleaveGap \t=", dirRec->InterleaveGap); + CONSOLE_DEBUG_W_NUM( "VolumeSeqNum \t=", dirRec->VolumeSeqNum.LSB); + CONSOLE_DEBUG_W_HEX( "VolumeSeqNum \t=", dirRec->VolumeSeqNum.LSB); + CONSOLE_DEBUG_W_NUM( "FileIdentifierLength\t=", dirRec->FileIdentifierLength); + +// dataPtr = (char *)dirRec; +// for (iii=0; iii= 0x7f)) + { + theChar = '.'; + } + printf("%c", theChar); + } + printf("]\r\n"); + iii += 16; + } +} + +//***************************************************************************** +void SeekToBlock(FILE *rawDatafilePointer, int blockNumber) +{ +size_t filePositionOffset; +long currentOffset; +int errCode; + + filePositionOffset = blockNumber * gPVD.LogicalBlockSize.LSB; + + if (gVerboseFlag) + { + CONSOLE_DEBUG_W_NUM("Seeking to block number\t=", blockNumber); + CONSOLE_DEBUG_W_LHEX("New file offset \t=", (unsigned long)filePositionOffset); + } + errCode = fseek(rawDatafilePointer, filePositionOffset, SEEK_SET); + if (errCode == 0) + { + currentOffset = ftell(rawDatafilePointer); + } + else + { + CONSOLE_DEBUG_W_NUM("errno\t=", errno); + } + if (gVerboseFlag) + { + CONSOLE_DEBUG_W_LONG( "filePositionOffset\t\t=", filePositionOffset); + CONSOLE_DEBUG_W_NUM( "LogicalBlockSize \t\t=", gPVD.LogicalBlockSize.LSB); + CONSOLE_DEBUG_W_LONG( "currentOffset \t\t=", currentOffset); + } +} + +int gLevelsdeep = 0; + +//***************************************************************************** +void PrintDirectoryEntry(TYPE__DirectoryEntry *dirEntry) +{ +int year; +int month; +int day; +int hour; +int minute; +int second; +int gmtOffst; +char dateString[32]; +char fileFlagsString[10] = "--------"; +int iii; + + year = 1900 + (dirEntry->DirRecord.RecordingDate[0] & 0x00ff); + month = (dirEntry->DirRecord.RecordingDate[1] & 0x00ff); + day = (dirEntry->DirRecord.RecordingDate[2] & 0x00ff); + hour = (dirEntry->DirRecord.RecordingDate[3] & 0x00ff); + minute = (dirEntry->DirRecord.RecordingDate[4] & 0x00ff); + second = (dirEntry->DirRecord.RecordingDate[5] & 0x00ff); + gmtOffst = (dirEntry->DirRecord.RecordingDate[6] & 0x00ff); + sprintf(dateString, "%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second); + + if (dirEntry->DirRecord.FileFlags & 0x80) + { + fileFlagsString[0] = '+'; + } + if (dirEntry->DirRecord.FileFlags & 0x02) + { + fileFlagsString[6] = 'd'; + } + + for (iii=1; iiiDirRecord.Length & 0x00ff)); + printf("%8d ", dirEntry->DirRecord.DataLength.LSB); + printf("%s ", dateString); + printf("%-20s\t", dirEntry->filename); + printf("->%4d ", dirEntry->DirRecord.ExtentLocation.LSB); + + + + printf("\r\n"); + +} + + +//***************************************************************************** +void DisplayFileStat(const char *pathName) +{ +struct stat sb; + + if (lstat(pathName, &sb) == 0) + { + printf("ID of containing device: [%jx,%jx]\n", + (uintmax_t) major(sb.st_dev), + (uintmax_t) minor(sb.st_dev)); + + printf("File type: "); + + switch (sb.st_mode & S_IFMT) + { + case S_IFBLK: printf("block device\n"); break; + case S_IFCHR: printf("character device\n"); break; + case S_IFDIR: printf("directory\n"); break; + case S_IFIFO: printf("FIFO/pipe\n"); break; + case S_IFLNK: printf("symlink\n"); break; + case S_IFREG: printf("regular file\n"); break; + case S_IFSOCK: printf("socket\n"); break; + default: printf("unknown?\n"); break; + } + + printf("I-node number: %ju\n", (uintmax_t) sb.st_ino); + + printf("Mode: %jo (octal)\n", + (uintmax_t) sb.st_mode); + + printf("Link count: %ju\n", (uintmax_t) sb.st_nlink); + printf("Ownership: UID=%ju GID=%ju\n", + (uintmax_t) sb.st_uid, (uintmax_t) sb.st_gid); + + printf("Preferred I/O block size: %jd bytes\n", + (intmax_t) sb.st_blksize); + printf("File size: %jd bytes\n", + (intmax_t) sb.st_size); + printf("Blocks allocated: %jd\n", + (intmax_t) sb.st_blocks); + + printf("Last status change: %s", ctime(&sb.st_ctime)); + printf("Last file access: %s", ctime(&sb.st_atime)); + printf("Last file modification: %s", ctime(&sb.st_mtime)); + } +} + +//***************************************************************************** +void BuildPath(char *fileSystemPath, const int level) +{ +int iii; + + fileSystemPath[0] = 0; + for (iii=0; iii<=level; iii++) + { + strcat(fileSystemPath, gDirectoryPathTree[iii].directoryName); + strcat(fileSystemPath, "/"); + } +} + +//***************************************************************************** +int CreateDirectory(const int level) +{ +struct stat fileStatus; +char myDirectoryPath[512]; +int iii; +int returnCode; + +// CONSOLE_DEBUG(__FUNCTION__); + BuildPath(myDirectoryPath, level); + + CONSOLE_DEBUG_W_STR("myDirectoryPath\t=", myDirectoryPath); + + returnCode = mkdir(myDirectoryPath, 0744); + if (returnCode != 0) + { + if (errno != EEXIST) + { + CONSOLE_DEBUG_W_NUM("Error creating directory errno\t=", errno); + } + } +// DisplayFileStat(myDirectoryPath); +} + +//***************************************************************************** +//* returns number of bytes copied +//***************************************************************************** +int CreateAndCopyFile(FILE *rawDatafilePointer, TYPE__DirectoryEntry *dirEntry) +{ +char myFilePath[256]; +char dataBuffer[5000]; +int dataBytesRead; +size_t myFileSize; +uint8_t *fileBufferPtr; +FILE *dataFilePointer; +size_t bytesWritten; + +// CONSOLE_DEBUG_W_STR(__FUNCTION__, dirEntry->filename); + bytesWritten = 0; + BuildPath(myFilePath, gLevelsdeep-1); + strcat(myFilePath, dirEntry->filename); + CONSOLE_DEBUG_W_STR("myFilePath\t\t=", myFilePath); + +// CONSOLE_DEBUG_W_NUM("ExtentLocation\t=", dirEntry->DirRecord.ExtentLocation.LSB); +// CONSOLE_DEBUG_W_NUM("DataLength \t=", dirEntry->DirRecord.DataLength.LSB); + + SeekToBlock(rawDatafilePointer, dirEntry->DirRecord.ExtentLocation.LSB + 1); + + myFileSize = dirEntry->DirRecord.DataLength.LSB; + fileBufferPtr = calloc(1, (myFileSize + 100)); + if (fileBufferPtr != NULL) + { + dataBytesRead = fread(fileBufferPtr, 1, myFileSize, rawDatafilePointer); +// CONSOLE_DEBUG_W_NUM("dataBytesRead \t=", dataBytesRead); + if (dataBytesRead == myFileSize) + { + //* write out the file + dataFilePointer = fopen(myFilePath, "w"); + if (dataFilePointer != NULL) + { + bytesWritten = fwrite(fileBufferPtr, 1, myFileSize, dataFilePointer); +// CONSOLE_DEBUG_W_LONG("bytesWritten \t=", bytesWritten); + + fclose(dataFilePointer); + } + } + +// DumpHex(fileBufferPtr, 0x400); + + free(fileBufferPtr); + } + return(bytesWritten); +} + + + +//***************************************************************************** +//* returns number of valid entries +//***************************************************************************** +int BuildDirectory( FILE *rawDatafilePointer, + DirectoryRecord *currentDirectory, + TYPE__DirectoryEntry *dirArray) +{ +DirectoryRecord *dirRecordPtr; +int dirRecordSize; +bool keepGoing; +uint8_t *myDataPtr; +uint8_t *myBlockPtr; +int fileNameLen; +int dirEntryIdx; +TYPE__DirectoryEntry localDirEntry; +size_t bytesUsedInBlock; +size_t bytesLeftInBlock; +int blocksProcessed; +int directoryByteCount; +int blockCount; +int iii; +uint8_t directoryBuffer[2100]; +int blkNum; +int dataBytesRead; + + //* the directory is in 2048 byte blocks. + //* a directory entry cannot span across a block boundry + //* so at the end of each block, we have to skip a few bytes + + //* figure out how many blocks we should be processing + directoryByteCount = currentDirectory->DataLength.LSB; + blockCount = directoryByteCount / 2048; +// CONSOLE_DEBUG_W_NUM("blockCount\t\t\t=", blockCount); + + dirEntryIdx = 0; + blocksProcessed = 0; + for (blkNum=0; blkNumFileFlags & 0x02) == 0) + { + if (localDirEntry.filename[fileNameLen - 2] == ';') + { + localDirEntry.filename[fileNameLen - 2] = 0; + } + } + + // PrintDirectoryEntry(&localDirEntry); + if (dirEntryIdx < kMaxDirEntries) + { + dirArray[dirEntryIdx] = localDirEntry; + dirEntryIdx++; + } + else + { + CONSOLE_DEBUG("OUT OF MEMORY IN DIRECTORY TREE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + CONSOLE_ABORT(__FUNCTION__); + } + + myDataPtr += dirRecordSize; + } + else + { + keepGoing = false; + if (gVerboseFlag) + { + CONSOLE_DEBUG("We are the end of the current block (should be empty)"); + DumpHex(myDataPtr, 48); + } + } + } + blocksProcessed++; + } + if (blocksProcessed < blockCount) + { + CONSOLE_DEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + CONSOLE_DEBUG_W_NUM("entries found \t=", dirEntryIdx); + CONSOLE_DEBUG_W_NUM("directoryByteCount\t=", directoryByteCount); + CONSOLE_DEBUG_W_NUM("blockCount \t=", blockCount); + CONSOLE_DEBUG_W_NUM("blocksProcessed \t=", blocksProcessed); + CONSOLE_ABORT(__FUNCTION__); + } + if (gVerboseFlag) + { + CONSOLE_DEBUG_W_NUM("blocksProcessed\t=", blocksProcessed); + CONSOLE_DEBUG_W_NUM("entries found \t=", dirEntryIdx); + } + return(dirEntryIdx); +} + + +//***************************************************************************** +//* LBA = Logical block addressing +//***************************************************************************** +void ReadDirectoryRecursivly(FILE *rawDatafilePointer, + DirectoryRecord *currentDirectory, + const int directoryLBA, + TYPE__DirectoryEntry *dirArray) +{ +int validEntries; +int dataBytesRead; +int iii; + + gLevelsdeep++; + + if (gVerboseFlag) + { + CONSOLE_DEBUG(__FUNCTION__); + CONSOLE_DEBUG_W_NUM("directoryLBA\t=", directoryLBA); + } + + //* go to the starting block of the directory + SeekToBlock(rawDatafilePointer, directoryLBA); + + + validEntries = BuildDirectory(rawDatafilePointer, currentDirectory, dirArray); + if (gVerboseFlag) + { + CONSOLE_DEBUG_W_NUM("validEntries\t=", validEntries); + } + for (iii=2; iii 0); +} + + + +//***************************************************************************** +void read_PDS_labels(short frefNum, short recordLen) +{ +char ibuf[2048],lineBuf[256]; +short length, labelRecCount, ii, lbfCtr; +char *argptr; +char theChar; +long bytecount; +bool eofFlag; +OSErr iErr; + + PDSlabelData[0] = 255; + PDSlabelData[1] = 0; + + + eofFlag = false; + if (recordLen == 0) + { + while (eofFlag == false) + { + length = read_variableRecord(frefNum, ibuf); + if (length == 0) + { + eofFlag = true; + } + + argptr = strchr(ibuf, '='); // find the '=' + if (argptr != 0) + { + argptr++; // skip the '=' + if (argptr[0] == 0x20) argptr++; // skip any spaces + if (argptr[0] == 0x27) argptr++; // skip any single quote + if (argptr[0] == '"') argptr++; // skip any quotes + + } + eofFlag = parsePDS_Label_Entry(ibuf, argptr); + } + } + else + { + //* we dont know how long the label area is, take a guess and hope it gets fixed + PDSheader.label_records = 10; + + labelRecCount = 0; + while ((labelRecCount < PDSheader.label_records) && (eofFlag == false)) + { + bytecount = recordLen; + iErr = FSRead(frefNum, &bytecount, ibuf); + labelRecCount++; + ibuf[bytecount] = 0; + if (iErr != noErr) + { + eofFlag = true; + } + lbfCtr = 0; + for (ii = 0; ii= 0x20) + { + lineBuf[lbfCtr++] = theChar; + } + else if (theChar == 0x0D) + { + lineBuf[lbfCtr++] = 0; + argptr = strchr(lineBuf, '='); // find the '=' + if (argptr != 0) + { + argptr++; // skip the '=' + if (argptr[0] == 0x20) argptr++; // skip any spaces + if (argptr[0] == 0x27) argptr++; // skip any single quote + if (argptr[0] == '"') argptr++; // skip any quotes + + } + eofFlag = parsePDS_Label_Entry(lineBuf, argptr); + lbfCtr = 0; + } + } + } + } + +} + + +//***************************************************************************** +//* This routine will swap bytes of the histogram integer long words for computer +//* hardware which stores long words in "most significant byte order first" order. +//* This is necessary because the DECOMPRESSION routines will automatically +//* swap the byte order for this computer hardware. +//***************************************************************************** +void swapit(long *longwords) +{ +int cnt; +unsigned char *cp = (unsigned char *) longwords; +unsigned long jjj; +int iii; + + for (cnt=512; cnt--;) + { + for (iii=4; --iii >= 0; jjj = (jjj<<8) | *(cp+iii)); + { + *longwords++ = jjj; + } + } +} + + +//***************************************************************************** +//* figure out what type of label type the file is +//* +//* LABEL_UNKNOWN +//* VARIABLE_LENGTH, +//* FIXED_LENGTH, +//* STREAM +//* +//***************************************************************************** +#define testBuffSize 2048L +short getLabelType(short fRefNum, short *recordSize) +{ +char *bufPtr; +char *recTypeStrPtr; +char *recBytesStrPtr; +char *argptr; +long bytecount; +short returnValue; +short myRecSize; + + //* set the default error conditions + *recordSize = -1; + returnValue = LABEL_UNKNOWN; + + bufPtr = (char *)NewPtr(testBuffSize + 10); + if (bufPtr != nil) + { + bytecount = testBuffSize; + FSRead(fRefNum, &bytecount, bufPtr); + bufPtr[testBuffSize] = 0; + + recTypeStrPtr = strstr(bufPtr, "RECORD_TYPE"); + if (recTypeStrPtr != nil) + { + //* now check for the different types of records + if (strstr(recTypeStrPtr, "VARIABLE_LENGTH") != nil) + { + returnValue = VARIABLE_LENGTH; + *recordSize = 0; + } + else if (strstr(recTypeStrPtr, "FIXED_LENGTH") != nil) + { + returnValue = FIXED_LENGTH; + recBytesStrPtr = strstr(recTypeStrPtr, "RECORD_BYTES"); + if (recBytesStrPtr != nil) + { + argptr = strchr(recBytesStrPtr, '='); // find the '=' + if (argptr != 0) + { + argptr++; // skip the '=' + if (argptr[0] == 0x20) argptr++; // skip any spaces + if (argptr[0] == 0x27) argptr++; // skip any single quote + if (argptr[0] == '"') argptr++; // skip any quotes + sscanf(argptr, "%d", &myRecSize); + + *recordSize = myRecSize; + } + } + } + } + SetFPos(fRefNum, fsFromStart, 0L); + } + DisposePtr(bufPtr); + return(returnValue); +} + +extern char imagebuff[8192]; //* : array[1..8192] of signedbyte; + +//***************************************************************************** +bool OpenPDS_Labeled_Image(Str255 fname, short vnum, short labelType) +{ +GrafPtr tPort; +char ibuf[2048],obuf[2048]; +long nsi,nso,nl,il; +long hist[HISTOGRAM_SIZE+1]; +long hist2[HISTOGRAM_SIZE+1]; +long hist3[HISTOGRAM_SIZE+1]; +long total_bytes, length, long_length; +char linei[836],lineo[836]; +long line; +long out_bytes = VOYAGER_RECORD_BYTES; +short count; +short i, j; +Ptr iptr; +long TempSize; +long bytecount; +OSErr err; +short fRefNum; +Str255 linebuf; +Rect PDStextRect; +short pdsLabelType, pdsRecordSize; + + + ShowWatch(); + err = FSOpen(fname, vnum, &fRefNum); + if ( err != noErr ) + { + SysBeep(1); + return(false); + } + info->vref = vnum; //* save the Volumne Number + SaveInfo = info; + iptr = NewPtr(sizeof(PicInfo)); + if ( iptr == nil ) + { + PutOutOfMemMsg(); + DisposPtr(iptr); + err = FSClose(fRefNum); + return(false); + } + + info = (InfoPtr)iptr; + *info = *SaveInfo; + clrPDSinfoStuf(info); + + + //***************************************************************************** + //***************************************************************************** + //* + //* Read all of the PDS (Planetary Data System) header + //* + //***************************************************************************** + initPDSheader(); + + if (labelType == VARIABLE_LENGTH) + { + pdsLabelType = VARIABLE_LENGTH; + pdsRecordSize = 0; + } + else + { + pdsLabelType = getLabelType(fRefNum, &pdsRecordSize); + } + + read_PDS_labels(fRefNum, pdsRecordSize); + + out_bytes = PDSheader.record_Bytes; + + if (PDSheader.record_Bytes == 836) + { + PDS_readingFileType = VoyagerFull; //* set file type that we are reading + } + else + { + PDS_readingFileType = VikingFull; //* set file type that we are reading + } + + info->LutMode = GrayScale; + info->PixelsPerLine = PDSheader.lineSamples; + info->nlines = PDSheader.scanLines + PDSLabelTextHeight; + info->PicSize = (long)info->nlines * info->PixelsPerLine; + TempSize = info->PicSize; + + info->PicBaseAddr = (Ptr)GetMemory(TempSize, true); + if (info->PicBaseAddr == nil) + { + err = FSClose(fRefNum); + DisposeInfoPtr(); + return(false); + } + + //* set up the color lookup table + info->nColors = 256; + info->ColorStart = 0; + info->ColorWidth = 8; + UpdateColors(); + + + SetDefaultColorTable(); + MakeNewWindow(fname, WPicture); + SelectAll(false); + DoOperation(EraseOp); + info->RoiType = NoRoi; + info->Changes = false; + info->BinaryPic = false; + ResetGrayMap(); + SaveOriginalColorPalette(); + + + setPDSinfoStuf(info, gCurrentVolName, (char *)fname); + PDS_readingFileType = 0; //* reset the flag for the next time + + + //******************************************************************** + //* + //* process the image histogram + //* + //********************************************************************* + + //* need to know record_bytes,hist_count,hist_item_type,item_count. + total_bytes = 0; + length = read_variableRecord(fRefNum, (char *)hist); + total_bytes = total_bytes + length; + + if (PDSheader.record_Bytes == 836) //* read one more time for Voyager image + { + length = read_variableRecord(fRefNum,(char *)hist + PDSheader.record_Bytes); + total_bytes = total_bytes + length; + } + + + //********************************************************************* + //* + //* process the encoding histogram + //* don't have to byte-swap because DECOMP.C does it for us + //* + //********************************************************************* + if (PDSheader.record_Bytes == 836) + { + length = read_variableRecord(fRefNum, (char *)hist); + length = read_variableRecord(fRefNum, (char *)hist+836); + length = read_variableRecord(fRefNum, (char *)hist+1672); + } + else + { + length = read_variableRecord(fRefNum, (char *)hist); + length = read_variableRecord(fRefNum, (char *)hist+1204); + } + + //******************************************************************** + //* + //* process the engineering summary + //* + //******************************************************************** + + total_bytes = 0; + length = read_variableRecord(fRefNum, ibuf); + + //******************************************************************** + //* + //* process the line header table + //* + //******************************************************************** + + if ( (PDSheader.record_Bytes == 1204) + || (PDSheader.record_Bytes == 1224) + || (PDSheader.record_Bytes == 1310) + || (PDSheader.record_Bytes == 1457)) + { + long_length = 0L; + for (i=0;i<1056;i++) + { + length = read_variableRecord(fRefNum, ibuf); + } + } + //******************************************************************** + //* + //* initialize the decompression + //* + //******************************************************************** + + //*DEBUG printf("\nInitializing decompression routine..."); + + decmpinit(hist); + + + strcpy((Ptr)linebuf, (Ptr)"\pReading PDS file: "); + PtoPstrcat(linebuf, fname); + DisplayReadStatus((Ptr)linebuf, PDSlabelData); //* display status dialog box (themometer bar ) + + //******************************************************************** + //* + //* read in decompress, and display the image + //* + //******************************************************************** + + //*DEBUG printf("\nDecompressing data...\n"); + + //********************************************************************* + //* put the name etc as the first line of the image + //********************************************************************* + if (PDSLabelTextHeight != 0) + { + GetPort(&tPort); + SetPort((GrafPtr)info->osPort); + TextSize(9); + TextFont(monaco); + TextMode(srcCopy); + SetBackgroundColor(WhiteIndex); + SetForegroundColor(BlackIndex); + SetRect(&PDStextRect, 0 ,0, info->PixelsPerLine, PDSLabelTextHeight); + FrameRect(&PDStextRect); + MoveTo(5, 12); + for (i=1; i<250; i++) + { + if (PDSlabelData[i] == 0) break; + if (PDSlabelData[i] < 0x20) PDSlabelData[i] = 0x20; + if (PDSlabelData[i] == 0x20) + { + //* remove duplicate spaces + while (PDSlabelData[i+1] == 0x20) + { + for (j=i+1; j<250; j++) + { + PDSlabelData[j] = PDSlabelData[j+1]; + } + } + } + } + PDSlabelData[0] = i; + DrawString((unsigned char *)PDSlabelData); + SetPort(tPort); + } + line = PDSLabelTextHeight; + length = 1; + while ((line < PDSheader.scanLines + PDSLabelTextHeight) && (length > 0) && !CommandPeriod() ) + { + + length = read_variableRecord(fRefNum, ibuf); + if (length <= 0) + { + break; + } + long_length = (long)length; + decompress(ibuf, imagebuff, &long_length, &out_bytes); + + if (PDSheader.record_Bytes == 836) + { + //* invert the pixels for Mac grayscale clut + for (i=0; iPixelsPerLine; i++) + { + imagebuff[i] = 256 - imagebuff[i]; + } + } + stuffPixels(info->osPort, info->PixelsPerLine, info->nlines, line); + + if (((line+1) % 25) == 0) + { + UpdateReadStatus((line * 100L) / info->nlines); + if (line < ScreenHeight) + { + UpdatePicWindow(); + } + } + line += 1; + //*DEBUG if (line % 100 == 0) printf("line %ld\n",line); + } + CloseReadStatus(); + + + //*DEBUG printf("\n"); + err = FSClose(fRefNum); + return(true); +} + + +//***************************************************************************** +bool OpenPDSimage(Str255 fname, short vnum) +{ +GrafPtr tPort; +char ibuf[2048],obuf[2048]; +long nsi,nso,nl,il; +long hist[HISTOGRAM_SIZE+1]; +long hist2[HISTOGRAM_SIZE+1]; +long hist3[HISTOGRAM_SIZE+1]; +long total_bytes, length, long_length; +char linei[836],lineo[836]; +long line; +long out_bytes = VOYAGER_RECORD_BYTES; +short count; +short i, j; +Ptr iptr; +long TempSize; +long bytecount; +OSErr err; +short fRefNum; +Str255 linebuf; +Rect PDStextRect; + + ShowWatch(); + err = FSOpen(fname, vnum, &fRefNum); + if ( err != noErr ) + { + SysBeep(1); + return(false); + } + + initPDSheader(); + //******************************************************************** + //* Read all of the PDS (Planetary Data System) header + //******************************************************************* + read_PDS_labels(fRefNum, 0); + out_bytes = PDSheader.record_Bytes; + + if (PDSheader.record_Bytes == 836) + { + PDS_readingFileType = VoyagerFull; //* set file type that we are reading + } + else + { + PDS_readingFileType = VikingFull; //* set file type that we are reading + } + + //*DEBUG printf("\n"); + err = FSClose(fRefNum); + return(true); +} + + + +//***************************************************************************** +bool OpenPDS_LabelFile(Str255 fname, short vnum, short labelType) +{ +union //* this union is used to swap 16 and 32 bit integers + { + char ichar[4]; + short slen; + long llen; + } onion; +char temp; +OSErr err; +short fRefNum; +char ibuf[3000]; +short length; +short i, crCount; +long j1, j2; +long bytecount, FileLength; +Ptr iptr; +textEditInfoPtr TEDataPtr; +long TempSize; +short fileRecordType; +char *inputBuffP, *inputBuffP2; +short vRefNum; +long freeBytes; +enum +{ + VariableRec = 1, + LinesEndInCR, + FixedLen80 +}; + + ShowWatch(); + PDS_readingFileType = PDSLabelText; //* set file type that we are reading + + err = FSOpen(fname, vnum, &fRefNum); + if ( err != noErr ) + { + return(false); + } + + if (GetEOF(fRefNum,&FileLength) != noErr) + { + FSClose(fRefNum); + return(false); + } + + //* Create a new info record + SaveInfo = info; + iptr = NewPtr(sizeof(PicInfo)); + if ( iptr == nil ) + { + PutOutOfMemMsg(); + DisposPtr(iptr); + err = FSClose(fRefNum); + return(false); + } + + info = (InfoPtr)iptr; + *info = *SaveInfo; + clrPDSinfoStuf(info); + + info->vref = vnum; //* save the Volumne Number + info->LutMode = AppleDefault; + info->PixelsPerLine = 600; + info->nlines = 400; + info->PicSize = (long)info->nlines * info->PixelsPerLine; + TempSize = info->PicSize; + + info->PicBaseAddr = nil; + + //* set up the color lookup table + info->nColors = 256; + info->ColorStart = 0; + info->ColorWidth = 8; + UpdateColors(); + + + SetDefaultColorTable(); + MakeNewWindow(fname, WTextScroll); + + SetPort((GrafPtr)info->osPort); + + TEDataPtr = (textEditInfoPtr)info->textEditRec; + + + err = GetVInfo(vnum, (StringPtr)gCurrentVolName, &vRefNum, &freeBytes); + + setPDSinfoStuf(info, gCurrentVolName, (char *)fname); + + //***************************************************************** + //* now check to see what type of data it is + //***************************************************************** + bytecount = 2; + FSRead(fRefNum, &bytecount, &onion.ichar ); + //* byte swap the length field + temp = onion.ichar[0]; + onion.ichar[0] = onion.ichar[1]; + onion.ichar[1] = temp; + + length = onion.slen; + if (info->fnameExtension == '.FIT') + { + fileRecordType = FixedLen80; + } + else if ((length > FileLength) || (length > 0x2000) || (length == 0x0A0D)) + { + fileRecordType = LinesEndInCR; + } + else + { + fileRecordType = VariableRec; + } + + SetFPos(fRefNum, fsFromStart, 0L); + + switch (fileRecordType) + { + case VariableRec: + //* the file is variable length records, read it that way + { + length = 1; + while (length > 0) + { + length = read_variableRecord(fRefNum, ibuf); + strncat(ibuf, "\r", 1); + bytecount = length +1; + TEStylInsert(ibuf, bytecount, nil, TEDataPtr->TEH); + //* read to the end of the PDS labels +// if (((i = strncmp(ibuf,"END",3)) == 0) && length == 3) + if (((strncmp(ibuf,"END",3)) == 0) && length == 3) + { + break; + } + } + } + break; + case LinesEndInCR: + { + //* the file is NOT variable length recs but lines end in CR/LF + if (FileLength < 30000) + { + bytecount = FileLength; + } + else + { + bytecount = 30000; + } + inputBuffP = NewPtr(bytecount + 10); + FSRead(fRefNum, &bytecount, inputBuffP); + j1 = 0; + crCount = 0; + for (j2 = 0; j2 < bytecount; j2++) + { + if ((inputBuffP[j2] >= 0x20) || (inputBuffP[j2] == 0x0d)) + { + inputBuffP[j1++] = inputBuffP[j2]; + } + if (inputBuffP[j2] == 0x0d) crCount++; + + } + bytecount = j1; + if (crCount == 0) + { + inputBuffP2 = NewPtr(bytecount + (bytecount/80) + 100); + + j1 = 0; + for (j2 = 0; j2 < bytecount; j2++) + { + inputBuffP2[j1++] = inputBuffP[j2]; + if (((j2+1) % 80) == 0) + { + inputBuffP2[j1++] = 0x0d; + } + } + inputBuffP2[j1++] = 0x0d; + TEStylInsert(inputBuffP2, j1, nil, TEDataPtr->TEH); + DisposPtr(inputBuffP2); + } + else + { + TEStylInsert(inputBuffP, j1, nil, TEDataPtr->TEH); + } + DisposPtr(inputBuffP); + } + break; + case FixedLen80: + { + short bytesInLine = 0; + //* the file is NOT variable length recs but lines end in CR/LF + if (FileLength < 30000) + { + bytecount = FileLength; + } + else + { + bytecount = 30000; + } + inputBuffP = NewPtr(bytecount + 10); + FSRead(fRefNum, &bytecount, inputBuffP); + j1 = 0; + crCount = 0; + for (j2 = 0; j2 < bytecount; j2++) + { + if ((inputBuffP[j2] >= 0x20) || (inputBuffP[j2] == 0x0d)) + { + inputBuffP[j1++] = inputBuffP[j2]; + } + if (bytesInLine++ >= 79) + { + inputBuffP[j2] = 0x0d; + bytesInLine = 0; + } + if (inputBuffP[j2] == 0x0d) crCount++; + + } + bytecount = j1; + if (crCount == 0) + { + inputBuffP2 = NewPtr(bytecount + (bytecount/80) + 100); + + j1 = 0; + for (j2 = 0; j2 < bytecount; j2++) + { + inputBuffP2[j1++] = inputBuffP[j2]; + if (((j2+1) % 80) == 0) + { + inputBuffP2[j1++] = 0x0d; + } + } + inputBuffP2[j1++] = 0x0d; + TEStylInsert(inputBuffP2, j1, nil, TEDataPtr->TEH); + DisposPtr(inputBuffP2); + } + else + { + TEStylInsert(inputBuffP, j1, nil, TEDataPtr->TEH); + } + DisposPtr(inputBuffP); + } + break; + } + TextWind_SetVScroll(); + TextWind_AdjustText(); +#ifdef DEBUGGING + printf ("%ld records read\n", i); +#endif + err = FSClose(fRefNum); + + + return(true); +} + +//***************************************************************************** +//* IMGINDEX.TAB;1 +//* The list below presents each field in the image index table, along +//* with a 10 character terse name for each field, the full PDS data +//* dictionary name, the data type which would normally be used for +//* loading the field into a data management system, the field width and +//* the number of decimal places in numeric fields. +//* +//* IMAGE INDEX FLAT TABLE CONTENTS +//* +//* Field Terse Name Full Name Type Start Width Dec +//* ----- ----------- ------------------- ---------- ----- ----- --- +//* 1 SCNAME SPACECRAFT_NAME Character 2 9 +//* 2 MSNPHSNM MISSION_PHASE_NAME Character 14 17 +//* 3 TARGETNAME TARGET_NAME Character 34 8 +//* 4 IMAGEID IMAGE_ID Character 45 10 +//* 5 IMAGENUM IMAGE_NUMBER Numeric 57 8 2 +//* 6 IMAGETIME IMAGE_TIME Character 67 20 +//* 7 EARTHRCDTM EARTH_RECEIVED_TIME Character 90 20 +//* 8 INSTRNAME INSTRUMENT_NAME Character 113 19 +//* 9 SCANMODEID SCAN_MODE_ID Character 135 7 +//* 10 SHUTMODEID SHUTTER_MODE_ID Character 145 7 +//* 11 GAINMODEID GAIN_MODE_ID Character 155 7 +//* 12 EDITMODEID EDIT_MODE_ID Character 165 7 +//* 13 FILTERNAME FILTER_NAME Character 175 7 +//* 14 FILTERNUM FILTER_NUMBER Numeric 184 4 +//* 15 EXPOSUREDU EXPOSURE_DURATION Numeric 189 7 4 +//* 16 NOTE NOTE Character 198 80 +//* 17 SMPLBITMSK SAMPLE_BIT_MASK Character 281 8 +//* 18 DATAANMTYP DATA_ANOMALY_TYPE Character 292 6 +//* 19 IMAGEVOLID IMAGE_VOLUME_ID Character 301 8 +//* 20 IMAGEFILNM IMAGE_FILE_NAME Character 312 31 +//* 21 BROWSVOLID BROWSE_VOLUME_ID Character 346 8 +//* 22 BROWSFILNM BROWSE_FILE_NAME Character 357 38 +//* +//***************************************************************************** + +#define SPACECRAFT_NAME_index 1 +#define MISSION_PHASE_NAME_index 2 +#define TARGET_NAME_index 3 +#define IMAGE_ID_index 4 +#define IMAGE_NUMBER_index 5 +#define IMAGE_TIME_index 6 +#define EARTH_RECEIVED_TIME_index 7 +#define INSTRUMENT_NAME_index 8 +#define SCAN_MODE_ID_index 9 +#define SHUTTER_MODE_ID_index 10 +#define GAIN_MODE_ID_index 11 +#define EDIT_MODE_ID_index 12 +#define FILTER_NAME_index 13 +#define FILTER_NUMBER_index 14 +#define EXPOSURE_DURATION_index 15 +#define NOTE_index 16 +#define SAMPLE_BIT_MASK_index 17 +#define DATA_ANOMALY_TYPE_index 18 +#define IMAGE_VOLUME_ID_index 19 +#define IMAGE_FILE_NAME_index 20 +#define BROWSE_VOLUME_ID_index 21 +#define BROWSE_FILE_NAME_index 22 + + +//***************************************************************************** +typedef struct +{ + bool selected; + char SPACECRAFT_NAME[16 + 2]; + char MISSION_PHASE_NAME[32 + 2]; + char TARGET_NAME[16 + 2]; + //* char IMAGE_ID[10 + 2]; + char IMAGE_NUMBER[8 + 2]; + //* char IMAGE_TIME[20 + 2]; + //* char EARTH_RECEIVED_TIME[20 + 2]; + //* char INSTRUMENT_NAME[19 + 2]; + //* char SCAN_MODE_ID[7 + 2]; + //* char SHUTTER_MODE_ID[7 + 2]; + //* char GAIN_MODE_ID[7 + 2]; + //* char EDIT_MODE_ID[7 + 2]; + //* char FILTER_NAME[7 + 2]; + //* char FILTER_NUMBER[4 + 2]; + //* char EXPOSURE_DURATION[7 + 2]; + char NOTE[160 + 2]; + //* char SAMPLE_BIT_MASK[8 + 2]; + //* char DATA_ANOMALY_TYPE[6 + 2]; + char IMAGE_VOLUME_ID[8 + 2]; + char IMAGE_FILE_NAME[31 + 2]; + char BROWSE_VOLUME_ID[8 + 2]; + char BROWSE_FILE_NAME[38 + 2]; + bool ImgVolumePresentFlag; + bool BrsVolumePresentFlag; + + short minLon; + short maxLon; + short minLat; + short maxLat; +} PDS_db_rec; + +typedef PDS_db_rec *PDS_db_recPtr; +long PDS_record_count; +InfoPtr infoPtrUsedForPDSdbase; +InfoPtr BrowseInfoPtr; + + +//***************************************************************************** +void getIndexedText(short index, char data[], char *saveIt) +{ +short i, commaCount, quoteCount, adjustedIndex, offset; + + adjustedIndex = index -1; + commaCount = 0; + quoteCount = 0; + i = 0; + + //* VG_0004 record # 1699 in the data base file has an error + //* nothing I can do about it + if (adjustedIndex > 0) + { + while ((i < 512) && (commaCount < adjustedIndex)) + { + + if (data[i] == '"') quoteCount++; + if ((data[i++] == ',') && ((quoteCount % 2) == 0)) + { + commaCount++; + } + } + } + + //* does the data start with '"'? + if (data[i] == '"') + { + i += 1; + while ((data[i] != '"') && (data[i] != 0x0D) && (data[i] != 0x00)) + { + *saveIt++ = data[i++]; + } + } + else //* doesnt start with '"', so allow termination with ',' + { + while ((data[i] != '"') && (data[i] != ',') && (data[i] != 0x0D) && (data[i] != 0x00)) + { + *saveIt++ = data[i++]; + } + } + *saveIt++ = 0; + //* get rid of trailing spaces + while ((*saveIt == 0x00) || (*saveIt == 0x20)) + { + *saveIt = 0; + *saveIt--; + } +} + +//***************************************************************************** +int getIndexedInt(index, data) +short index; +char data[]; +{ +char theNumString[32]; +short returnValue; + + returnValue = 0; + getIndexedText(index, data, theNumString); + sscanf(theNumString, "%d", &returnValue); + return(returnValue); +} + + +//***************************************************************************** +OSErr GetVolInfo(short VolRefNum, int Index, char *VolName, HParamBlockRec *myHParam) +{ + //* Get volume name and information block + + myHParam->volumeParam.ioCompletion = NULL; + myHParam->volumeParam.ioNamePtr = (unsigned char *)VolName; + myHParam->volumeParam.ioVRefNum = VolRefNum; + myHParam->volumeParam.ioVolIndex = Index; + return(PBHGetVInfo(myHParam,false)); +} + +//***************************************************************************** +short getMountedVolumeList(diskNames *volumes) +{ +short i; +short volumeCount; +char VolName[80]; +HParamBlockRec myHParam; + + //* clear out the volume array + for (i = 0; i < MaxVolCount; i++) + { + volumes[i].vOK = false; + volumes[i].vIndex = 0; + volumes[i].vName[0] = 0; + } + + VolName[0] = 0x00; + volumeCount = 0; + + //* get the list of all mounted volumes + for (i = 1;i < MaxVolCount; i++) + { + if (GetVolInfo(0, i, VolName, &myHParam) == noErr) + { + volumes[volumeCount].vOK = true; + volumes[volumeCount].vIndex = i; + PtoCstrcpy(volumes[volumeCount].vName, VolName); + volumeCount++; + } + } + return(volumeCount); +} + +//***************************************************************************** +* check mounted volumes and redo volume mounted flags in data base +//***************************************************************************** +void PDS_checkMountedVolumes(void) +{ +PDS_db_recPtr PDSrecordPtr; +long numberOfRecords, i, j; +textEditInfoPtr TEDataPtr; +InfoPtr SaveInfo; +short volumeCount; +diskNames volumes[MaxVolCount]; + +PDS_db_recPtr PDS_image_listPtr; + + PDS_image_listPtr = (PDS_db_recPtr)info->PDS_dbasePtr; + + //* check to make sure we have a data base file open + if ((infoPtrUsedForPDSdbase == nil) || (infoPtrUsedForPDSdbase->PictureType != DataBaseRecordType)) + { + return; + } + SaveInfo = info; + info = infoPtrUsedForPDSdbase; + + TEDataPtr = (textEditInfoPtr)info->textEditRec; + numberOfRecords = TEDataPtr->linesInFile; //* get the number of lines read + + ShowWatch(); + volumeCount = getMountedVolumeList(volumes); + + for (i=0; iImgVolumePresentFlag = false; + PDSrecordPtr->BrsVolumePresentFlag = false; + for (j=0; j < volumeCount; j++) + { + if (strncmp(volumes[j].vName, PDSrecordPtr->IMAGE_VOLUME_ID,7) == 0) + { + PDSrecordPtr->ImgVolumePresentFlag = true; + } + if (strncmp(volumes[j].vName, PDSrecordPtr->BROWSE_VOLUME_ID,7) == 0) + { + PDSrecordPtr->BrsVolumePresentFlag = true; + } + } + } + dBaseWind_UpdateWindow(info->wptr); + info = SaveInfo; +} + +//***************************************************************************** +bool CheckForVolume(void * checkVolname) +{ +long i; +HParamBlockRec myHParam; +char VolName[80]; +bool returnFlag; +short vnmLen; + + returnFlag = false; + + //* check all of the mounted volumes + for (i = 1;i < MaxVolCount; i++) + { + if (GetVolInfo(0, i, VolName, &myHParam) == noErr) + { + PtoCstr((unsigned char *)VolName); + vnmLen = strlen(VolName); + if (strncmp(VolName, checkVolname, vnmLen) == 0) + { + returnFlag = true; + break; + } + } + } + return(returnFlag); +} + + +//***************************************************************************** +void PDS_closeDataBase(void) +{ + + DisposPtr(info->PDS_dbasePtr); + info->PDS_dbasePtr = nil; + infoPtrUsedForPDSdbase = nil; +} + + + +//***************************************************************************** +bool OpenPDSdatabaseFile(Str255 fname, short vnum) +{ +OSErr err; +short fRefNum; +char ibuf[525]; +long length; +long bytecount, FileLength; +long numberOfRecords, i, j; +PDS_db_recPtr PDSrecordPtr; +long TempSize; +Ptr iptr; +textEditInfoPtr TEDataPtr; +StScrpHandle hStScrap; +Str255 linebuf; +long lineCtr = 0; +char tempStr[100]; +short vRefNum; +long freeBytes; +PDS_db_recPtr PDS_image_listPtr; + + ShowWatch(); + + if (vnum == 0) //* if vnum is 0, then this is not the 'connected' drive + { + for (i=1; ((i<10) && (fname[i] != ':')); i++) + { + gCurrentVolName[i] = fname[i]; + } + gCurrentVolName[0] = i-1; + } + else + { + err = GetVInfo(vnum, (StringPtr)gCurrentVolName, &vRefNum, &freeBytes); + } + PDSdBASEtype = getPDSdBASEtype(gCurrentVolName, (char *)fname); + + if (PDSdBASEtype == 0) //* we have a problem, we dont know what type it is + { + //* try to figure it out by reading the first few bytes of the file + //* the offsets into the first line are hard coded and were obtained + //* by looking at the file manually + err = FSOpen(fname, vnum, &fRefNum); + bytecount = 50; + err = FSRead(fRefNum, &bytecount, ibuf ); + if (strncmp(&ibuf[1], "VOYAGER", 7) == 0) PDSdBASEtype = Voyager_db_ImageDBase; + else if (strncmp(&ibuf[21], "VIKING", 6) == 0) PDSdBASEtype = Viking_db_ImageDBase; + + FSClose(fRefNum); + } + + if (PDSdBASEtype == 0) + { + SysBeep(1); + return; + } + + //* if it is the Magellan MDIR Geometry table (GEOM), read it as text file + if (PDSdBASEtype == Magellan_db_MDIR_Geometry) + { + OpenPDS_LabelFile(fname, vnum, VARIABLE_LENGTH); + return; + } + + + err = FSOpen(fname, vnum, &fRefNum); + if ( err != noErr ) + { + return(false); + } + + if (GetEOF(fRefNum,&FileLength) != noErr) + { + FSClose(fRefNum); + return(false); + } + numberOfRecords = FileLength / PDS_Info_BytesPerRecord; + PDS_image_listPtr = (PDS_db_recPtr)NewPtr((numberOfRecords + 1) * sizeof(PDS_db_rec)); + PDS_record_count = numberOfRecords; + if (PDS_image_listPtr == nil) + { + PutOutOfMemMsg(); + FSClose(fRefNum); + return(false); + } + + + //* Create a new info record + SaveInfo = info; + iptr = NewPtr(sizeof(PicInfo)); + if ( iptr == nil ) + { + PutOutOfMemMsg(); + DisposPtr(iptr); + err = FSClose(fRefNum); + return(false); + } + + info = (InfoPtr)iptr; + *info = *SaveInfo; + + PDS_readingFileType = PDSdBASEtype; + setPDSinfoStuf(info, gCurrentVolName, (char *)fname); + PDS_readingFileType = 0; //* reset the flag for the next time + + infoPtrUsedForPDSdbase = info; //* save which 'info' we are using + + info->PDS_dbaseType = PDSdBASEtype; + info->PDS_dbasePtr = (Ptr)PDS_image_listPtr; + info->PDS_dbaseRecCnt = PDS_record_count; + + info->vref = vnum; //* save the Volumne Number + info->PictureType = DataBaseRecordType; //* DataBase Records + info->LutMode = GrayScale; + info->PixelsPerLine = ScreenWidth - 10; + info->nlines = ScreenHeight - PicTopBase; + info->PicSize = (long)info->nlines * info->PixelsPerLine; + TempSize = info->PicSize; + + info->PicBaseAddr = nil; + + //* set up the color lookup table + info->nColors = 256; + info->ColorStart = 0; + info->ColorWidth = 8; + UpdateColors(); + + + SetDefaultColorTable(); + MakeNewWindow(fname, WDataBase); + ResetGrayMap(); + SaveOriginalColorPalette(); + + SetPort((GrafPtr)info->osPort); + + TEDataPtr = (textEditInfoPtr)info->textEditRec; + + strcpy((Ptr)linebuf, (Ptr)"\pReading PDS database file: "); + PtoPstrcat(linebuf, fname); + + sprintf (tempStr, "Reading %ld database records", numberOfRecords); + CtoPstr(tempStr); + DisplayReadStatus((Ptr)linebuf, (Ptr)tempStr); //* display status dialog box (themometer bar ) + + for (i =0; ((iSPACECRAFT_NAME); + getIndexedText(MISSION_PHASE_NAME_index, ibuf, PDSrecordPtr->MISSION_PHASE_NAME); + getIndexedText(TARGET_NAME_index, ibuf, PDSrecordPtr->TARGET_NAME); + getIndexedText(IMAGE_NUMBER_index, ibuf, PDSrecordPtr->IMAGE_NUMBER); + getIndexedText(NOTE_index, ibuf, PDSrecordPtr->NOTE); + getIndexedText(IMAGE_VOLUME_ID_index, ibuf, PDSrecordPtr->IMAGE_VOLUME_ID); + getIndexedText(IMAGE_FILE_NAME_index, ibuf, PDSrecordPtr->IMAGE_FILE_NAME); + getIndexedText(BROWSE_VOLUME_ID_index, ibuf, PDSrecordPtr->BROWSE_VOLUME_ID); + getIndexedText(BROWSE_FILE_NAME_index, ibuf, PDSrecordPtr->BROWSE_FILE_NAME); + break; + + case Viking_db_ImageDBase: + getIndexedText(3, ibuf, PDSrecordPtr->SPACECRAFT_NAME); + getIndexedText(4, ibuf, PDSrecordPtr->MISSION_PHASE_NAME); + getIndexedText(5, ibuf, PDSrecordPtr->TARGET_NAME); + getIndexedText(2, ibuf, PDSrecordPtr->IMAGE_NUMBER); + getIndexedText(15, ibuf, PDSrecordPtr->NOTE); + getIndexedText(16, ibuf, PDSrecordPtr->IMAGE_VOLUME_ID); + getIndexedText(17, ibuf, PDSrecordPtr->IMAGE_FILE_NAME); + getIndexedText(18, ibuf, PDSrecordPtr->BROWSE_VOLUME_ID); + getIndexedText(19, ibuf, PDSrecordPtr->BROWSE_FILE_NAME); + break; + + case Magellan_db_Venus_Features: //* GEO.TAB + getIndexedText(5, ibuf, PDSrecordPtr->TARGET_NAME); + getIndexedText(6, ibuf, PDSrecordPtr->NOTE); + PDSrecordPtr->minLat = getIndexedInt(1, ibuf); + PDSrecordPtr->maxLat = getIndexedInt(2, ibuf); + PDSrecordPtr->minLon = getIndexedInt(3, ibuf); + PDSrecordPtr->maxLon = getIndexedInt(4, ibuf); + break; + + case Magellan_db_CD_Contents: //* CONTENTS.TAB + + break; + + case Magellan_db_MDIR_Products_list: //* MCUMDIR.TAB + getIndexedText(3, ibuf, PDSrecordPtr->TARGET_NAME); + getIndexedText(1, ibuf, PDSrecordPtr->IMAGE_VOLUME_ID); + getIndexedText(2, ibuf, PDSrecordPtr->IMAGE_FILE_NAME); + break; + + case Magellan_db_FrameLatLong_List: //* FRAME.TAB + getIndexedText(7, ibuf, PDSrecordPtr->TARGET_NAME); + getIndexedText(5, ibuf, PDSrecordPtr->IMAGE_VOLUME_ID); + getIndexedText(6, ibuf, PDSrecordPtr->IMAGE_FILE_NAME); + strncpy(PDSrecordPtr->NOTE, ibuf, 35); //* get the lat/long values + break; + + } + } + CloseReadStatus(); + + TEDataPtr->linesInFile = i; //* save the number of lines read + PDS_dbaseNoSelection(); //* make sure none of them are selected + dBaseWind_SetVScroll(); + dBaseWind_SetView(info->wptr, false); + err = FSClose(fRefNum); + PDS_checkMountedVolumes(); + + return(true); +} + + +//***************************************************************************** +void PDS_dbaseNoSelection() +{ +PDS_db_recPtr PDSrecordPtr; +textEditInfoPtr TEDataPtr; +short i; +PDS_db_recPtr PDS_image_listPtr; + + PDS_image_listPtr = (PDS_db_recPtr)info->PDS_dbasePtr; + TEDataPtr = (textEditInfoPtr)info->textEditRec; + + for (i=0; i< TEDataPtr->linesInFile; i++) + { + //* get ptr to current record + PDSrecordPtr = &PDS_image_listPtr[i]; + + PDSrecordPtr->selected = false; + } +} + +//***************************************************************************** +void setPDS_dbaseEntrySelected(long lineIndex, bool selectedValue) +{ +PDS_db_recPtr PDSrecordPtr; +long mylineIndex; +PDS_db_recPtr PDS_image_listPtr; + + PDS_image_listPtr = (PDS_db_recPtr)info->PDS_dbasePtr; + + //* Bullet proffing, check for range of value + mylineIndex = lineIndex; + if (mylineIndex < 0) + { + mylineIndex = 0; + } + else if (mylineIndex >= PDS_record_count) + { + mylineIndex = PDS_record_count-1; + } + //* get ptr to current record + PDSrecordPtr = &PDS_image_listPtr[mylineIndex]; + + PDSrecordPtr->selected = selectedValue; +} + +//***************************************************************************** +//* get a single line of data from the index +//***************************************************************************** +void getPDS_dbaseData(long lineIndex, char *lineBuff, bool *selectedFlag, bool *volPresentFlag) +{ +PDS_db_recPtr PDSrecordPtr; +PDS_db_recPtr PDS_image_listPtr; + + PDS_image_listPtr = (PDS_db_recPtr)info->PDS_dbasePtr; + + //* get ptr to current record + PDSrecordPtr = &PDS_image_listPtr[lineIndex]; + + *selectedFlag = PDSrecordPtr->selected; + *volPresentFlag = PDSrecordPtr->ImgVolumePresentFlag; + + switch(info->PDS_dbaseType) + { + case Voyager_db_ImageDBase: + case Viking_db_ImageDBase: + sprintf(lineBuff, "%4ld-%s: %s - %s - %s - %s\r",(lineIndex +1), + PDSrecordPtr->IMAGE_VOLUME_ID, + PDSrecordPtr->SPACECRAFT_NAME, + //* PDSrecordPtr->MISSION_PHASE_NAME, + PDSrecordPtr->IMAGE_NUMBER, + PDSrecordPtr->TARGET_NAME, + PDSrecordPtr->NOTE + ); + break; + + case Magellan_db_MDIR_Geometry: //* GEOM.TAB;1 Geometry file for one MIDR + sprintf(lineBuff, "%4ld-Not finished\r",(lineIndex +1)); + break; + + case Magellan_db_Venus_Features: //* GEO.TAB;1 Venus Features + sprintf(lineBuff, "%4ld-%-8s == %4d -> %4d : %4d ->%4d: %s \r",(lineIndex +1), + PDSrecordPtr->TARGET_NAME, + PDSrecordPtr->minLat, + PDSrecordPtr->maxLat, + PDSrecordPtr->minLon, + PDSrecordPtr->maxLon, + PDSrecordPtr->NOTE + ); + *volPresentFlag = true; + break; + + case Magellan_db_CD_Contents: //* CONTENTS.TAB;1 + sprintf(lineBuff, "%4ld-Not finished\r",(lineIndex +1)); + break; + + case Magellan_db_MDIR_Products_list: //* MCUMDIR.TAB;1 + sprintf(lineBuff, "%4ld-%s: %s - %s\r",(lineIndex +1), + PDSrecordPtr->IMAGE_VOLUME_ID, + PDSrecordPtr->TARGET_NAME, + PDSrecordPtr->IMAGE_FILE_NAME + ); + *volPresentFlag = true; + break; + + case Magellan_db_FrameLatLong_List: //* FRAME.TAB;1 + sprintf(lineBuff, "%4ld-%s: %s - %s - %s - %s\r",(lineIndex +1), + PDSrecordPtr->IMAGE_VOLUME_ID, + PDSrecordPtr->SPACECRAFT_NAME, + PDSrecordPtr->IMAGE_NUMBER, + PDSrecordPtr->TARGET_NAME, + PDSrecordPtr->NOTE + ); + *volPresentFlag = true; + break; + + default: + sprintf(lineBuff, "%4ld-Internal Error\r",(lineIndex +1)); + break; + + } +} + +//***************************************************************************** +void VenusFeaturesDoubleClick(long lineIndex) +{ +PDS_db_recPtr PDSrecordPtr; +Rect featureRect; +PDS_db_recPtr PDS_image_listPtr; + + PDS_image_listPtr = (PDS_db_recPtr)info->PDS_dbasePtr; + + //* get ptr to current record + PDSrecordPtr = &PDS_image_listPtr[lineIndex]; + + featureRect.left = PDSrecordPtr->minLon; + featureRect.right = PDSrecordPtr->maxLon; + featureRect.top = PDSrecordPtr->maxLat; + featureRect.bottom = PDSrecordPtr->minLat; + + MercatorFrameRect(&featureRect); + + //* PDSrecordPtr->TARGET_NAME, + //* PDSrecordPtr->NOTE + +} + +//***************************************************************************** +PDS_FixFileName(char *filenameString, Str255 nameBuff) +{ +short i,j; +bool inDirNameFlg; + + //************************************************************** + //* the file names look like this + //* "VG_0004 :[HELENE]C3401041.IMQ " + //* "VG_0004 :[SATURN.C3470XXX]C3470640.IMQ " + //* change the string to conform to Mac conventions + //************************************************************** + i = 0; + j = 0; + inDirNameFlg = false; + while (i < strlen(filenameString)) + { + if (filenameString[i] == '[') //* ignore "[" + { + inDirNameFlg = true; + } + else if (filenameString[i] == ']') //* change "]" to ':' + { + nameBuff[j++] = ':'; + inDirNameFlg = false; + } + else if ((filenameString[i] == '.') && (inDirNameFlg == true)) + { + nameBuff[j++] = ':'; //* change '.' to ':' + //* but only when in the directory section of the name + } + else if (filenameString[i] != ' ') + { + nameBuff[j++] = filenameString[i]; //* copy others + } + i++; + } + if (gUseSemicolonOne) + { + nameBuff[j++] = ';'; //* adde ";1" + nameBuff[j++] = '1'; + } + nameBuff[j++] = 0x00; + CtoPstr((Ptr)nameBuff); + +} + + + +//***************************************************************************** +//* If 'info' is also the Browse info ptr, set it to nil +//* this gets called from the close window code +//***************************************************************************** +PDS_checkForBrowseWindow() +{ + if (info == BrowseInfoPtr) + { + BrowseInfoPtr = nil; + } +} + + +//***************************************************************************** +PDS_VolumeNotMounted(void *volName) +{ +short itemHit; + itemHit = doSimpleDialog(PDS_volumeDialog, PDS_volumeDialogLAST); + if (itemHit == upDateVolumes) + { + PDS_checkMountedVolumes(); + } +} + +//***************************************************************************** +bool OpenIndexedVoyagerPDSfile(long lineIndex, short whichFile) +{ +bool returnFlag, okFlag; +PDS_db_recPtr PDSrecordPtr; +char tempbuf[256]; +Str255 nameBuff; +InfoPtr SaveInfo; +OSErr err; +long TempSize, fileSize; +short browseWidth,browseHeidth; +short fRefNum; +short theRefNum; +OSType theExtension; +short i, fnameLen; +PDS_db_recPtr PDS_image_listPtr; + + PDS_image_listPtr = (PDS_db_recPtr)info->PDS_dbasePtr; + + //* get ptr to current record + PDSrecordPtr = &PDS_image_listPtr[lineIndex]; + + ShowWatch(); + if (whichFile == Browse) + { + sprintf(tempbuf, "%s:%s", PDSrecordPtr->BROWSE_VOLUME_ID, + PDSrecordPtr->BROWSE_FILE_NAME ); + PDS_FixFileName(tempbuf, nameBuff); + + //* if the volume present flag is false, check again anyway + if (PDSrecordPtr->BrsVolumePresentFlag == false) + { + PDSrecordPtr->BrsVolumePresentFlag = CheckForVolume(PDSrecordPtr->BROWSE_VOLUME_ID); + } + + if (PDSrecordPtr->BrsVolumePresentFlag == false) + { + PtoCstr(nameBuff); + sprintf(tempbuf, "Sorry, file '%s' could not be opened. The volume is not mounted", nameBuff); + PutMessage(CtoPstr(tempbuf)); + return(false); + } + + SaveInfo = info; + + //* open the file first + //* we have to figure out what size it is so we can figure out what + //* size the image is + err = FSOpen(nameBuff, theRefNum, &fRefNum); + if (err != noErr) + { + return(false); + } + err = GetEOF(fRefNum, &fileSize); + + if (fileSize == 82500L) + { + browseWidth = 300; + browseHeidth = 264; + info->ImageDataOffset = 3300; + } + else + { + browseWidth = 200; + browseHeidth = 200; + info->ImageDataOffset = 3200; + } + + if (BrowseInfoPtr == nil) + { + okFlag = NewPicWindow("\pBrowse Window", browseWidth, browseHeidth); + if ( okFlag == false ) + { + info = SaveInfo; + return(false); + } + info->LutMode = GrayScale; + ResetGrayMap(); + SaveOriginalColorPalette(); + + BrowseInfoPtr = info; + } + info = BrowseInfoPtr; + + TempSize = 1L * browseWidth * browseHeidth; + err = SetFPos(fRefNum, fsFromStart, info->ImageDataOffset); + err = FSRead(fRefNum, &TempSize, info->PicBaseAddr); + if (err != noErr) + { + SysBeep(1); + } + err = FSClose(fRefNum); + + + + strncpy(gCurrentVolName, PDSrecordPtr->BROWSE_VOLUME_ID, 8); + gCurrentVolName[7] = 0; + CtoPstr(gCurrentVolName); + + PDS_readingFileType = VoyagerBrowse; + setPDSinfoStuf(info, gCurrentVolName, (char *)nameBuff); + PDS_readingFileType = 0; //* reset the flag for the next time + + if (info->PDS_volPrefix == 'VG_0') + { + InvertPic(); + } + UpdatePicWindow(); + info = SaveInfo; + returnFlag = true; + } + else + { + sprintf(tempbuf, "%s:%s", PDSrecordPtr->IMAGE_VOLUME_ID, + PDSrecordPtr->IMAGE_FILE_NAME ); + + PDS_FixFileName(tempbuf, nameBuff); + + //* is that volume on line + if (PDSrecordPtr->ImgVolumePresentFlag == true) + { + returnFlag = OpenPDS_LabelFile(nameBuff, 0, VARIABLE_LENGTH); + if (returnFlag == true) + { + //* Magellan CD-ROM has seperate label and image files + theExtension = getFnameExtension((char *)nameBuff); //* find the extension of the file name + + if (theExtension == '.IMQ') //* read normal IMQ file + { + returnFlag = OpenPDS_Labeled_Image(nameBuff, 0, VARIABLE_LENGTH); + } + else if (theExtension == '.LBL') //* replace ".LBL" with ".IMG" + { + fnameLen = nameBuff[0]; //* get the length of the file name + for (i = fnameLen; i > 0; i--) + { + if (nameBuff[i] == '.') break; //* find the "." + } + nameBuff[i+1] = 'I'; //* replace the extension + nameBuff[i+2] = 'M'; + nameBuff[i+3] = 'G'; + + WhatToOpen = OpenCustom; + ImportCustomWidth = 1024; + ImportCustomHeight = 1024; + ImportCustomOffset = 0; + returnFlag = OpenFile(nameBuff, 0); + strncpy(gCurrentVolName, PDSrecordPtr->IMAGE_VOLUME_ID, 8); + gCurrentVolName[7] = 0; + CtoPstr(gCurrentVolName); + + setPDSinfoStuf(info, gCurrentVolName, (char *)nameBuff); + PDS_readingFileType = 0; //* reset the flag for the next time + + } + else //* for now, leave this the default, we may have to change it later + { + returnFlag = OpenPDS_Labeled_Image(nameBuff, 0, VARIABLE_LENGTH); + } + } + else + { + PtoCstr(nameBuff); + sprintf(tempbuf, "Sorry, file '%s' could not be opened. The volume is probably not mounted", nameBuff); + PutMessage(CtoPstr(tempbuf)); + } + } + else + { + PDS_VolumeNotMounted(PDSrecordPtr->IMAGE_VOLUME_ID); + returnFlag = false; + } + } + return(returnFlag); +} + +//***************************************************************************** +void PDS_OpenBrowse() +{ +long lineNumOnScreen, lineIndex; +textEditInfoPtr TEDataPtr; +PDS_db_recPtr PDSrecordPtr; +PDS_db_recPtr PDS_image_listPtr; + + PDS_image_listPtr = (PDS_db_recPtr)info->PDS_dbasePtr; + + TEDataPtr = (textEditInfoPtr)info->textEditRec; + if (TEDataPtr != nil) + { + lineIndex = TEDataPtr->selectedIndex; + + //* Bullet proffing, check for range of value + if (lineIndex < 0) + { + lineIndex = 0; + } + else if (lineIndex >= PDS_record_count) + { + lineIndex = PDS_record_count-1; + } + + //* get ptr to current record + PDSrecordPtr = &PDS_image_listPtr[lineIndex]; + + if (PDSrecordPtr->BrsVolumePresentFlag == false) + { + PDS_VolumeNotMounted(PDSrecordPtr->BROWSE_VOLUME_ID); + } + + if (PDSrecordPtr->BrsVolumePresentFlag == true) + { + OpenIndexedVoyagerPDSfile(lineIndex, Browse); + } + } + else + { + SysBeep(1); + } +} + + +//***************************************************************************** +//* args are pascal strings +void setPDSinfoStuf(InfoPtr theInfoPtr, char *volname, char *fname) +{ + + theInfoPtr->fnameExtension = getFnameExtension((char *)fname); + strncpy(theInfoPtr->PDS_volName, volname,8); + theInfoPtr->PDS_volName[0] = 7; //* force Pascal string notation + theInfoPtr->PDS_volName[8] = 0; + theInfoPtr->PDS_volPrefix = (volname[1] << 8) + + (volname[2]); + theInfoPtr->PDS_volPrefix = (theInfoPtr->PDS_volPrefix << 16) + + (volname[3] << 8) + + (volname[4]); + theInfoPtr->PDS_imageType = PDS_readingFileType; + theInfoPtr->PDS_dbaseType = 0; + theInfoPtr->PDS_dbasePtr = 0; + theInfoPtr->PDS_dbaseRecCnt = 0; + + //* debuging code + if (theInfoPtr->PDS_imageType == 0) + { + SysBeep(1); + } +} + +//***************************************************************************** +void clrPDSinfoStuf(InfoPtr theInfoPtr) +{ + theInfoPtr->fnameExtension = 0; + theInfoPtr->PDS_volName[0] = 0; + theInfoPtr->PDS_volPrefix = 0; + theInfoPtr->PDS_imageType = 0; + theInfoPtr->PDS_dbaseType = 0; + theInfoPtr->PDS_dbasePtr = 0; + theInfoPtr->PDS_dbaseRecCnt = 0; + theInfoPtr->imageMinLat = 0; + theInfoPtr->imageMaxLat = 0; + theInfoPtr->imageMinLon = 0; + theInfoPtr->imageMaxLon = 0; +} + +//***************************************************************************** +bool PDS_is_this_an_Image(InfoPtr theInfoPtr) +{ +bool returnFlag; + returnFlag = true; + if ( (theInfoPtr->PDS_imageType == PDSLabelText) || + (theInfoPtr->PDS_imageType >= Voyager_db_ImageDBase)) + { + returnFlag = false; + } + return(returnFlag); +} + +//*************************************************************** +void doPDS_DbaseMenu(int MenuItem) +{ +Str255 fileName; +short volumeCount, magellanVolCnt; +short i, j; +diskNames volumes[MaxVolCount]; + + switch ( MenuItem ) + { + case PDS_dbOpenVoyagerViking: + break; + + case PDS_dbOpenMagellanFeatureList: + //*************************************************************** + //* find the first mounted Magellan CD-ROM + volumeCount = getMountedVolumeList(volumes); + magellanVolCnt = 0; + for (j=0; j < volumeCount; j++) + { + if (strncmp(volumes[j].vName, "MG_00",5) == 0) + { + strcpy((char *)fileName, volumes[j].vName); + magellanVolCnt++; //* increment the number of magellan CDs we have + } + } + if (magellanVolCnt > 0) + { + strcat((char *)fileName, ":GEO.TAB"); + CtoPstr((Ptr)fileName); + OpenPDSdatabaseFile(fileName, 0); + } + else + { + SysBeep(1); + } + break; + } +} + +//*************************************************************** +UpdatePDSdbaseMenu() +{ +char volName[32]; +short volumeCount, VG_VolCnt, VO_VolCnt, MG_VolCnt; +short volType; +short j; +diskNames volumes[MaxVolCount]; + + volumeCount = getMountedVolumeList(volumes); + VG_VolCnt = 0; + VO_VolCnt = 0; + MG_VolCnt = 0; + + for (j=0; j < volumeCount; j++) + { + CtoPstrcpy(volName, volumes[j].vName); + volType = PDS_GetCDROMtype(volName); + switch(volType) + { + case VOYAGER: VG_VolCnt++; break; + case VIKING_1: VO_VolCnt++; break; + case VIKING_2: VO_VolCnt++; break; + case MAGELLAN: MG_VolCnt++; break; + } + } + SetMenuItem(OpenPDSdbaseMenuH, PDS_dbOpenVoyagerViking, (VG_VolCnt+VO_VolCnt) > 0); + SetMenuItem(OpenPDSdbaseMenuH, PDS_dbOpenMagellanFeatureList, MG_VolCnt > 0); +} +#endif // __MAC__