/***************************************************************************** # Copyright (C) 1994-2008 by David Gordon. # All rights reserved. # # This software is part of a beta-test version of the Consed/Autofinish # package. It should not be redistributed or # used for any commercial purpose, including commercially funded # sequencing, without written permission from the author and the # University of Washington. # # This software is provided ``AS IS'' and any express or implied # warranties, including, but not limited to, the implied warranties of # merchantability and fitness for a particular purpose, are disclaimed. # In no event shall the authors or the University of Washington be # liable for any direct, indirect, incidental, special, exemplary, or # consequential damages (including, but not limited to, procurement of # substitute goods or services; loss of use, data, or profits; or # business interruption) however caused and on any theory of liability, # whether in contract, strict liability, or tort (including negligence # or otherwise) arising in any way out of the use of this software, even # if advised of the possibility of such damage. # # Building Consed from source is error prone and not simple which is # why I provide executables. Due to time limitations I cannot # provide any assistance in building Consed. Even if you do not # modify the source, you may introduce errors due to using a # different version of the compiler, a different version of motif, # different versions of other libraries than I used, etc. For this # reason, if you discover Consed bugs, I can only offer help with # those bugs if you first reproduce those bugs with an executable # provided by me--not an executable you have built. # # Modifying Consed is also difficult. Although Consed is modular, # some modules are used by many other modules. Thus making a change # in one place can have unforeseen effects on many other features. # It may takes months for you to notice these other side-effects # which may not seen connected at all. It is not feasable for me to # provide help with modifying Consed sources because of the # potentially huge amount of time involved. # #*****************************************************************************/ /* Written by David Gordon. Parts of it written by James Knight and gratefully used with permission. */ /* * checksff * * Usage: checksff sfffile * * This program extracts the fields from an SFF file and outputs a text * version of the data to standard output. */ #include #include /* solaris does not have stdint.h but time.h includes sys/types.h which includes sys/int_types.h which takes the place of stdint.h */ #ifndef SOLARIS #include #endif #include #include #include #include #include "rwtptrorderedvector.h" #include "basesAndQualitiesAndPeaks.h" #include "mbtValOrderedVectorOfRWCString.h" #define SFF_MAGIC_NUMBER 0x2E736666 #define SFF_VERSION "\0\0\0\1" #define MANIFEST_INDEX_MAGIC_NUMBER ( (((unsigned int) '.') << 24) + (((unsigned int) 'm') << 16) + (((unsigned int) 'f') << 8) + ((unsigned int) 't') ) #define SORT_INDEX_MAGIC_NUMBER ( (((unsigned int) '.') << 24) + (((unsigned int) 's') << 16) + (((unsigned int) 'r') << 8) + ((unsigned int) 't') ) #define INDEX_VERSION "1.00" #define TEXT_MODE 0 #define FASTA_MODE 1 #define QUAL_MODE 2 #define FLOWGRAM_MODE 3 #define MANIFEST_MODE 4 #define ACCNO_MODE 5 struct { char *accnoPrefix; char *runName; char *analysisName; char *runPath; } manifestList[10000]; int numManifest; /* * Forward references. */ void parseManifest(char *buf); int getManifestInfo(char *accno, char *runNameOut, char *analysisNameOut, char *runPathOut); int getUAccnoInfo(char *accno, char *timeOut, int *regionOut, char *xyOut); unsigned int lookupAccno(char *accno, unsigned char *indexBuf, int indexSize); void getBytes(FILE *fp, unsigned int size, unsigned char *buf, char *filename); int prefixCheck(char *s, char *t, int minlen); uint32_t getuint8(unsigned char *b); uint32_t getuint16(unsigned char *b); uint32_t getuint32(unsigned char *b); unsigned int getuint4_255(unsigned char *b); uint64_t getuint64(unsigned char *b); void readOneSffFile( char* szSffFileFullPath, FILE* fpPhdBall, char* szTimeStamp ); void removeTrailingWhitespace( char* szLine, int nInitialLength, int* pFinalLength ); void getBasename( char* szFullPath, char* szBasename ); void readOneSffFile( char* szSffFileFullPath, RWTPtrOrderedVector& aArrayOfReads, const bool bWantOnlyCertainReads, mbtValOrderedVectorOfRWCString& aDesiredReads ) { int i, j, argnum, pos, offset, outputMode, firstarg, accnoMode; int indexMode, indexSize, left, right, trimMode, prevIndex; int flowIndex[10000], scores[10000], fileMode, tabMode, uaccnoFlag; int accnoRegionId; uint32_t magic_number, index_length, number_of_reads; uint32_t header_length, key_length, number_of_flows_per_read; uint32_t flowgram_format_code, flowgram_bytes, number_reads_found; uint32_t read_header_length, name_length, number_of_bases; uint32_t clip_qual_left, clip_qual_right, clip_adapter_left; uint32_t clip_adapter_right, read_data_length, eight_byte_padding; uint32_t enc_value, clip_left, clip_right, index_mft_length; uint64_t index_offset, cur_offset, index_idx_length; float leftCut, rightCut, sig, flowgram[10000]; char *s, seq[10000], szReadName[100]; unsigned char buf[50000]; char runName[1000], analysisName[1000], runPath[1000], flowChars[1000]; char accnoTime[1000], accnoXY[1000]; unsigned char *indexBuf; FILE* fpSFF; char szSffFileWithoutPath[1000]; fpSFF = fopen( szSffFileFullPath, "r" ); if ( !fpSFF ) { fprintf( stderr, "fatal: could not open sff file %s due to error %s (%d)\n", szSffFileFullPath, strerror( errno ), errno ); exit( -1 ); } fprintf( stderr, "Now processing sff file %s\n", szSffFileFullPath ); getBasename( szSffFileFullPath, szSffFileWithoutPath ); accnoMode = 0; numManifest = 0; outputMode = TEXT_MODE; trimMode = 1; tabMode = 0; /* * Read the beginning of the common header, check that the magic number * is 0x2E736666 and the version string is "\0\0\0\1", then extract the * other fields of the header, read the flow_chars and key_sequence * strings, then output the text information in the common header. */ getBytes(fpSFF, 31, buf, szSffFileFullPath); magic_number = getuint32(buf); if (magic_number != SFF_MAGIC_NUMBER) { fprintf(stderr, "Error: File is not an SFF file: %s\n", szSffFileFullPath); exit(-1); } if (strncmp(( (char*)buf) + 4, SFF_VERSION, 4) != 0) { fprintf(stderr, "Error: Unsupported SFF file version number.\n"); exit(-1); } index_offset = getuint64(buf+8); index_length = getuint32(buf+16); number_of_reads = getuint32(buf+20); aArrayOfReads.resize( number_of_reads ); fprintf( stderr, "number_of_reads = %d\n", number_of_reads ); header_length = getuint16(buf+24); key_length = getuint16(buf+26); number_of_flows_per_read = getuint16(buf+28); flowgram_format_code = getuint8(buf+30); if (flowgram_format_code != 1) { fprintf(stderr, "Error: Invalid flowgram_format_code: %d\n", flowgram_format_code); exit(-1); } flowgram_bytes = 2; getBytes(fpSFF, header_length - 31, buf + 31, szSffFileFullPath); strncpy(flowChars, (char*)buf + 31, number_of_flows_per_read); flowChars[number_of_flows_per_read] = '\0'; /* /* */ /* * Print out the text version of the common header. */ /* */ /* if (outputMode == TEXT_MODE) { */ /* printf("Common Header:\n"); */ /* printf(" Magic Number: 0x2E736666\n"); */ /* printf(" Version: %c%c%c%c\n", */ /* buf[4] + '0', buf[5] + '0', buf[6] + '0', buf[7] + '0'); */ /* printf(" Index Offset: %ld\n", (long) index_offset); */ /* printf(" Index Length: %d\n", index_length); */ /* printf(" # of Reads: %d\n", number_of_reads); */ /* printf(" Header Length: %d\n", header_length); */ /* printf(" Key Length: %d\n", key_length); */ /* printf(" # of Flows: %d\n", number_of_flows_per_read); */ /* printf(" Flowgram Code: %d\n", flowgram_format_code); */ /* pos = 31; */ /* printf(" Flow Chars: "); */ /* for (i=0; i < number_of_flows_per_read; i++) { */ /* fputc(buf[pos++], stdout); */ /* } */ /* fputc('\n', stdout); */ /* printf(" Key Sequence: "); */ /* for (i=0; i < key_length; i++) { */ /* fputc(buf[pos++], stdout); */ /* } */ /* fputc('\n', stdout); */ /* fflush(stdout); */ /* } */ /* * Read the index, if there are accno's on the command line, the index * exists and is the ".srt" or ".mft" format. */ indexMode = 0; indexSize = 0; indexBuf = NULL; fileMode = 1; if ( fileMode && index_length > 0) { fseek(fpSFF, index_offset, SEEK_SET); getBytes(fpSFF, 8, buf, szSffFileFullPath); magic_number = getuint32(buf); if (magic_number == MANIFEST_INDEX_MAGIC_NUMBER && strncmp( (char*)buf+4, INDEX_VERSION, 4) == 0) { getBytes(fpSFF, 8, buf, szSffFileFullPath); index_mft_length = getuint32(buf); index_idx_length = getuint32(buf+4); } else if (magic_number == SORT_INDEX_MAGIC_NUMBER && strncmp( (char*) buf+4, INDEX_VERSION, 4) == 0) { index_mft_length = 0; index_idx_length = index_length - 8; } else { index_mft_length = 0; index_idx_length = 0; } if (index_mft_length > 0) { if (outputMode == TEXT_MODE || outputMode == MANIFEST_MODE) { indexBuf = (unsigned char*) malloc(index_mft_length + 1); if (indexBuf == NULL) { fprintf(stderr, "Error: Ran out of memory.\n"); exit(-1); } getBytes(fpSFF, index_mft_length, indexBuf, szSffFileFullPath); indexBuf[index_mft_length] = '\0'; parseManifest( (char*) indexBuf); /* if (outputMode == MANIFEST_MODE) { */ /* fwrite(indexBuf, 1, index_mft_length, stdout); */ /* return 0; */ /* } */ free(indexBuf); indexBuf = NULL; } else { fseek(fpSFF, index_mft_length, SEEK_CUR); } } /* else if (outputMode == MANIFEST_MODE) { */ /* printf("No manifest found.\n"); */ /* return 0; */ /* } */ if (accnoMode) { if (index_idx_length > 0) { indexBuf = (unsigned char*) malloc(index_idx_length); if (indexBuf == NULL) { fprintf(stderr, "Error: Ran out of memory.\n"); exit(-1); } getBytes(fpSFF, index_idx_length, indexBuf, szSffFileFullPath); indexSize = index_idx_length; while (indexSize > 0 && indexBuf[indexSize-1] == '\0') { indexSize--; } indexMode = 1; } else { fprintf(stderr, "Warning: Unsupported index format. Scanning file...\n"); } } fseek(fpSFF, header_length, SEEK_SET); } /* * Either scan the entire file, or skip from entry to entry to access * the necessary entries. */ number_reads_found = 0; if (!indexMode) { cur_offset = header_length; /* argnum = argc; */ } else { cur_offset = header_length; /* argnum = firstarg; */ } while (1) { /* * If the current file pointer is at the beginning of the index, * skip the index section, or write the manifest. */ if (cur_offset == index_offset) { if (fileMode) { fseek(fpSFF, index_length, SEEK_CUR); } else { indexBuf = (unsigned char*) malloc(index_length); if (indexBuf == NULL) { fprintf(stderr, "Error: Ran out of memory.\n"); exit(-1); } getBytes(fpSFF, index_length, indexBuf, szSffFileFullPath); /* if (outputMode == MANIFEST_MODE) { */ /* magic_number = getuint32(buf); */ /* if (magic_number == MANIFEST_INDEX_MAGIC_NUMBER && */ /* strncmp(buf+4, INDEX_VERSION, 4) == 0) { */ /* index_mft_length = getuint32(buf+8); */ /* s = buf+16; */ /* fwrite(s, 1, index_mft_length, stdout); */ /* } else { */ /* printf("No manifest found.\n"); */ /* } */ /* return 0; */ /* } */ } cur_offset += index_length; } /* * Read the next 16 bytes of the next entry, * and check for end of file. */ if (fread(buf, 1, 16, fpSFF) != 16) { break; } /* } */ /* else { */ /* if (argnum == argc) { */ /* break; */ /* } */ /* /* */ /* * Lookup the accno in the index, and set the file pointer to */ /* * the file location. */ /* */ /* cur_offset = lookupAccno(argv[argnum], indexBuf, indexSize); */ /* if (cur_offset == 0) { */ /* fprintf(stderr, */ /* "Error: Sequence %s does not exist in SFF file.\n", */ /* argv[argnum]); */ /* argnum++; */ /* continue; */ /* } */ /* fseek(fpSFF, cur_offset, SEEK_SET); */ /* getBytes(fpSFF, 16, buf, szSffFileFullPath); */ /* argnum++; */ /* } */ /* * Parse the initial read header bytes, and read the rest of the * read header. */ read_header_length = getuint16(buf); name_length = getuint16(buf+2); number_of_bases = getuint32(buf+4); clip_qual_left = getuint16(buf+8); clip_qual_right = getuint16(buf+10); clip_adapter_left = getuint16(buf+12); clip_adapter_right = getuint16(buf+14); getBytes(fpSFF, read_header_length - 16, buf + 16, szSffFileFullPath); strncpy(szReadName, (char*)buf + 16, name_length); szReadName[name_length] = '\0'; cur_offset += read_header_length; /* /* */ /* * If accnos are specified, but no index is available, check to */ /* * see if this entry is in the list. */ /* */ /* if (accnoMode && !indexMode) { */ /* for (i=firstarg; i < argc; i++) { */ /* if (strcmp(argv[i], name) == 0) { */ /* break; */ /* } */ /* } */ /* if (i == argc) { */ /* continue; */ /* } */ /* } */ /* * Read the read data section. */ read_data_length = number_of_flows_per_read * flowgram_bytes + number_of_bases * 3; eight_byte_padding = (read_data_length % 8 > 0 ? 8 - read_data_length % 8 : 0); getBytes(fpSFF, read_data_length + eight_byte_padding, buf, szSffFileFullPath); cur_offset += read_data_length + eight_byte_padding; // added April 2010 for selected reads if ( bWantOnlyCertainReads ) { RWCString soReadName( szReadName ); if ( !aDesiredReads.bContains( soReadName ) ) { continue; } } // end new section /* if (outputMode != ACCNO_MODE) { */ offset = 0; for (i=0; i < number_of_flows_per_read; i++) { enc_value = getuint16(buf + offset); flowgram[i] = enc_value * 1.0 / 100.0; offset += flowgram_bytes; } prevIndex = 0; for (i=0; i < number_of_bases; i++) { flowIndex[i] = prevIndex + getuint8(buf + offset); prevIndex = flowIndex[i]; offset++; } for (i=0; i < number_of_bases; i++) { seq[i] = buf[offset]; offset++; } for (i=0; i < number_of_bases; i++) { scores[i] = getuint8(buf + offset); offset++; } /* } */ /* * Compute the left and right clip points. */ clip_left = 1; clip_left = (clip_qual_left > clip_left ? clip_qual_left : clip_left); clip_left = (clip_adapter_left > clip_left ? clip_adapter_left : clip_left); clip_right = number_of_bases; if (clip_qual_right > 0 && clip_qual_right < clip_right) { clip_right = clip_qual_right; } if (clip_adapter_right > 0 && clip_adapter_right < clip_right) { clip_right = clip_adapter_right; } /* * Print out the read information. */ uaccnoFlag = getUAccnoInfo(szReadName, accnoTime, &accnoRegionId, accnoXY); basesAndQualitiesAndPeaks* pSeq = new basesAndQualitiesAndPeaks(); pSeq->soSequenceName_ = szReadName; aArrayOfReads.insert( pSeq ); pSeq->n1ClipLeft_ = clip_left; pSeq->n1ClipRight_ = clip_right; pSeq->soBases_.increaseMaxLength( number_of_bases ); pSeq->aQualities_.resize( number_of_bases ); // pLittlePeakPositions_ can be used for positions up to size // about 32,000 which corresponds (since each base takes about // 19 positions), up to about 1700 bases. 454 reads might // someday be this large so let's be smart about whether we // use pLittlePeakPositions_ or pBigPeakPositions_ pSeq->createPointPosArray( true, // bFoundTraceArrayMaxIndex, // well, we don't really know // nTraceArrayMaxIndex_ but we have // a pretty good estimate: ( number_of_bases - 1 ) * 19 + 15 + 100, // this is the largest peak position // + 100 for good measure number_of_bases, // nInitialSizeOfArray false ); // bFillUpArray for( i = 0; i < number_of_bases; i++ ) { pSeq->soBases_.append( tolower( seq[i] ) ); pSeq->aQualities_.append( scores[i] ); pSeq->appendPointPos( i * 19 + 15 ); } // numSamples = number_of_bases * 19 + 12 from studying // sff2scf.c pSeq->nTraceArrayMaxIndex_ = number_of_bases * 19 + 11; number_reads_found++; if ( number_reads_found % 10000 == 0 ) { cerr << "."; cerr.flush(); } } /* while (1) { */ fclose(fpSFF); /* * Check to make sure the file contains the correct number of reads. */ if (!bWantOnlyCertainReads && !indexMode && number_reads_found != number_of_reads) { fprintf(stderr, "Error: Number of reads found in SFF file does not equal number_of_reads field.\n"); exit(-1); } /* return 0; */ } /* void readOneSffFile( char* szSffFileFullPath... */ /* * parseManifest * * Scan the manifest text for the run information. */ void parseManifest(char *buf) { char *s, *s2, *s3, *s4, *t, accnoPrefix[1000], runName[1000]; char analysisName[1000], runPath[1000]; s = buf; while ((s2 = strstr(s, "")) && (s4 = strstr(s2, ""))) { *s4 = '\0'; accnoPrefix[0] = '\0'; runName[0] = '\0'; analysisName[0] = '\0'; runPath[0] = '\0'; if ((s3 = strstr(s2, ""))) { s3 += 18; for (t=accnoPrefix; *s3 && strncmp(s3, ""))) { s3 += 10; for (t=runName; *s3 && strncmp(s3, "", 11) != 0; s3++,t++) { *t = *s3; } *t = '\0'; } if ((s3 = strstr(s2, ""))) { s3 += 15; for (t=analysisName; *s3 && strncmp(s3, ""))) { s3 += 6; for (t=runPath; *s3 && strncmp(s3, "", 7) != 0; s3++,t++) { *t = *s3; } *t = '\0'; } if (runPath[0] != '\0') { if (accnoPrefix[0] != '\0') { manifestList[numManifest].accnoPrefix = strdup(accnoPrefix); } if (runName[0] != '\0') { manifestList[numManifest].runName = strdup(runName); } if (analysisName[0] != '\0') { manifestList[numManifest].analysisName = strdup(analysisName); } manifestList[numManifest].runPath = strdup(runPath); numManifest++; } *s4 = '<'; s = s4 + 1; } } /* * getManifestInfo * * Return the run information for an accno from the manifest. */ int getManifestInfo(char *accno, char *runNameOut, char *analysisNameOut, char *runPathOut) { int i; if (numManifest == 0) { return 0; } if (numManifest == 1) { i = 0; } else { for (i=0; i < numManifest; i++) { if (manifestList[i].accnoPrefix != NULL && strncmp(accno, manifestList[i].accnoPrefix, strlen(manifestList[i].accnoPrefix)) == 0) { break; } } if (i == numManifest) { return 0; } } runNameOut[0] = '\0'; analysisNameOut[0] = '\0'; runPathOut[0] = '\0'; if (manifestList[i].runName != NULL) { strcpy(runNameOut, manifestList[i].runName); } if (manifestList[i].analysisName != NULL) { strcpy(analysisNameOut, manifestList[i].analysisName); } if (manifestList[i].runPath != NULL) { strcpy(runPathOut, manifestList[i].runPath); } return 1; } /* * lookupAccno * * Search through the index looking for the given accno, and either * returning the associated file offset, or 0 if the accno cannot be found. */ unsigned int lookupAccno(char *accno, unsigned char *indexBuf, int indexSize) { int start, end, mid, val; unsigned int offset; unsigned char *us; /* * Perform a binary search of the index, stopping when the search * region becomes relatively small. This assumes that no accession * number is near 200 characters. */ start = 0; end = indexSize; while (end - start > 200) { mid = (start + end) / 2; /* * From the byte midpoint, scan backwards to the beginning of the * index record that covers that byte midpoint. */ while (mid > start && indexBuf[mid-1] != 255) { mid--; } val = strcmp(accno, ((char*)indexBuf ) +mid); if (val == 0) { break; } else if (val < 0) { end = mid; } else { start = mid; } } /* * Scan through the small search region, looking for the accno. */ while (start < end) { if (strcmp(accno, (char*)indexBuf+start) == 0) { /* * If the accno is found, skip the accno characters, * then get the record offset. */ for (us=indexBuf+start; *us; us++,start++) ; us++; start++; offset = getuint4_255(us); if (us[4] != 255) { fprintf(stderr, "Error: Invalid TVF index format.\n"); exit(1); } return offset; } /* * Skip to the beginning of the next index element. */ while (start < end && indexBuf[start] != 255) { start++; } start++; } return 0; } /* * getUAccnoInfo * * Extract the run timestamp and the XY position information from * a universal accno. */ int getUAccnoInfo(char *accno, char *timeOut, int *regionOut, char *xyOut) { int i, chval; unsigned int total; if (strlen(accno) != 14) { return 0; } for (i=0; i < 14; i++) { if (i == 0) { if (!isalpha(accno[i])) { return 0; } } else if (i == 7 || i == 8) { if (!isdigit(accno[i])) { return 0; } } else { if (!isalnum(accno[i])) { return 0; } } } total = ((unsigned int) 0); for (i=0; i < 6; i++) { if (isalpha(accno[i])) { chval = ((int) toupper(accno[i])) - ((int) 'A'); } else if (isdigit(accno[i])) { chval = 26 + ((int) accno[i]) - ((int) '0'); } else { return 0; } if (chval < 0 || chval >= 36) { return 0; } total = total * ((unsigned int) 36) + ((unsigned int) chval); } sprintf(timeOut, "R_%04d_%02d_%02d_%02d_%02d_%02d_", 2000 + total / (13 * 32 * 24 * 60 * 60), (total / (32 * 24 * 60 * 60)) % 13, (total / (24 * 60 * 60)) % 32, (total / (60 * 60)) % 24, (total / 60) % 60, total % 60); *regionOut = (((int) accno[7]) - ((int) '0')) * 10 + (((int) accno[8]) - ((int) '0')); total = ((unsigned int) 0); for (i=9; i < 14; i++) { if (isalpha(accno[i])) { chval = ((int) toupper(accno[i])) - ((int) 'A'); } else if (isdigit(accno[i])) { chval = 26 + ((int) accno[i]) - ((int) '0'); } else { return 0; } if (chval < 0 || chval >= 36) { return 0; } total = total * ((unsigned int) 36) + ((unsigned int) chval); } sprintf(xyOut, "%04d_%04d", (total / 4096) % 4096, total % 4096); return 1; } /* * prefixCheck * * Compare two strings are report that they are equal if they match to * the end of one of the two, and the length is at least minlen chars. */ int prefixCheck(char *s, char *t, int minlen) { int i; for (i=0; *s && *t; i++,s++,t++) { if (toupper(*s) != toupper(*t)) { break; } } return ((!*s || !*t) && i >= minlen); } /* * getBytes * * Read a region of the file of length size into * the buffer specified by buf. */ void getBytes(FILE *fpSFF, unsigned int size, unsigned char *buf, char *filename) { int numread, numleft, bytes; numread = 0; numleft = size; while (numleft > 0) { bytes = fread(buf+numread, 1, numleft, fpSFF); if (bytes <= 0) { fprintf(stderr, "Error: Unable to read SFF file: %s\n", filename); exit(-1); } numread += bytes; numleft -= bytes; } } /* * getuint8 * * A function to convert a 1-byte value into an integer. */ uint32_t getuint8(unsigned char *b) { return ((uint32_t) b[0]); } /* * getuint16 * * A function to convert a big endian 2-byte value into an integer. */ uint32_t getuint16(unsigned char *b) { return ((uint32_t) b[0]) * 256 + ((uint32_t) b[1]); } /* * getuint32 * * A function to convert a big endian 4-byte value into an integer. */ uint32_t getuint32(unsigned char *b) { return ((uint32_t) b[0]) * 256 * 256 * 256 + ((uint32_t) b[1]) * 256 * 256 + ((uint32_t) b[2]) * 256 + ((uint32_t) b[3]); } /* * getuint4_255 * * A function to convert a 4-byte index offset value into an integer, where * the bytes are base-255 numbers. This is used to store the index offsets. */ unsigned int getuint4_255(unsigned char *b) { return ((unsigned int) b[0]) * 255 * 255 * 255 + ((unsigned int) b[1]) * 255 * 255 + ((unsigned int) b[2]) * 255 + ((unsigned int) b[3]); } /* * getuint64 * * A function to convert a big endian 8-byte value into an integer. */ uint64_t getuint64(unsigned char *b) { return (((uint64_t) b[0]) << 56) + (((uint64_t) b[1]) << 48) + (((uint64_t) b[2]) << 40) + (((uint64_t) b[3]) << 32) + (((uint64_t) b[4]) << 24) + (((uint64_t) b[5]) << 16) + (((uint64_t) b[6]) << 8) + ((uint64_t) b[7]); } void removeTrailingWhitespace( char* szLine, int nInitialLength, int* pFinalLength ) { int nLength; nLength = nInitialLength - 1; while( nLength >= 0 && isspace( szLine[ nLength ] ) ) { --nLength; } szLine[ nLength + 1 ] = 0; *pFinalLength = nLength + 1; } void getBasename( char* szFullPath, char* szBasename ) { int nLength; int nSlashPosition; int n; nLength = strlen( szFullPath ); nSlashPosition = -1; for( n = nLength - 1; n >= 0; --n ) { if ( szFullPath[n] == '/' ) { nSlashPosition = n; break; } } /* allowing n to go to nLength makes it copy the null at the end */ for( n = nSlashPosition + 1; n <= nLength; ++n ) { szBasename[n - nSlashPosition - 1 ] = szFullPath[n]; } }