// // Copyright 1998-2004 by Craig Stuart Sapp, All Rights Reserved. // Programmer: Craig Stuart Sapp // Creation Date: Mon May 18 13:43:47 PDT 1998 // Last Modified: Wed Nov 29 10:24:29 PST 2000 split from HumdrumFile class // Last Modified: Wed Mar 21 17:38:23 PST 2001 added spine width feature // Last Modified: Thu Nov 15 12:38:49 PST 2001 added getTrackExInterp // Last Modified: Sat May 8 12:57:53 PDT 2004 fix complicated spine tracing // Last Modified: Wed Jun 2 15:19:57 PDT 2004 fix fix in spine trace ! lines // Last Modified: Fri Apr 24 15:01:35 PDT 2009 fixed contructor with char* // Last Modified: Wed Apr 29 17:14:44 PDT 2009 fixed *x bug in dot analysis // Last Modified: Mon May 4 12:11:13 PDT 2009 fixed new? bug in dot analysis // Last Modified: Fri Jun 12 22:58:34 PDT 2009 renamed SigCollection class // Last Modified: Mon Jun 22 15:03:44 PDT 2009 added Humdrum/Http URIs // Last Modified: Wed Sep 2 21:48:23 PDT 2009 fixed problem with *x again // Last Modified: Wed May 12 22:29:42 PDT 2010 added embedded PDF parsing // Last Modified: Mon Feb 14 08:14:53 PST 2011 added VTS functions // Last Modified: Tue Apr 24 16:37:34 PDT 2012 added jrp:// URI // Last Modified: Tue Dec 11 17:23:04 PST 2012 added fileName, segmentLevel // Last Modified: Mon Apr 1 16:44:32 PDT 2013 added printNonemptySegmentLevel // Filename: ...sig/src/sigInfo/HumdrumFileBasic.cpp // Web Address: http://sig.sapp.org/src/sigInfo/HumdrumFileBasic.cpp // Syntax: C++ // // Description: Basic parsing functions for handling a Humdrum data file. // Special musical parsing of the Humdrum file is done in // the inherited class HumdrumFile. // #include "Convert.h" #include "HumdrumFileBasic.h" #include "PDFFile.h" #include "CheckSum.h" #include #include #include #include #ifndef OLDCPP #include #include using namespace std; #else #include #include #endif char HumdrumFileBasic::empty[1] = {0}; /////////////////////////////////////////////////////////////////////////// // // HumdrumFileAddress class // ////////////////////////////// // // HumdrumFileAddress::HumdrumFileAddress -- // HumdrumFileAddress::HumdrumFileAddress(void) { // do nothing (address has uninitialized concents) } HumdrumFileAddress::HumdrumFileAddress(int aLine) { address[0] = 0; address[1] = aLine; address[2] = 0; address[3] = 0; } HumdrumFileAddress::HumdrumFileAddress(int aLine, int aField) { address[0] = 0; address[1] = aLine; address[2] = aField; address[3] = 0; } HumdrumFileAddress::HumdrumFileAddress(int aLine, int aField, int aSubfield) { address[0] = 0; address[1] = aLine; address[2] = aField; address[3] = aSubfield; } HumdrumFileAddress::HumdrumFileAddress(const HumdrumFileAddress& anAddress) { address[0] = 0; address[1] = anAddress.address[0]; address[2] = anAddress.address[1]; address[3] = anAddress.address[2]; } ////////////////////////////// // // HumdrumFileAddress::~HumdrumFileAddress -- // HumdrumFileAddress::~HumdrumFileAddress() { // do nothing } ////////////////////////////// // // HumdrumFileAddress::line -- Return the line in the Humdrum file. // int& HumdrumFileAddress::line(void) { return address[1]; } int& HumdrumFileAddress::getLine(void) { return address[1]; } int& HumdrumFileAddress::row(void) { return address[1]; } int& HumdrumFileAddress::getRow(void) { return address[1]; } int& HumdrumFileAddress::i(void) { return address[1]; } ////////////////////////////// // // HumdrumFileAddress::field -- Returns the column on the line. // int& HumdrumFileAddress::field(void) { return address[2]; } int& HumdrumFileAddress::getField(void) { return address[2]; } int& HumdrumFileAddress::column(void) { return address[2]; } int& HumdrumFileAddress::getColumn(void) { return address[2]; } int& HumdrumFileAddress::col(void) { return address[2]; } int& HumdrumFileAddress::getCol(void) { return address[2]; } int& HumdrumFileAddress::j(void) { return address[2]; } ////////////////////////////// // // HumdrumFileAddress::subfield -- // int& HumdrumFileAddress::subfield(void) { return address[3]; } int& HumdrumFileAddress::getSubfield(void) { return address[3]; } int& HumdrumFileAddress::subtoken(void) { return address[3]; } int& HumdrumFileAddress::getSubtoken(void) { return address[3]; } int& HumdrumFileAddress::k(void) { return address[3]; } ////////////////////////////// // // HumdrumFileAddress::zero -- Set all address components to 0. // void HumdrumFileAddress::zero(void) { address[0] = 0; address[1] = 0; address[2] = 0; address[3] = 0; } ////////////////////////////// // // HumdrumFileAddress::operator= -- // HumdrumFileAddress HumdrumFileAddress::operator=(const HumdrumFileAddress& anAddress) { if (this == &anAddress) { return *this; } address[0] = anAddress.address[0]; address[1] = anAddress.address[1]; address[2] = anAddress.address[2]; address[3] = anAddress.address[3]; return *this; } ////////////////////////////// // // HumdrumFileAddress::setLineField -- // void HumdrumFileAddress::setLineField(int aLine, int aField) { line() = aLine; field() = aField; } /////////////////////////////////////////////////////////////////////////// // // HumdrumFileBasic class // ////////////////////////////// // // HumdrumFileBasic::HumdrumFileBasic // HumdrumFileBasic::HumdrumFileBasic(void) { records.setSize(100000); // initial storage size 100000 lines records.setSize(0); records.allowGrowth(); records.setGrowth(1000000); // grow in increments of 1000000 lines maxtracks = 0; segmentLevel = 0; } HumdrumFileBasic::HumdrumFileBasic(const HumdrumFileBasic& aHumdrumFileBasic) { records.setSize(100000); // initial storage size 100000 lines records.setSize(0); records.allowGrowth(); records.setGrowth(1000000); // grow in increments of 1000000 lines maxtracks = 0; segmentLevel = 0; *this = aHumdrumFileBasic; } HumdrumFileBasic::HumdrumFileBasic(const char* filename) { records.setSize(100000); // initial storage size 100000 lines records.setSize(0); records.allowGrowth(); records.setAllocSize(1000000); // grow in increments of 1000000 lines maxtracks = 0; segmentLevel = 0; ifstream infile(filename, ios::in); if (!infile) { cerr << "Error: cannot open file: " << filename << endl; exit(1); } read(filename); /* char templine[4096]; while (!infile.eof()) { infile.getline(templine, 4096); if (infile.eof() && (strcmp(templine, "") == 0)) { break; } else { appendLine(templine); } } analyzeSpines(); analyzeDots(); */ } HumdrumFileBasic::HumdrumFileBasic(const string& filename) { records.setSize(100000); // initial storage size 100000 lines records.setSize(0); records.allowGrowth(); records.setAllocSize(1000000); // grow in increments of 1000000 lines maxtracks = 0; segmentLevel = 0; ifstream infile(filename.c_str(), ios::in); if (!infile) { cerr << "Error: cannot open file: " << filename << endl; exit(1); } read(filename); /* char templine[4096]; while (!infile.eof()) { infile.getline(templine, 4096); if (infile.eof() && (strcmp(templine, "") == 0)) { break; } else { appendLine(templine); } } analyzeSpines(); analyzeDots(); */ } //////////////////////////////////////// // // HumdrumFileBasic::setAllocation -- set the expected number of // lines from the input file. // void HumdrumFileBasic::setAllocation(int allocation) { if (allocation <= 0) { return; } if (allocation > 10000000) { return; } int currentsize = records.getSize(); if (currentsize < allocation) { records.setSize(allocation); records.setSize(currentsize); records.setAllocSize(allocation); } } ////////////////////////////// // // HumdrumFileBasic::~HumdrumFileBasic // HumdrumFileBasic::~HumdrumFileBasic() { clear(); } ////////////////////////////// // // HumdrumFileBasic::analyzeSpines -- // void HumdrumFileBasic::analyzeSpines(void) { privateSpineAnalysis(); } ////////////////////////////// // // HumdrumFileBasic::analyzeDots -- // void HumdrumFileBasic::analyzeDots(void) { privateDotAnalysis(); } ////////////////////////////// // // HumdrumFileBasic::appendLine -- adds a line to a humdrum file // void HumdrumFileBasic::appendLine(const char* aLine) { HumdrumRecord* aRecord; aRecord = new HumdrumRecord; aRecord->setLine(aLine); records[records.getSize()] = aRecord; } void HumdrumFileBasic::appendLine(HumdrumRecord& aRecord) { HumdrumRecord *tempRecord; tempRecord = new HumdrumRecord; *tempRecord = aRecord; records[records.getSize()] = tempRecord; } void HumdrumFileBasic::appendLine(HumdrumRecord* aRecord) { appendLine(*aRecord); } ////////////////////////////// // // HumdrumFileBasic::clear -- removes all lines from the humdrum file // void HumdrumFileBasic::clear(void) { int i; for (i=0; i 0) { printSegmentLabel(out); } return out; } ////////////////////////////// // // HumdrumFileBasic::getSegmentLevel -- return the segment level // int HumdrumFileBasic::getSegmentLevel(void) { return segmentLevel; } ////////////////////////////// // // HumdrumFileBasic::setSegmentLevel -- return the segment level // void HumdrumFileBasic::setSegmentLevel(int level) { segmentLevel = level; } ////////////////////////////// // // HumdrumFileBasic::extract -- // HumdrumFileBasic HumdrumFileBasic::extract(int aField) { int fieldNumber = aField; HumdrumRecord aRecord; HumdrumFileBasic output; for (int i=0; igetType()) { case E_humrec_data: case E_humrec_data_comment: case E_humrec_data_kern_measure: case E_humrec_data_interpretation: if (aField < 0) { fieldNumber = records[i]->getFieldCount() + aField; if (fieldNumber < 0) { fieldNumber = 0; } } else { fieldNumber = aField; } aRecord.setLine((*records[i])[fieldNumber]); aRecord.setExInterp(0, records[i]->getExInterpNum(fieldNumber)); output.appendLine(aRecord); break; case E_humrec_empty: output.appendLine(records[i]); break; case E_humrec_none: case E_humrec_global_comment: default: output.appendLine(records[i]); } } return output; } ////////////////////////////// // // HumdrumFileBasic::getNonNullAddress -- // void HumdrumFileBasic::getNonNullAddress(HumdrumFileAddress& add) { HumdrumFileBasic& afile = *this; if (strcmp(afile[add], ".") != 0) { return; } int i = afile[add.line()].getDotLine(add.field()); int j = afile[add.line()].getDotField(add.field()); add.line() = i; add.field() = j; } /////////////////////////////// // // HumdrumFileBasic::getDotValue -- // const char* HumdrumFileBasic::getDotValue(int index, int spinei) { int line = (*this)[index].getDotLine(spinei); int spine = (*this)[index].getDotSpine(spinei); if (line < 0 || spine < 0) { return HumdrumFileBasic::empty; } else { return (*this)[line][spine]; } } ////////////////////////////// // // HumdrumFileBasic::getMaxTracks -- // int HumdrumFileBasic::getMaxTracks(void) { return maxtracks; } ////////////////////////////// // // HumdrumFileBasic::getTrackExInterp -- // string HumdrumFileBasic::getTrackExInterp(int track) { return trackexinterp[track-1]; } ////////////////////////////// // // HumdrumFileBasic::getTracksByExInterp -- return a list of track numbers // which have the matching exclusive interpretation type. // int HumdrumFileBasic::getTracksByExInterp(Array& tracks, const string& exinterp) { int maxsize = getMaxTracks(); tracks.setSize(maxsize); tracks.setSize(0); int i; for (i=0; i<(int)trackexinterp.size(); i++) { if (trackexinterp[i] == exinterp) { tracks.append(i); tracks.last()++; } else if (strcmp(trackexinterp[i].c_str()+2, exinterp.c_str()) == 0) { tracks.append(i); tracks.last()++; } } return tracks.getSize(); } int HumdrumFileBasic::getTracksByExInterp(vector& tracks, const string& exinterp) { int maxsize = getMaxTracks(); tracks.reserve(maxsize); tracks.resize(0); int i; for (i=0; i<(int)trackexinterp.size(); i++) { if (trackexinterp[i] == exinterp) { tracks.push_back(i); tracks.back()++; } else if (strcmp(trackexinterp[i].c_str()+2, exinterp.c_str()) == 0) { tracks.push_back(i); tracks.back()++; } } return tracks.size(); } ////////////////////////////// // // HumdrumFileBasic::getKernTracks -- // int HumdrumFileBasic::getKernTracks(Array& tracks) { return getTracksByExInterp(tracks, "**kern"); } int HumdrumFileBasic::getKernTracks(vector& tracks) { return getTracksByExInterp(tracks, "**kern"); } ////////////////////////////// // // HumdrumFileBasic::getType -- returns the enumerated type of the record. // int HumdrumFileBasic::getType(int index) { return (*this)[index].getType(); } ////////////////////////////// // // HumdrumFileBasic::getLine -- returns the character string of the // specified line // const char* HumdrumFileBasic::getLine(int index) { if (index >= getNumLines()) { cerr << "Error: maximum line index is: " << getNumLines() - 1 << ", but you asked for line index: " << index << endl; exit(1); } return records[index]->getLine(); } ////////////////////////////// // // HumdrumFileBasic::getBibValue -- add an optional parameter later which // selects the nth occurance of the bibliographic key. // const char* HumdrumFileBasic::getBibValue(char* buffer, const char* key) { int i; buffer[0] = '\0'; HumdrumFileBasic& hfile = *this; char newkey[1024] = {0}; if (strncmp(key, "!!!", 3) == 0) { strcpy(newkey, key); } else { strcpy(newkey, "!!!"); strcat(newkey, key); } for (i=0; i= getNumLines()) { cerr << "Error: maximum line index is: " << getNumLines() - 1 << ", but you asked for line index: " << index << endl; exit(1); } return *records[index]; } ////////////////////////////// // // HumdrumFileBasic::getSegmentCount -- will eventually return the // number of independent musical segments (which each start with // /^\*\*/ and end with /^\*-/). // // also later, add a function called getSegmentStart(int index) which // returns the staring index in the file for the segment. // int HumdrumFileBasic::getSegmentCount(void) { return 1; } ////////////////////////////// // // HumdrumFileBasic::getSpineCount -- returns the record of the specified line // int HumdrumFileBasic::getSpineCount(int index) { int type = ((*this)[index]).getType(); if ((type & E_humrec_data) == E_humrec_data) { return ((*this)[index]).getFieldCount(); } else { return 0; } } ////////////////////////////// // // HumdrumFileBasic::operator= // HumdrumFileBasic& HumdrumFileBasic::operator=(const HumdrumFileBasic& aFile) { // don't copy onto self if (&aFile == this) { return *this; } // delete any current contents int i; for (i=0; igetType()) { case E_humrec_data: for (j=0; jgetFieldCount(); j++) { if (strcmp((*records[i])[j], ".") != 0) { nulltest = 0; break; } } if (nulltest) { // do nothing } else { output.appendLine(records[i]); } break; default: output.appendLine(records[i]); } } return output; } ////////////////////////////// // // HumdrumFileBasic::operator[] // HumdrumRecord& HumdrumFileBasic::operator[](int index) { if (index >= getNumLines()) { cerr << "Error: maximum line index is: " << getNumLines() - 1 << ", but you asked for line index: " << index << endl; exit(1); } return *records[index]; } const char* HumdrumFileBasic::operator[](HumdrumFileAddress& add) { return (*this)[add.line()][add.field()]; } ////////////////////////////// // // HumdrumFileBasic::write -- write out a humdrum file. // void HumdrumFileBasic::write(const char* filename) { #ifndef OLDCPP ofstream outfile(filename, ios::out); #else ofstream outfile(filename, ios::out | ios::noreplace); #endif if (!outfile) { cerr << "Error: could not open file for writing: " << filename << endl; cerr << "Perhaps it already exists?" << endl; exit(1); } for (int i=0; igetLine() << endl; } } void HumdrumFileBasic::write(ostream& outStream) { for (int i=0; igetLine() << endl; } } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // operator<< // ostream& operator<<(ostream& out, HumdrumFileBasic& aHumdrumFileBasic) { aHumdrumFileBasic.printNonemptySegmentLabel(out); for (int i=0; i spineinfo; vector exinterps; spineinfo.reserve(1000); exinterps.reserve(100); exinterps.resize(1); exinterps[0] = 0; int currentwidth = 0; int prediction = 0; int i, n; int type; char buffer[1024] = {0}; string bp; trackexinterp.clear(); trackexinterp.reserve(100); int linecount = getNumLines(); for (n=0; n= linecount) && prediction != 0) { cerr << "Error in termination of humdrum data" << endl; } ((*this)[n]).copySpineInfo(spineinfo, n+1); makeNewSpineInfo(spineinfo, ((*this)[n]), prediction, spineid, exinterps); if (prediction == 0) { init = 0; } } else { // plain tandem interpretation if (init == 0) { cerr << "Error on first line of data: no starting interpretation" << endl; exit(1); } ((*this)[n]).copySpineInfo(spineinfo, n+1); (*this)[n].setSpineWidth(currentwidth); } } else { // do nothing: global comment, bibliography information, or null line (*this)[n].setSpineWidth(currentwidth); } } spineinfo.clear(); // provide Exclusive Interpretations ownerships to the record spines int spineindex; linecount = getNumLines(); int m; const char* ptr; for (n=0; n& spineinfo, HumdrumRecord& aRecord, int newsize, int& spineid, vector& ex) { vector newinfo; newinfo.resize(newsize); int i, j; int spinecount = aRecord.getFieldCount(); int subcount; int inindex = 0; int outindex = 0; for (inindex=0; inindex 1) { newinfo[outindex] += " "; newinfo[outindex] += spineinfo[inindex+subcount-1]; simplifySpineString(newinfo[outindex]); } } else { break; } } if (subcount == 1) { cout << "Error: single *v path indicator on line: " << aRecord.getLineNum() << "\n" << aRecord.getLine() << endl; exit(1); } else { inindex += subcount-1; } // check to see if the spine info can be simplified: simplifySpineInfo(newinfo, outindex); outindex++; } else if (strncmp("**", aRecord[inindex], 2) == 0) { int value; value = Convert::exint.getValue(aRecord[inindex]); if (spineid != (int)ex.size()) { cout << "Error in exclusive interpretation allocation" << endl; exit(1); } if (value == E_unknown) { value = Convert::exint.add(aRecord[inindex]); ex.push_back(value); } else { ex.push_back(value); } newinfo[outindex] = spineinfo[inindex]; outindex++; } else { newinfo[outindex] = spineinfo[inindex]; outindex++; } } if (outindex != (int)newinfo.size()) { cout << "Error in HumdrumFileBasic path parsing" << endl; exit(1); } if (inindex != (int)spineinfo.size()) { cout << "Error in HumdrumFileBasic path parsing" << endl; exit(1); } // delete the old information: spineinfo.clear(); // copy the new spine path indicators spineinfo.resize(newinfo.size()); for (i=0; i<(int)spineinfo.size(); i++) { spineinfo[i] = newinfo[i]; } newinfo.clear(); } ////////////////////////////// // // HumdrumFileBasic::simplifySpineString -- // function added Sat May 8 12:57:37 PDT 2004 // void HumdrumFileBasic::simplifySpineString(string& spinestring) { int length = (int)spinestring.size(); if (spinestring[length-1] == ' ') { spinestring.resize(length-1); } if (strchr(spinestring.c_str(), ' ') == NULL) { // no multiple sources, so already in simplest form return; } if (strchr(spinestring.c_str(), '(') == NULL) { // no sub-spine data, so already in simplest form return; } char buffer[1024] = {0}; strcpy(buffer, spinestring.c_str()); Array ptrs; Array lengths; ptrs.setSize(100); ptrs.setGrowth(100); ptrs.setSize(0); lengths.setSize(100); lengths.setGrowth(100); lengths.setSize(0); char* ptr = strtok(buffer, " "); while (ptr != NULL) { ptrs.append(ptr); length = strlen(ptr); lengths.append(length); ptr = strtok(NULL, " "); } int i, j; int k; for (i=0; i& info, int index) { char* temp; int length; length = (int)info[index].size(); temp = new char[length + 1]; strcpy(temp, info[index].c_str()); int count = 0; int i; for (i=0; i 2 && len2 > 2) { p1[len1-2] = '\0'; p2[len2-2] = '\0'; if (strcmp(p1, p2) == 0) { info[index] = p1; } } } delete [] temp; } ////////////////////////////// // // HumdrumFileBasic::predictNewSpineCount -- // int HumdrumFileBasic::predictNewSpineCount(HumdrumRecord& aRecord) { int output = 0; int spinecount = aRecord.getFieldCount(); int subcount; int i; int j; for (i=0; i lastline; Array lastspine; int i, j; int count = 0; int newcount = 0; int length = (*this).getNumLines(); for (i=0; i& lastline, Array& lastspine, HumdrumRecord& record, int newsize) { Array newline; Array newspine; newline.setSize(newsize); newspine.setSize(newsize); newline.allowGrowth(0); newspine.allowGrowth(0); int i, j; for (i=0; i 1) { newline[outindex] = lastline[inindex+subcount-1]; newspine[outindex] = lastspine[inindex+subcount-1]; } } else { break; } } if (subcount == 1) { cout << "Error: single *v path indicator on line: " << record.getLineNum() << "\n" << record.getLine() << endl; exit(1); } else { inindex += subcount-1; } outindex++; } else if (strncmp("**", record[inindex], 2) == 0) { newline[outindex] = -1; newspine[outindex] = -1; outindex++; } else { newline[outindex] = lastline[inindex]; newspine[outindex] = lastspine[inindex]; outindex++; } } if (outindex != newline.getSize()) { cout << "Error in HumdrumFileBasic path parsing" << endl; exit(1); } if (inindex != lastline.getSize()) { cout << "Error in HumdrumFileBasic path parsing" << endl; exit(1); } // copy the new information lastline.setSize(newline.getSize()); lastspine.setSize(newspine.getSize()); for (i=0; i location; location.setSize(strlen(ptr)+1); location.allowGrowth(0); strcpy(location.getBase(), ptr); Array filename; filename.setSize(1); filename[0] = '\0'; filename.setSize(0); strcpy(location.getBase(), ptr); char* pot; if ((pot = strrchr(location.getBase(), '/')) != NULL) { *pot = '\0'; pot++; filename.setSize(strlen(pot)+1); strcpy(filename.getBase(), pot); filename.allowGrowth(0); } else { filename = location; location.setSize(2); strcpy(location.getBase(), "/"); } SSTREAM httprequest; httprequest << "https://" << "kern.humdrum.org"; if (strchr(filename.getBase(), '.') != NULL) { httprequest << "/cgi-bin/ksdata?file="; if (filename.getSize() > 0) { httprequest << filename.getBase(); } httprequest << "&l="; if (location.getSize() > 0) { httprequest << location.getBase(); } } else { httprequest << "/cgi-bin/ksdata?l="; if (location.getSize() > 0) { httprequest << location.getBase(); httprequest << "/"; httprequest << filename.getBase(); } } httprequest << "&format=kern"; httprequest << ends; strcpy(buffer, httprequest.CSTRING); return buffer; } if (strncmp(uri, "jrp://", strlen("jrp://")) == 0) { const char* ptr = uri; // skip over the staring portion of the address: if (strncmp(ptr, "jrp://", strlen("jrp://")) == 0) { ptr += strlen("jrp://"); } else if (strncmp(ptr, "jrp:", strlen("jrp:")) == 0) { ptr += strlen("jrp:"); } SSTREAM httprequest; httprequest << "https://" << "josquin.stanford.edu"; httprequest << "/cgi-bin/jrp?a=humdrum&f="; httprequest << ptr; httprequest << ends; strcpy(buffer, httprequest.CSTRING); return buffer; } // not familiar with the URI, just assume that it is a URL: strcpy(buffer, uri); return buffer; } #ifdef USING_URI ////////////////////////////// // // readFromHumdrumURI -- Read a Humdrum file from an humdrum:// web address // // Example: // maps: humdrum://osu/classical/haydn/london/sym099a.krn // into: // http://kern.humdrum.org/cgi-bin/ksdata?file=sym099a.krn&l=/osu/classical/haydn/london&format=kern // void HumdrumFileBasic::readFromHumdrumURI(const char* humdrumaddress) { cerr << "READING FROM HUMDRUM ADDRESS URI " << humdrumaddress << endl; const char* ptr = humdrumaddress; // skip over the staring portion of the address: if (strncmp(ptr, "humdrum://", strlen("humdrum://")) == 0) { ptr += strlen("humdrum://"); } else if (strncmp(ptr, "hum://", strlen("hum://")) == 0) { ptr += strlen("hum://"); } else if (strncmp(ptr, "h://", strlen("h://")) == 0) { ptr += strlen("h://"); } Array location; location.setSize(strlen(ptr)+1); location.allowGrowth(0); strcpy(location.getBase(), ptr); Array filename; filename.setSize(1); filename[0] = '\0'; filename.setSize(0); strcpy(location.getBase(), ptr); char* pot; if ((pot = strrchr(location.getBase(), '/')) != NULL) { *pot = '\0'; pot++; filename.setSize(strlen(pot)+1); strcpy(filename.getBase(), pot); filename.allowGrowth(0); } else { filename = location; location.setSize(2); strcpy(location.getBase(), "/"); } SSTREAM httprequest; cerr << "HTTPS REQUEST HERE" << endl; httprequest << "https://" << "kern.humdrum.org"; httprequest << "/cgi-bin/ksdata?file="; if (filename.getSize() > 0) { httprequest << filename.getBase(); } httprequest << "&l="; if (location.getSize() > 0) { httprequest << location.getBase(); } httprequest << "&format=kern"; httprequest << ends; readFromHttpURI(httprequest.CSTRING); } ////////////////////////////// // // readFromJrpURI -- Read a Humdrum file from a jrp:// web-style address // // Example: // maps: // jrp://Jos2721-La_Bernardina // into: // http://jrp.ccarh.org/cgi-bin/jrp?a=humdrum&f=Jos2721-La_Bernardina // void HumdrumFileBasic::readFromJrpURI(const char* jrpaddress) { const char* ptr = jrpaddress; // skip over the staring portion of the address: if (strncmp(ptr, "jrp://", strlen("jrp://")) == 0) { ptr += strlen("jrp://"); } else if (strncmp(ptr, "jrp:", strlen("jrp:")) == 0) { ptr += strlen("jrp:"); } SSTREAM httprequest; httprequest << "http://" << "jrp.ccarh.org"; httprequest << "/cgi-bin/jrp?a=humdrum&f="; httprequest << ptr; httprequest << ends; readFromHttpURI(httprequest.CSTRING); } ////////////////////////////// // // readFromHttpURI -- Read a Humdrum file from an http:// web address // void HumdrumFileBasic::readFromHttpURI(const char* webaddress) { Array hostname; Array location; location.setSize(0); const char* ptr = webaddress; const char* filename = NULL; if (strncmp(webaddress, "http://", strlen("http://")) == 0) { // remove the "http://" portion of the webaddress ptr += strlen("http://"); } hostname.setSize(strlen(ptr)+1); hostname.setGrowth(0); strcpy(hostname.getBase(), ptr); char* pot; if ((pot = strchr(hostname.getBase(), '/')) != NULL) { *pot = '\0'; } if ((filename = strchr(ptr, '/')) != NULL) { location.setSize(strlen(filename)+1); strcpy(location.getBase(), filename); location.allowGrowth(0); } if (location.getSize() == 0) { location.setSize(2); location.allowGrowth(0); strcpy(location.getBase(), "/"); } char newline[3] = {0x0d, 0x0a, 0}; SSTREAM request; request << "GET " << location.getBase() << " HTTP/1.1" << newline; request << "Host: " << hostname.getBase() << newline; request << "User-Agent: HumdrumFile Downloader 1.0 (" << __DATE__ << ")" << newline; request << "Connection: close" << newline; // this line is necessary request << newline; request << ends; // cout << "HOSTNAME: " << hostname.getBase() << endl; // cout << "LOCATION: " << location.getBase() << endl; // cout << request.CSTRING << endl; // cout << "-------------------------------------------------" << endl; int socket_id = open_network_socket(hostname.getBase(), 80); if (::write(socket_id, request.CSTRING, strlen(request.CSTRING)) == -1) { exit(-1); } #define URI_BUFFER_SIZE (10000) char buffer[URI_BUFFER_SIZE]; int message_len; SSTREAM inputdata; SSTREAM header; int foundcontent = 0; int i; int newlinecounter = 0; // read the response header: while ((message_len = ::read(socket_id, buffer, 1)) != 0) { header << buffer[0]; if ((buffer[0] == 0x0a) || (buffer[0] == 0x0d)) { newlinecounter++; } else { newlinecounter = 0; } if (newlinecounter == 4) { foundcontent = 1; break; } } if (foundcontent == 0) { cerr << "Funny error trying to read server response" << endl; exit(1); } // now read the size of the rest of the data which is expected int datalength = -1; // also, check for chunked transfer encoding: int chunked = 0; header << ends; // cout << header.CSTRING << endl; // cout << "-------------------------------------------------" << endl; while (header.getline(buffer, URI_BUFFER_SIZE)) { int len = strlen(buffer); for (i=0; i= 0) { // break; // } } // once the length of the remaining data is known (or not), read it: if (datalength > 0) { getFixedDataSize(socket_id, datalength, inputdata, buffer, URI_BUFFER_SIZE); } else if (chunked) { int chunksize; int totalsize = 0; do { chunksize = getChunk(socket_id, inputdata, buffer, URI_BUFFER_SIZE); totalsize += chunksize; } while (chunksize > 0); if (totalsize == 0) { cerr << "Error: no data found for URI (probably invalid)\n"; exit(1); } } else { // if the size of the rest of the data cannot be found in the // header, then just keep reading until done (but this will // probably cause a 5 second delay at the last read). while ((message_len = ::read(socket_id, buffer, URI_BUFFER_SIZE)) != 0) { if (foundcontent) { inputdata.write(buffer, message_len); } else { for (i=0; i datalength) { readsize = datalength - readcount; } message_len = ::read(socket_id, buffer, readsize); if (message_len == 0) { // shouldn't happen, but who knows... break; } inputdata.write(buffer, message_len); readcount += message_len; } return readcount; } ////////////////////////////// // // HumdrumFileBasic::prepare_address -- Store a computer name, such as // www.google.com into a sockaddr_in structure for later use in // open_network_socket. // void HumdrumFileBasic::prepare_address(struct sockaddr_in *address, const char *hostname, unsigned short int port) { memset(address, 0, sizeof(struct sockaddr_in)); struct hostent *host_entry; host_entry = gethostbyname(hostname); if (host_entry == NULL) { cerr << "GOT HERE TTT " << endl; cerr << "Could not find address for" << hostname << endl; exit(1); } // copy the address to the sockaddr_in struct. memcpy(&address->sin_addr.s_addr, host_entry->h_addr_list[0], host_entry->h_length); // set the family type (PF_INET) address->sin_family = host_entry->h_addrtype; address->sin_port = htons(port); } ////////////////////////////// // // open_network_socket -- Open a connection to a computer on the internet. // Intended for downloading a Humdrum file from a website. // int HumdrumFileBasic::open_network_socket(const char *hostname, unsigned short int port) { int inet_socket; // socket descriptor struct sockaddr_in servaddr; // IP/port of the remote host prepare_address(&servaddr, hostname, port); // socket(domain, type, protocol) // domain = PF_INET(internet/IPv4 domain) // type = SOCK_STREAM(tcp) * // protocol = 0 (only one SOCK_STREAM type in the PF_INET domain inet_socket = socket(PF_INET, SOCK_STREAM, 0); if (inet_socket < 0) { // socket returns -1 on error cerr << "Error opening socket to computer " << hostname << endl; exit(1); } // connect(sockfd, serv_addr, addrlen) if (connect(inet_socket, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)) < 0) { // connect returns -1 on error cerr << "Error opening connection to coputer: " << hostname << endl; exit(1); } return inet_socket; } #endif ////////////////////////////// // // HumdrumFileBasic::makeVts -- create a !!!VTS: record for the // given Humdrum data. The function will ignore all reference records // which start with the string "!!!VTS" when calculating the VTS data. // The data is always assumbed to be encoded with Unix newlines (0x0a). // void HumdrumFileBasic::makeVts(Array& vtsstring) { HumdrumFileBasic::makeVts(vtsstring, (*this)); } void HumdrumFileBasic::makeVts(Array& vtsstring, HumdrumFileBasic& infile) { int i; SSTREAM tstream; for (i=0; i& vtsstring) { HumdrumFileBasic::makeVtsData(vtsstring, (*this)); } void HumdrumFileBasic::makeVtsData(Array& vtsstring, HumdrumFileBasic& infile) { int i; SSTREAM tstream; for (i=0; i