/************************************************************************** ------------------------------------------------------------ jconv Version 1.0 ------------------------------------------------------------ copyright Andreas Mock 1999 Andreas Mock ------------------------------------------------------------ based on the original source code and with friendly permission of J. J. Lehett ------------------------------------------------------------ You are permitted to use the jconv package in the terms of the GNU General Public License. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 See the COPYRIGHT file in this package. **************************************************************************/ #include "jconv.h" #include #include #include #include #include #define MAXERR 255 #define MB_OK 0 char popupListStringForFunction[10000]; tRecEntry recEntrys[MAX_RECORDS]; int dataLengths[MAX_RECORDS]; short dataLengthsFields[MAX_FIELDS]; short curFieldTypes[MAX_FIELDS]; int BinaryDataSize; char BinaryDataString[4000]; char tempFieldNames[MAX_FIELDS][55]; int main(int argc, char* argv[]) { char infofile[FILENAME_MAX]; char outfile[FILENAME_MAX]; char infile[FILENAME_MAX]; char title[32]; char o = ' '; char encode = ' '; extern char *optarg; extern int optind, opterr, optopt; opterr = 0; /* no option processing error */ strcpy(infofile, ""); strcpy(outfile, ""); strcpy(infile, ""); delimChar = ','; /* standard */ m_CommandLineComma = 1; /* standard */ m_UseInfoFile = 0; while((o = getopt(argc, argv, "edvht:i:s")) != EOF) { switch(o) { case 'e': encode = 'e'; break; case 'd': encode = 'd'; break; case 's': m_CommandLineComma = 0; break; case 't': strncpy(title, optarg, 32); title[31] = 0; strcpy(m_DBName, title); break; case 'i': strcpy(infofile, optarg); strcpy(m_InfoPath, optarg); m_UseInfoFile = 1; break; case 'h': showsynopsis(); exit(0); case 'v': showversion(); exit(0); case '?': fprintf(stderr, "Error while option processing\n"); showsynopsis(); exit(1); } } if (optind != argc - 2) { fprintf(stderr, "Error: You must give a filename\n"); showsynopsis(); exit(1); } strcpy(infile, argv[optind]); strcpy(outfile, argv[optind + 1]); if(strlen(m_DBName) == 0) { strncpy(m_DBName, basename(outfile), 32); m_DBName[31] = 0; } switch(encode) { case ' ': fprintf(stderr, "Error: You should specify what you want to do\n"); showsynopsis(); exit(1); case 'e': strcpy(m_CSVPath, infile); strcpy(m_PDBPath, outfile); return(CSVToJFile()); case 'd': strcpy(m_PDBPath, infile); strcpy(m_CSVPath, outfile); return(JFileToCSV()); } return(0); } void DecodeField(unsigned char* inData, char* outData, int type, int len) { int loc, i; long intHold; unsigned char holdChr[2]; switch(type) { case FLDTYPE_BINARY: holdChr[1] = '\0'; for(i=0; i 0) fputs("\"", output); for(i=0; i 0) fputs("\"", output); for(i=1; i 0) fputs("\"", output); for(j=0; j 0) fputs("\"", output); } fputs("\n", output); dumpLoc = 0; //!!!!! 10 extra bytes, but why???? //for(j=0; j<10; j++) // fgetc(input); for(i=0; i 0) fputc(delimChar, output); fputs("\"", output); fputs(tempRec.fieldData[ij], output); fputs("\"", output); } fputs("\n", output); } // ok everything should be read in close the input file fclose(input); fclose(output); sprintf(recNumStr, "%d", numNonDeletedRecs); strcpy(endMsg, "Conversion of "); strcat(endMsg, recNumStr); strcat(endMsg, " records in "); strcat(endMsg, m_PDBPath); strcat(endMsg, " to "); strcat(endMsg, m_CSVPath); strcat(endMsg, " was successful!"); MessageBox( endMsg, NULL, MB_OK ); } int CSVToJFile() { char errorStr[MAXERR]; char errorNum[50]; unsigned long currentOfs; int i,j; char dbName[200]; int usesInfoFile; tHeader header = { 0 }; char inputString[MAX_RECORD_LENGTH]; int inputStringLoc, inputStringLen; JFileAppInfoType appInfo; int fieldNameLocs[MAX_FIELDS]; int isInQuote = 0; int wasQuoted = 0; char tempLine[MAX_DATA_LENGTH+1]; char tempLine2[MAX_DATA_LENGTH+1]; int currentRecord; int currentField; int dataLocs[MAX_FIELDS]; JBaseRecordType record; char* returnPtr = NULL; int u = 0; WORD oddity = 0x008C; // unknown byte in the pdb struct char endMsg[2048]; char recNumStr[10]; FILE* input; FILE* output; FILE* info; char* nullPtr; if(m_CommandLineComma == 0) delimChar = ';'; nullPtr = NULL; usesInfoFile = m_UseInfoFile; if((input = fopen(m_CSVPath, "r")) == NULL) { // handle the error here MessageBox2( "Error - Can't open csv file", NULL, MB_OK ); return; } if((output = fopen(m_PDBPath, "wb")) == NULL) { //handle the error here MessageBox2( "Error - Can't open pdb file", NULL, MB_OK ); return; } if(usesInfoFile) { if((info = fopen(m_InfoPath, "r")) == NULL) { //handle the error here //MessageBox2( "Error - Can't open ifo file", NULL, MB_OK ); usesInfoFile = 0; } } // need to find DB name somehow strcpy(dbName, m_PDBPath); dbName[30]= '\0'; strcpy(header.sTitle, dbName); // get the field names fgets(inputString, MAX_RECORD_LENGTH, input); if(strlen(inputString) > 3999) { strcpy(errorStr, "Field Names record too long"); MessageBox2( errorStr, NULL, MB_OK ); fclose(input); fclose(output); if(usesInfoFile) fclose(info); return; } inputStringLoc = 0; appInfo.numFields = 0; fieldNameLocs[0] = 0; inputStringLen = strlen(inputString); while(inputStringLoc < inputStringLen) { if((inputString[inputStringLoc] == '"') && (inputString[inputStringLoc+1] == '"') && (isInQuote == 1)) { inputStringLoc += 2; continue; } if((inputString[inputStringLoc] == '"')) { if(isInQuote == 1) { isInQuote = 0; } else { wasQuoted = 1; isInQuote = 1; } } if((inputString[inputStringLoc] == delimChar) && (isInQuote == 0)) { fieldNameLocs[appInfo.numFields+1] = inputStringLoc+1; if(fieldNameLocs[appInfo.numFields+1] - fieldNameLocs[appInfo.numFields] > MAX_FIELD_NAME_LENGTH+3) { sprintf(errorNum, "%d", appInfo.numFields + 1); strcpy(errorStr, "Field Name: "); strcat(errorStr, errorNum); strcat(errorStr, " too long"); MessageBox2( errorStr, NULL, MB_OK ); fclose(input); fclose(output); if(usesInfoFile) fclose(info); return; } appInfo.numFields++; inputString[inputStringLoc] = '\0'; } if(inputString[inputStringLoc] == '\n') { inputString[inputStringLoc] = '\0'; fieldNameLocs[appInfo.numFields+1] = inputStringLoc+1; if(fieldNameLocs[appInfo.numFields+1] - fieldNameLocs[appInfo.numFields] > MAX_FIELD_NAME_LENGTH+3) { sprintf(errorNum, "%d", appInfo.numFields + 1); sprintf(errorStr, "Field Name: %s too long", errorNum); MessageBox2( errorStr, NULL, MB_OK ); fclose(input); fclose(output); if(usesInfoFile) fclose(info); return; } } inputStringLoc++; } appInfo.numFields++; for(i=0; i MAX_FIELDS) { sprintf(errorNum, "%d", appInfo.numFields); sprintf(errorStr, "ERROR: This csv file contains %s fields. 50 fields is the maximum limit for JFile.", errorNum); MessageBox2( errorStr, NULL, MB_OK ); fclose(input); fclose(output); if(usesInfoFile) fclose(info); return; } for(i=0; i MAX_FIELD_NAME_LENGTH) { sprintf(errorStr, "Field Name: too long"); MessageBox2( errorStr, NULL, MB_OK ); fclose(input); fclose(output); if(usesInfoFile) fclose(info); return; } } currentRecord = -1; returnPtr = fgets(inputString, MAX_RECORD_LENGTH, input); while( returnPtr != NULL) { //printf("%i\n", currentRecord+1); currentRecord++; currentField = 0; inputStringLoc = 0; inputStringLen = strlen(inputString); if(inputString[inputStringLen-1] != '\n') { inputString[inputStringLen] = '\n'; inputString[inputStringLen+1] = '\0'; inputStringLen++; } //inputString[inputStringLen+1] = '\0'; dataLocs[0] = 0; while(inputStringLoc < inputStringLen) { if((inputString[inputStringLoc] == '"') && (inputString[inputStringLoc+1] == '"') && (isInQuote == 1)) { inputStringLoc += 2; continue; } if((inputString[inputStringLoc] == '"')) { if(isInQuote == 1) { isInQuote = 0; } else { wasQuoted = 1; isInQuote = 1; } } if((inputString[inputStringLoc] == delimChar) && (isInQuote == 0)) { dataLocs[currentField+1] = inputStringLoc+1; if(dataLocs[currentField+1] - dataLocs[currentField] > MAX_DATA_LENGTH) { sprintf(errorNum, "%d", currentRecord+1); sprintf(errorStr, "Field data too long at record: %s", errorNum); MessageBox2( errorStr, NULL, MB_OK ); fclose(input); fclose(output); if(usesInfoFile) fclose(info); return; } currentField++; inputString[inputStringLoc] = '\0'; } if(inputString[inputStringLoc] == '\n') { if(isInQuote) { sprintf(errorNum, "%d", currentRecord+1); sprintf(errorStr, "Unclosed quoted string at record: %s", errorNum); MessageBox2( errorStr, NULL, MB_OK ); fclose(input); fclose(output); if(usesInfoFile) fclose(info); return; } if(inputStringLoc - dataLocs[currentField] > MAX_DATA_LENGTH) { sprintf(errorNum, "%d", currentRecord+1); sprintf(errorStr, "Field data too long\n\ at record: %s", errorNum); MessageBox2( errorStr, NULL, MB_OK ); fclose(input); fclose(output); if(usesInfoFile) fclose(info); return; } inputString[inputStringLoc] = '\0'; while(currentField < appInfo.numFields) { dataLocs[currentField+1] = inputStringLoc+1; currentField++; inputString[inputStringLoc++] = '\0'; } } inputStringLoc++; } if(currentField != appInfo.numFields) { sprintf(errorNum, "%d", currentRecord+2); sprintf(errorStr, "Invalid number of fields (commas) at CSV line #: %s", errorNum); MessageBox2( errorStr, NULL, MB_OK ); fclose(input); fclose(output); //fclose(info); return; } for(i=0; i 0) { strcpy(header.sTitle, m_DBName); } fwrite(&header, 1, 78, output); for(i=0; i<=currentRecord; i++) { fwrite(&recEntrys[i].rp.ofs, 1, sizeof(DWORD), output); fwrite(&recEntrys[i]._id, 1, sizeof(DWORD), output); } fwrite(&oddity, 1, sizeof(oddity), output); if(!usesInfoFile) { fwrite(&appInfo, 1, JFILEAPPINFOSIZE, output); fwrite(BinaryDataString, 1, BinaryDataSize, output); } else { fwrite(&appInfo, 1, (JFILEAPPINFOSIZE)-4, output); fwrite(appInfo.popupLists, 1, FindJFileAppInfoSize(&appInfo) - ((JFILEAPPINFOSIZE)-4) - BinaryDataSize, output); fwrite(BinaryDataString, 1, BinaryDataSize, output); } if((input = fopen(m_CSVPath, "r")) == NULL) { sprintf(errorStr, "Could not open input file."); MessageBox2( errorStr, NULL, MB_OK ); fclose(input); fclose(output); fclose(info); return; } header.tCreated = SwapDWordToMotor(header.tCreated); header.tModded = SwapDWordToMotor(header.tModded); header.wVersion = FlipWord(header.wVersion); header.ofsAttributes = SwapDWordToMotor(header.ofsAttributes); header.dwType = SwapDWordToMotor(header.dwType); header.dwCreator = SwapDWordToMotor(header.dwCreator); header.wAttr = FlipWord(header.wAttr); header.nRecs = FlipWord(header.nRecs); appInfo.numFields = FlipWord(appInfo.numFields); // get the field names fgets(inputString, 4000, input); currentRecord = -1; while( fgets(inputString, 4000, input) != NULL) { currentRecord++; currentField = 0; inputStringLoc = 0; inputStringLen = strlen(inputString); if(inputString[inputStringLen-1] != '\n') { inputString[inputStringLen] = '\n'; inputString[inputStringLen+1] = '\0'; inputStringLen++; } //inputString[inputStringLen+1] = '\0'; //dataLengths[currentRecord] = inputStringLen; dataLocs[0] = 0; while(inputStringLoc < inputStringLen) { if((inputString[inputStringLoc] == '"') && (inputString[inputStringLoc+1] == '"') && (isInQuote == 1)) { inputStringLoc += 2; continue; } if((inputString[inputStringLoc] == '"')) { if(isInQuote == 1) { isInQuote = 0; } else { wasQuoted = 1; isInQuote = 1; } } if((inputString[inputStringLoc] == delimChar) && (isInQuote == 0)) { dataLocs[currentField+1] = inputStringLoc+1; if(dataLocs[currentField+1] - dataLocs[currentField] > MAX_DATA_LENGTH) { sprintf(errorNum, "%d", currentRecord); sprintf(errorStr, "Field data at record: %s too long", errorNum); MessageBox2( errorStr, NULL, MB_OK ); fclose(input); fclose(output); fclose(info); return; } currentField++; inputString[inputStringLoc] = '\0'; } if(inputString[inputStringLoc] == '\n') { inputString[inputStringLoc] = '\0'; while(currentField < appInfo.numFields) { dataLocs[currentField+1] = inputStringLoc+1; currentField++; inputString[inputStringLoc++] = '\0'; } } inputStringLoc++; } for(i=0; i= '0') && (record.fieldData[j][u] <= '9')) { record.fieldData[j][u/2] = 16*(record.fieldData[j][u] - '0'); } else { record.fieldData[j][u/2] = 16*(record.fieldData[j][u] - 'A' + 10); } if( (record.fieldData[j][u+1] >= '0') && (record.fieldData[j][u+1] <= '9')) { record.fieldData[j][u/2] += (record.fieldData[j][u+1] - '0'); } else { record.fieldData[j][u/2] += (record.fieldData[j][u+1] - 'A' + 10); } } break; default: dataLengths[j] += (strlen(record.fieldData[j]) + 1); dataLengthsFields[j] = (strlen(record.fieldData[j]) + 1); break; } } for(j=0; j4000) { MessageBox2( "Error - Invalid AppInfo in .pdb file", NULL, MB_OK ); return(1); } //popupListLocation++; } appInfo->popupLists = PopupListString; return(1); } int FindJFileAppInfoSize(JFileAppInfoType * appInfo) { int appInfoSize = 0; char* tempPopupPtr; appInfoSize = (JFILEAPPINFOSIZE - 4); tempPopupPtr = appInfo->popupLists; if(strlen(tempPopupPtr) == 0) { appInfoSize+=4; // add 4 for the 4 nulls needed for no popup list } else { while(strlen(tempPopupPtr) != 0) { appInfoSize += (strlen(tempPopupPtr)+1); tempPopupPtr += (strlen(tempPopupPtr)+1); } appInfoSize++; // extra null since popup lists end in 2 nulls } appInfoSize += BinaryDataSize; if(appInfoSize < JFILEAPPINFOSIZE) { appInfoSize = JFILEAPPINFOSIZE; } return(appInfoSize); } int ReadJFileInfoFileFieldTypesOnly(JFileAppInfoType * appInfo, FILE * info) { char* tempPopupPtr; int i; int temp; int numItems = 0; int listLength = 0; char errorStr[2048]; // first line is the field types for(i=0; inumFields; i++) { if(fscanf(info, "%i", &(temp)) != 1) { char errorStr[2048]; strcpy(errorStr, "Invalid number of field types in info file."); MessageBox( errorStr, NULL, MB_OK ); return(1); } curFieldTypes[i] = temp; //curFieldTypes[i] = FlipWord(appInfo->fieldTypes[i]); } return(1); } int ReadJFileInfoFile(JFileAppInfoType * appInfo, FILE * info, char * popupListString, FILE* output) { char* tempPopupPtr; int i; int temp; int numItems = 0; int listLength = 0; char errorStr[2048]; char binStr[4000]; int binLen; // first line is the field types for(i=0; inumFields; i++) { if(fscanf(info, "%i", &(temp)) != 1) { char errorStr[2048]; strcpy(errorStr, "Invalid number of field types in info file."); MessageBox( errorStr, NULL, MB_OK ); return(1); } //printf("%i " , appInfo->numFields); appInfo->fieldTypes[i] = temp; //if( (temp != FLDTYPE_STRING) && (temp != FLDTYPE_BOOLEAN) && (temp != FLDTYPE_DATE) && // (temp != FLDTYPE_INT) && (temp != FLDTYPE_FLOAT) && (temp != FLDTYPE_LIST) ) //{ // printf("Error: Invalid field type in info file.\n"); // exit(0); //} appInfo->fieldTypes[i] = FlipWord(appInfo->fieldTypes[i]); //printf("%i " , appInfo->numFields); } //printf("%i " , appInfo->numFields); // second line is the field widths for(i=0; inumFields; i++) { //printf("%i " , i); if(fscanf(info, "%i", &(temp)) != 1) { char errorStr[2048]; strcpy(errorStr, "Invalid number of data widths (line 2) in info file."); MessageBox( errorStr, NULL, MB_OK ); return(1); } appInfo->showDBColumnWidths[i] = temp; if(temp > 160) { strcpy(errorStr, "Invalid field width in Info file"); MessageBox( errorStr, NULL, MB_OK ); return(1); } appInfo->showDBColumnWidths[i] = FlipWord(appInfo->showDBColumnWidths[i]); } // third line is the data entry screen field width if( fscanf(info, "%i\n", &(temp)) != 1) { char errorStr[2048]; strcpy(errorStr, "Invalid data screen width (line 3) in info file."); MessageBox( errorStr, NULL, MB_OK ); return(1); } appInfo->showDataWidth = temp; // printf("%i ", appInfo->showDataWidth); if((temp < 0) || (temp > 160)) { strcpy(errorStr, "Invalid first show data width in Info file"); MessageBox( errorStr, NULL, MB_OK ); return(1); } appInfo->showDataWidth = FlipWord(appInfo->showDataWidth); // 4th line is which column to display as first movable column in the database screen if(fscanf(info, "%i\n", &(temp)) != 1) { char errorStr[2048]; strcpy(errorStr, "Invalid first display column (line 4) in info file."); MessageBox( errorStr, NULL, MB_OK ); return(1); } appInfo->firstColumnToShow = temp; //appInfo->firstColumnToShow = 0xffff; if((temp < 0) || (temp > 19)) { strcpy(errorStr, "Error: invalid 'first show column' in Info file."); MessageBox( errorStr, NULL, MB_OK ); return(1); } appInfo->firstColumnToShow = FlipWord(appInfo->firstColumnToShow); // 5th line is appInfo flags variable (readonly, struct lock etc... bit field if(fscanf(info, "%i\n", &(temp)) != 1) { char errorStr[2048]; strcpy(errorStr, "Invalid AppInfo flag (line 5) in info file."); MessageBox( errorStr, NULL, MB_OK ); return(1); } appInfo->flags = temp; appInfo->flags = FlipWord(appInfo->flags); // 6th and 7th lines are 'extra data' // first line is the field types for(i=0; inumFields; i++) { if(fscanf(info, "%i", &(temp)) != 1) { char errorStr[2048]; strcpy(errorStr, "Invalid extra data 1 fields (line 5) in info file."); MessageBox( errorStr, NULL, MB_OK ); return(1); } appInfo->fieldExtraData[i] = temp; appInfo->fieldExtraData[i] = SwapDWordToIntel(appInfo->fieldExtraData[i]); } for(i=0; inumFields; i++) { if(fscanf(info, "%i", &(temp)) != 1) { char errorStr[2048]; strcpy(errorStr, "Invalid extra data 2 fields (line 6) in info file."); MessageBox( errorStr, NULL, MB_OK ); return(1); } appInfo->fieldExtraData2[i] = temp; appInfo->fieldExtraData2[i] = SwapDWordToIntel(appInfo->fieldExtraData2[i]); } // skip the final space char //fgetc(info); //fgetc(info); fgets(binStr, 4000, info); fgets(binStr, 4000, info); binLen = strlen(binStr); BinaryDataSize = binLen/2; for(i=0; i= '0') && (binStr[i] <= '9')) { BinaryDataString[i/2] = 16*(binStr[i] - '0'); } else { BinaryDataString[i/2] = 16*(binStr[i] - 'A' + 10); } if( (binStr[i+1] >= '0') && (binStr[i+1] <= '9')) { BinaryDataString[i/2] += (binStr[i+1] - '0'); } else { BinaryDataString[i/2] += (binStr[i+1] - 'A' + 10); } } tempPopupPtr = popupListString; while(fgets(tempPopupPtr, 100, info) != NULL) { if(strlen(tempPopupPtr) != 0) { //fputs("\n", output); //fputs(tempPopupPtr, output); //fputs("\n", output); listLength += strlen(tempPopupPtr)+1; if( (tempPopupPtr[0] == 'p') && (tempPopupPtr[1] == 'o') && (tempPopupPtr[2] == 'p') && (tempPopupPtr[3] == 'u') && (tempPopupPtr[4] == 'p') ) { numItems = 0; } else { numItems++; if(numItems > 99) { strcpy(errorStr, "Error: popup list exceeds 100 items."); MessageBox( errorStr, NULL, MB_OK ); return(1); } } if(tempPopupPtr[strlen(tempPopupPtr)-1] == 0x0A) { tempPopupPtr[strlen(tempPopupPtr)-1] = '\0'; } tempPopupPtr += (strlen(tempPopupPtr)+1); } } tempPopupPtr[0] = '\0'; // to be safe add in the remaining nulls to fill in a blank list to make // it be equal to the length of a char ptr tempPopupPtr[1] = '\0'; tempPopupPtr[2] = '\0'; tempPopupPtr[3] = '\0'; return(1); } unsigned long SwapDWordToMotor(unsigned long dwSubj) { DWORD dwAnswer = 0; BYTE oneByte; int maxCars = sizeof(DWORD) - 1; // 3 int i; for (i=0; i <= maxCars; i++) { oneByte = (BYTE)((dwSubj >> (i * 8)) & 0xFF); dwAnswer |= ((DWORD)oneByte) << ((maxCars - i) * 8); } return(dwAnswer); } unsigned long SwapDWordToIntel(DWORD dwSubj) { DWORD dwAnswer = 0; BYTE oneByte; int maxCars = sizeof(DWORD) - 1; // 3 int i; for (i=0; i <= maxCars; i++) { oneByte = (BYTE)((dwSubj >> ((maxCars - i) * 8)) & 0xFF); dwAnswer |= oneByte << (i * 8); } return(dwAnswer); } WORD FlipWord(WORD wSubj) { WORD wAnswer; wAnswer = ((wSubj >> 8) & 0xff) | ((wSubj & 0xff) << 8); return(wAnswer); } void Enquote(char* from, char* to) { strcpy(to, "\""); strcat(to, from); strcat(to, "\""); } void MessageBox2(char* lpszText, char* lpszCaption , unsigned int nType ) { MessageBox(lpszText, lpszCaption, nType); exit(1); } void MessageBox(char* lpszText, char* lpszCaption , unsigned int nType ) { fprintf(stderr, "jconv: %s\n", lpszText); return; } void showsynopsis() { fprintf(stderr, "jconv [-e|-d] [-i ] [-t title] \n\ \n\ -e encode: csv -> pdb\n\ -d decode: pdb -> csv\n\ -s use semicolon as delimiter\n\ -i use as infofile\n\ -t title title is the db-name\n\ -v print version information\n\ -h print this message\n\ \n\ "); return; } char* basename(char* file) { char* ptr = NULL; if((ptr = strrchr(file, '/')) != NULL) { return(ptr); } else { return(file); } } void showversion() { fprintf(stderr, "\n\ jconv: Converts JFile Pro database files to csv-files and vica versa\n\ Version 1.0\n\ copyright 1999 by Andreas Mock \n\ with permission of J. J. Lehett \n\ see also www.land-j.com\n\ \n\ "); return; }