#include #include #include #include "Weather.h" //#include #ifndef MAX_FILE_TIMES #define MAX_FILE_TIMES 256 #endif ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Derivatives of Host ////////////////////////////////////////////////////////////////////////////////////////////////////////// #pragma warning( push ) #pragma warning( disable : 4100 ) class HostHttp : public Weather::Host { private: UTIL::Socket m_clsSocket; bool Connect(void) {return false;} void Disconnect(void) { if ( m_blnConnected ) { m_clsSocket.Finish(); m_blnConnected = false; } } Weather::Host::Error GetFile(const char * p_ptrFileNameRemote, UTIL::Output & p_clsOut, UTIL::Log & p_clsLogStd, UTIL::Log & p_clsLogErr) { if ( m_clsSocket.Open(1) == false ) return Weather::Host::ERROR_COULD_NOT_CONNECT; int intResponse = 200; Weather::Host::Error enmError = ( m_clsSocket.WriteHttp("GET", p_ptrFileNameRemote) && m_clsSocket.ReadHttp(&intResponse, &p_clsOut) && intResponse < 300 ) ? Weather::Host::ERROR_NONE : Weather::Host::ERROR_UNKNOWN; m_clsSocket.Close(); return ( intResponse < 300 ) ? enmError : Weather::Host::ERROR_NO_FILE_FOUND; } bool GetFileTime(const char * p_ptrFileNameRemote) { int intRespose; return ( m_clsSocket.WriteHttp("HEAD", p_ptrFileNameRemote) && m_clsSocket.ReadHttp(&intRespose) && intRespose < 300 ); } public: HostHttp(const char * HostName) { m_clsSocket.WaitTimeSet(30, 0); m_clsSocket.SetHost(HostName, 80); } ~HostHttp() {Finish();} void Finish(void) {m_clsSocket.Finish();} }; class HostFtp : public Weather::Host { private: UTIL::Ftp m_clsFtp; bool Connect(void) { if ( m_blnConnected == false ) { m_blnConnected = m_clsFtp.Open(m_ptrAddress, ( m_ptrUsername ) ? m_ptrUsername : "anonymous", ( m_ptrPassword ) ? m_ptrPassword : "foo@bar.com"); } return m_blnConnected; } void Disconnect(void) { if ( m_blnConnected ) { m_clsFtp.Close(); m_blnConnected = false; } } Weather::Host::Error GetFile(const char * p_ptrFileNameRemote, UTIL::Output & p_clsOut, UTIL::Log & p_ptrLogStd, UTIL::Log & p_ptrLogErr) { if ( m_blnConnected == false && Connect() == false ) return Weather::Host::ERROR_COULD_NOT_CONNECT; switch ( m_clsFtp.Get(p_ptrFileNameRemote, &p_clsOut, &m_blnShouldBeRunning, &p_ptrLogStd, &p_ptrLogErr) ) { case UTIL::Ftp::ERROR_NONE: return Weather::Host::ERROR_NONE; case UTIL::Ftp::ERROR_SOCKET_TIMEOUT: return Weather::Host::ERROR_HOST_TIMEOUT; case UTIL::Ftp::ERROR_COMMAND_RETR: return Weather::Host::ERROR_NO_FILE_FOUND; case UTIL::Ftp::ERROR_SOCKET_ERROR: case UTIL::Ftp::ERROR_FAILED_SOCKET: return Weather::Host::ERROR_FAILED_NETWORK; default: return Weather::Host::ERROR_UNKNOWN; } } public: HostFtp(const bool Pasv = false) : m_clsFtp(true, !Pasv, 10, 0) {} ~HostFtp() {Finish();} void Finish(void) { Disconnect(); m_clsFtp.Finish(); } bool GetFileTime(const char * p_ptrFileNameRemote) { return m_clsFtp.Mtime(p_ptrFileNameRemote, NULL); } }; #pragma warning( pop ) ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Access ////////////////////////////////////////////////////////////////////////////////////////////////////////// Weather::Access:: Access() { if ( !m_clsMutex.Create() ) throw UTIL::Exception(UTIL::Exception::MUTEX_CREATE, __FILE__, __LINE__); } void Weather::Access:: Clean(const time_t p_intTimeToLive) { if ( m_clsMutex.Lock() == false ) return; // // See if the product has been loaded // time_t intTimeNow = time(NULL); Weather::DeleteList::iterator ptrProduct = m_clsProducts.begin(); while ( ptrProduct != m_clsProducts.end() ) { // // Get rid of product interval data that isn't being used // Weather::Access::Product & clsProduct = *(*ptrProduct); Weather::DeleteList::iterator ptrFile = clsProduct.m_clsFiles.begin(); while ( ptrFile != clsProduct.m_clsFiles.end() ) { Weather::Access::File & clsFile = *(*ptrFile); if ( clsFile.m_uintUsers == 0 && p_intTimeToLive > (intTimeNow - clsFile.m_intTimeUnlock) ) { delete (*ptrFile); if ( ptrFile != clsProduct.m_clsFiles.begin() ) { Weather::DeleteList::iterator ptrTemp = ptrFile; ptrFile--; clsProduct.m_clsFiles.erase(ptrTemp); ptrFile++; //ptrFile = ptrTemp + 1; } else { clsProduct.m_clsFiles.erase(ptrFile); ptrFile = clsProduct.m_clsFiles.begin(); } } } // // Unlock products that aren't being used // if ( clsProduct.m_uintUsers == 0 ) { // CHECK TO SEE IF THE DOWNLOADER IS WAITING TO UPDATE A PRODUCT if ( p_intTimeToLive > (intTimeNow - clsProduct.m_intTimeUnlock) ) { (*ptrProduct)->m_ptrProduct->Unlock(); (*ptrProduct)->m_ptrProduct = NULL; delete (*ptrProduct); if ( ptrProduct != m_clsProducts.begin() ) { Weather::DeleteList::iterator ptrTemp = ptrProduct; ptrProduct--; m_clsProducts.erase(ptrTemp); ptrProduct++; } else { m_clsProducts.erase(ptrProduct); ptrProduct = m_clsProducts.begin(); } } } } } Weather::Access::List * Weather::Access:: Load(const unsigned int p_uintInterval, Weather::Access::Product & p_clsProduct) { if ( m_clsMutex.Lock() == false ) return NULL; // // See if the product interval has been loaded // Weather::DeleteList::iterator ptrEnd = p_clsProduct.m_clsFiles.end(); for (Weather::DeleteList::iterator ptrStart = p_clsProduct.m_clsFiles.begin(); ptrStart != ptrEnd; ptrStart++) { Weather::Access::File & clsFile = *(*ptrStart); if ( p_uintInterval == clsFile.m_uintInterval ) { // // It has been loaded... increment the access count // clsFile.m_uintUsers++; Weather::Access::List * ptrList = &(clsFile.m_clsMessages); if ( m_clsMutex.Release() ) return ptrList; else { clsFile.m_uintUsers--; return NULL; } } } // // It has not been loaded... open it for loading // UTIL::File clsFile; if ( clsFile.Open("r", ( UTIL_CHECK_PATH(p_clsProduct.m_ptrDirectory) ) ? "%s%s.%03i.grb" : "%s/%s.%03i.grb", p_clsProduct.m_ptrDirectory, p_clsProduct.m_ptrProduct->m_ptrFileLocal, p_uintInterval) == false ) { m_clsMutex.Release(); return NULL; } // // Load each message in the GRIB file // Weather::Access::File * ptrFile = new Weather::Access::File(p_uintInterval); do { GRIB::Message * ptrMessage = new GRIB::Message; ptrFile->m_clsMessages.push_front(ptrMessage); if ( ptrMessage->Read(&clsFile) == false ) { delete ptrFile; clsFile.Finish(); m_clsMutex.Release(); return NULL; } } while ( clsFile.Eof() == false ); clsFile.Finish(); // // Add the messages to the list and release the mutex // p_clsProduct.m_clsFiles.push_front(ptrFile); if ( m_clsMutex.Release() == false ) { p_clsProduct.m_clsFiles.pop_front(); delete ptrFile; return NULL; } else return &(ptrFile->m_clsMessages); } Weather::Access::Product * Weather::Access:: Lock(const char * p_ptrDirectory, Weather::Product & p_clsProduct, UTIL::Log & p_clsLog) { if ( m_clsMutex.Lock() == false ) return NULL; // // See if the product has been loaded // Weather::DeleteList::iterator ptrEnd = m_clsProducts.end(); for (Weather::DeleteList::iterator ptrStart = m_clsProducts.begin(); ptrStart != ptrEnd; ptrStart++) { Weather::Access::Product & clsProduct = *(*ptrStart); if ( strcmp(p_clsProduct.m_ptrFileLocal, clsProduct.m_ptrProduct->m_ptrFileLocal) == 0 ) { clsProduct.m_uintUsers++; if ( m_clsMutex.Release() == false ) { clsProduct.m_uintUsers--; return NULL; } else return &clsProduct; } } // // It has not been loaded... load it // UTIL::Time stuTime; if ( p_clsProduct.Lock(300, &stuTime, p_clsLog) ) { m_clsMutex.Release(); return NULL; } Weather::Access::Product * ptrProduct = new Weather::Access::Product; ptrProduct->m_uintUsers = 1; ptrProduct->m_stuTime = stuTime; ptrProduct->m_ptrProduct = &p_clsProduct; ptrProduct->m_ptrDirectory = UTIL::Strdup(p_ptrDirectory); m_clsProducts.push_front(ptrProduct); if ( m_clsMutex.Release() == false ) { m_clsProducts.pop_front(); delete ptrProduct; return NULL; } return ptrProduct; } bool Weather::Access:: Unlock(Weather::Access::Product & p_clsProduct, Weather::Access::List * p_ptrList) { if ( m_clsMutex.Lock() == false ) return false; if ( p_ptrList ) { Weather::DeleteList::iterator ptrEnd = p_clsProduct.m_clsFiles.end(); for (Weather::DeleteList::iterator ptrStart = p_clsProduct.m_clsFiles.begin(); ptrStart != ptrEnd; ptrStart++) { Weather::Access::File & clsFile = *(*ptrStart); if ( p_ptrList == &(clsFile.m_clsMessages) ) { clsFile.m_uintUsers--; if ( clsFile.m_uintUsers == 0 ) clsFile.m_intTimeUnlock = time(NULL); return ( m_clsMutex.Release() ); } } fprintf(stderr, "ERROR: COULD NOT FIND MESSAGE OBJECT IN ARRAY\n"); m_clsMutex.Release(); return false; } else { if ( p_clsProduct.m_uintUsers == 0 ) { fprintf(stderr, "ERROR: PRODUCT HAS ZERO USER COUNT BEFORE UNLOCKING\n"); m_clsMutex.Release(); return false; } p_clsProduct.m_uintUsers--; if ( p_clsProduct.m_uintUsers == 0 ) p_clsProduct.m_intTimeUnlock = time(NULL); return ( m_clsMutex.Release() ); } } ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Access::File ////////////////////////////////////////////////////////////////////////////////////////////////////////// Weather::Access::File:: File(unsigned int p_uintInterval) : m_uintInterval(p_uintInterval), m_uintUsers(1) {} ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Access::Product ////////////////////////////////////////////////////////////////////////////////////////////////////////// Weather::Access::Product:: Product() : m_ptrProduct(NULL), m_ptrDirectory(NULL), m_uintUsers(0) {} Weather::Access::Product:: ~Product() { delete [] m_ptrDirectory; if ( m_ptrProduct ) m_ptrProduct->Unlock(); } ////////////////////////////////////////////////////////////////////////////////////////////////////////// // File ////////////////////////////////////////////////////////////////////////////////////////////////////////// Weather::File:: File(const UTIL::Time p_clsBaseTime, UTIL::D2::Box p_stuCorners) : m_blnRequestSent(false) { m_clsTime = p_clsBaseTime; m_stuCorners = p_stuCorners; m_stuCorners.AdjustW(); m_clsSocket.WaitTimeSet(300, 0); } Weather::File:: ~File() { for (unsigned int i=0; i stuWrapValues; //UTIL::DN::g_ptrWrapValues = &stuWrapValues; //UTIL::DN::g_uintWrapMask = 0x1; //stuWrapValues[0] = 0.0f; //stuWrapValues[1] = 360.0f; //stuWrapValues[2] = -90.0f; //stuWrapValues[3] = 90.0f; // // Find products that have common properties (geographic area, weather type, etc.) // std::vector clsAdded; Weather::GroupList::const_iterator ptrGroupEnd = p_clsGroups.end(); for (Weather::GroupList::const_iterator ptrGroupStart = p_clsGroups.begin(); ptrGroupStart != ptrGroupEnd; ptrGroupStart++) { const char * ptrDirectory = (*ptrGroupStart)->m_ptrDirectory; const Weather::ProductList::iterator ptrProductEnd = (*ptrGroupStart)->m_clsProducts.end(); for (Weather::ProductList::iterator ptrProductStart = (*ptrGroupStart)->m_clsProducts.begin(); ptrProductStart != ptrProductEnd; ptrProductStart++) { // // See if the zone area intersects the product area // Weather::Product & clsProduct = *(*ptrProductStart); if ( clsProduct.m_stuCorners.IntersectW(m_stuCorners) == false ) continue; // // See if there is a common weather type // for (i=0; i= m_clsParts.size() ) continue; // // See if there is a common time // Weather::Access::Product * ptrLock = p_clsAccess.Lock(ptrDirectory, clsProduct, p_clsLogStd); if ( ptrLock == NULL ) { p_clsLogErr.Printf("Could not aquire lock on product [%s]... skipping", clsProduct.m_ptrFileLocal); continue; } p_clsLogStd.Printf(" Locked product [%s]", clsProduct.m_ptrFileLocal); // // Skip the product if the zone time is either earlier than the product time, or after the last forecasted time // for (i=0; im_stuTime.ToEpoch()) / 3600; if ( /*intDifference < (-1 * ptrLock->m_ptrProduct->m_intIntervals[1]) ||*/ intDifference > ((1 + ptrLock->m_ptrProduct->m_intIntervals[2]) * ptrLock->m_ptrProduct->m_intIntervals[1]) ) { continue; } else if ( intDifference >= 0 ) { time_t intOffset = intDifference % ptrLock->m_ptrProduct->m_intIntervals[1]; intDifference += ( intOffset >= (ptrLock->m_ptrProduct->m_intIntervals[1] / 2) ) ? ptrLock->m_ptrProduct->m_intIntervals[1] - intOffset : -intOffset; if ( intDifference > (ptrLock->m_ptrProduct->m_intIntervals[1] * (ptrLock->m_ptrProduct->m_intIntervals[2] - 1)) ) intDifference = ptrLock->m_ptrProduct->m_intIntervals[1] * (ptrLock->m_ptrProduct->m_intIntervals[2] - 1); } else intDifference = 0; // // Create the split file name from the time offset // Weather::Access::List * ptrMessages = p_clsAccess.Load((unsigned int)(intDifference), *ptrLock); if ( ptrMessages == NULL ) { p_clsLogErr.Printf("Could not open time [%i] ... skipping", intDifference); continue; } // // Check all messages in the file // Weather::Access::List::iterator ptrListEnd = ptrMessages->end(); for (Weather::Access::List::iterator ptrListStart = ptrMessages->begin(); ptrListStart != ptrListEnd; ptrListStart++) { GRIB::Message & clsGrib = *(*ptrListStart); for (k=0; k *)(&m_stuCorners))); m_clsParts[k].ptrTrees[l]->Distance(m_clsParts[k].fltDistance); } clsGrib.Chop(m_clsParts[k].ptrTrees[l], &p_clsOut); } } } } if ( p_clsAccess.Unlock(*ptrLock, ptrMessages) == false ) p_clsLogErr.Printf("Could not unlock product messages"); } } // // Unlock the product // if ( p_clsAccess.Unlock(*ptrLock) == false ) p_clsLogErr.Printf("Could not unlock product"); clsAdded.clear(); } } return Weather::SUCCESS; } bool Weather::File:: Parse(UTIL::Parser * p_ptrData) { // // Skip to the start of the template // if ( p_ptrData->ToCharacter('{') == false ) return false; // // Read all the properties // bool blnTime = false; bool blnCorners = false; int intTimes[MAX_FILE_TIMES]; p_ptrData->Skip(1); for (;;) { // // Read the property name // char chrName[64]; p_ptrData->ToNotCharacters(" \t\r\n"); if ( p_ptrData->ReadString(chrName, 64, " \t\r\n=") == NULL ) { return false; } else if ( strcmp(chrName, "}") == 0 ) return true; else if ( p_ptrData->ToCharacter('=') == false || p_ptrData->Skip(1) == false || p_ptrData->ToNotCharacters(" \t\r\n") == false ) { return false; } // // Read the property value // if ( strcmpi(chrName, "time") == 0 ) { if ( blnTime ) return false; blnTime = true; int intTime[4]; if ( p_ptrData->ReadIntegers(&(intTime[0]), 4) == false ) return false; m_clsTime.ushtYear = (unsigned short)(intTime[0]); m_clsTime.ushtMonth = (unsigned short)(intTime[1]); m_clsTime.ushtDay = (unsigned short)(intTime[2]); m_clsTime.ushtHour = (unsigned short)(intTime[3]); m_clsTime.ushtMinute = m_clsTime.ushtSecond = 0; } else if ( strcmpi(chrName, "corners") == 0 ) { if ( blnCorners ) return false; blnCorners = true; if ( p_ptrData->ReadFloats(m_stuCorners, 4) == false ) return false; m_stuCorners.AdjustW(); } else if ( strcmpi(chrName, "weather") == 0 ) { Part stuPart; stuPart.uintAmount = 0; if ( p_ptrData->ReadIntegers((int *)(&(stuPart.uintType)), 1) == false || p_ptrData->ReadFloats(&(stuPart.fltDistance), 1) == false ) { return false; } while ( p_ptrData->ToCharacters("0123456789\n") && p_ptrData->Peek() != '\n' ) { if ( stuPart.uintAmount >= MAX_FILE_TIMES || p_ptrData->ReadIntegers(&(intTimes[stuPart.uintAmount++]), 1) == false ) { return false; } } stuPart.ptrTimes = new unsigned int[stuPart.uintAmount]; memcpy(stuPart.ptrTimes, &intTimes, stuPart.uintAmount * sizeof(unsigned int)); m_clsParts.push_back(stuPart); } else return false; } } ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Group ////////////////////////////////////////////////////////////////////////////////////////////////////////// Weather::Group:: Group() : m_ptrName(NULL), m_ptrDirectory(NULL) {} Weather::Group:: ~Group() { delete [] m_ptrName; delete [] m_ptrDirectory; } bool Weather::Group:: Init(const char * p_ptrDirectory, const bool p_blnCheckProductTime, UTIL::Log & p_clsErrLog) { // // Create the fully qualified path // bool blnReturn = true; const char * ptrPathFormat; if ( UTIL_CHECK_PATH(p_ptrDirectory) ) ptrPathFormat = ( UTIL_CHECK_PATH(m_ptrDirectory) ) ? "%s%s" : "%s%s/"; else ptrPathFormat = ( UTIL_CHECK_PATH(m_ptrDirectory) ) ? "%s/%s" : "%s/%s/"; char * ptrDirectory = UTIL::PrintfR(ptrPathFormat, p_ptrDirectory, m_ptrDirectory); delete [] m_ptrDirectory; m_ptrDirectory = UTIL::Strdup(ptrDirectory); free(ptrDirectory); // // Make sure the directory exists // if ( UTIL::FolderCreate(m_ptrDirectory, false, true) == false ) { p_clsErrLog.Printf("Could not create directory for group %s: %s", ( m_ptrName ) ? m_ptrName : "(unnamed)", m_ptrDirectory); return false; } // // Initialize the products // for (Weather::ProductList::iterator ptrStart = m_clsProducts.begin(); ptrStart != m_clsProducts.end(); ptrStart++) { if ( (*ptrStart)->Init(m_ptrDirectory, p_blnCheckProductTime, m_clsProducts, p_clsErrLog) == false ) { blnReturn = false; } } return blnReturn; } bool Weather::Group:: Read(UTIL::Parser & p_clsData, Weather::GroupList & p_clsGroups) { Weather::GroupList clsGroups; for (;;) { p_clsData.ToNotCharacters(" \t\r\n"); if ( p_clsData.Peek() == '#' ) { p_clsData.ToCharacter('\n'); continue; } if ( p_clsData.ToString("group", true, false) == false ) break; if ( p_clsData.ToNotWhitespace() == false ) return false; Group * ptrGroup = new Group; clsGroups.push_front(ptrGroup); if ( p_clsData.Peek() != '{' ) { ptrGroup->m_ptrName = p_clsData.ReadString(NULL, 0, " \t\r\n{}"); if ( ptrGroup->m_ptrName == NULL || p_clsData.ToCharacter('{') == false ) return false; } p_clsData.Skip(1); for (;;) { char chrName[64]; p_clsData.ToNotCharacters(" \t\r\n"); if ( p_clsData.Peek() == '#' ) { p_clsData.ToCharacter('\n'); continue; } else if ( p_clsData.ReadString(chrName, 64, " \t\r\n=") == NULL ) { return false; } else if ( strcmp(chrName, "}") == 0 ) break; if ( strcmpi(chrName, "product") ) { if ( p_clsData.ToCharacter('=') == false || p_clsData.Skip(1) == false || p_clsData.ToNotCharacters(" \t\r\n") == false ) { return false; } char * ptrValue = p_clsData.ReadString(NULL, 0, " \t\r\n"); if ( ptrValue == NULL ) return false; if ( strcmpi(chrName, "directory") == 0 ) ptrGroup->m_ptrDirectory = ptrValue; else { delete [] ptrValue; return false; } } else { Product * ptrProduct = new Product; if ( ptrProduct->Read(p_clsData) ) ptrGroup->m_clsProducts.push_front(ptrProduct); else { delete ptrProduct; return false; } } } } p_clsGroups.splice(p_clsGroups.begin(), clsGroups); return true; } bool Weather::Group:: Read(const char * p_ptrFileName, Weather::GroupList & p_clsGroups) { UTIL::File clsFile; return ( clsFile.Open("r", p_ptrFileName) ) ? Read(clsFile, p_clsGroups) : false; } void Weather::Group:: Split(UTIL::Log & p_clsLogStd, UTIL::Log & p_clsLogErr) { Weather::ProductList::iterator ptrEnd = m_clsProducts.end(); for (Weather::ProductList::iterator ptrStart = m_clsProducts.begin(); ptrStart != ptrEnd; ptrStart++) { // // Skip the product if it was not downloaded // Weather::Product & clsProduct = *(*ptrStart); if ( clsProduct.m_ptrFileDownloaded == NULL ) continue; // // Lock the product so it isn't used while we are creating new split files // UTIL::File clsFile; if ( clsProduct.Lock(60, NULL, p_clsLogErr) != Weather::Product::LOCK_SUCCESS ) { p_clsLogErr.Printf("Could not lock product %s", clsProduct.m_ptrFileLocal); } else if ( clsProduct.Clean(m_ptrDirectory, p_clsLogErr) == false || clsFile.OpenEx("r", clsProduct.m_ptrFileDownloaded) == false || GRIB::Split(&clsFile, m_ptrDirectory, clsProduct.m_ptrFileLocal, ".grb", clsProduct.m_ptrTypes) == false ) { p_clsLogErr.Printf("Could not split product [%s]", clsProduct.m_ptrFileLocal); clsProduct.Unlock(NULL, true); } else if ( clsProduct.Unlock(&(clsProduct.m_stuTime), true) == false ) p_clsLogErr.Printf("Could not unlock product [%s]", clsProduct.m_ptrFileLocal); else p_clsLogStd.Printf("Split product [%s]", clsProduct.m_ptrFileLocal); // // We are done splitting files... unlock the product // clsFile.Finish(); if ( unlink(clsProduct.m_ptrFileDownloaded) ) p_clsLogErr.Printf("Could not delete downloaded file [%s]", clsProduct.m_ptrFileDownloaded); delete [] clsProduct.m_ptrFileDownloaded; clsProduct.m_ptrFileDownloaded = NULL; } } ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Host ////////////////////////////////////////////////////////////////////////////////////////////////////////// Weather::Host:: Host() : m_enmStatus(STATUS_UNKNOWN), m_ptrName(NULL), m_ptrAddress(NULL), m_ptrUsername(NULL), m_ptrPassword(NULL), m_ptrCommonPath(NULL), m_ushtPortLocal(0), m_ushtPortRemote(0), m_intAffinity(0), m_uintErrors(0), m_uintAllowableErrors(3), m_blnConnected(false), m_blnShouldBeRunning(true) {} Weather::Host:: ~Host() { delete [] m_ptrName; delete [] m_ptrAddress; delete [] m_ptrUsername; delete [] m_ptrPassword; delete [] m_ptrCommonPath; } unsigned int Weather::Host:: Aggregate(const Weather::GroupList & p_clsGroups) { Weather::GroupList::const_iterator ptrEnd = p_clsGroups.end(); for (Weather::GroupList::const_iterator ptrStart = p_clsGroups.begin(); ptrStart != ptrEnd; ptrStart++) { Weather::ProductList::const_iterator ptrProductEnd = (*ptrStart)->m_clsProducts.end(); for (Weather::ProductList::const_iterator ptrProductStart = (*ptrStart)->m_clsProducts.begin(); ptrProductStart != ptrProductEnd; ptrProductStart++) { Weather::Product & clsProduct = *(*ptrProductStart); if ( clsProduct.m_ptrHost == this ) m_clsProducts.push_front(Weather::Host::ProductRef(clsProduct, clsProduct.m_ptrHostFile)); } } return m_clsProducts.size(); } void Weather::Host:: CheckVersions(const Weather::GroupList & p_clsGroups, UTIL::Log & p_clsLogStd) { Weather::GroupList::const_iterator ptrEnd = p_clsGroups.end(); for (Weather::GroupList::const_iterator ptrStart = p_clsGroups.begin(); ptrStart != ptrEnd; ptrStart++) { Weather::ProductList::const_iterator ptrProductEnd = (*ptrStart)->m_clsProducts.end(); for (Weather::ProductList::const_iterator ptrProductStart = (*ptrStart)->m_clsProducts.begin(); ptrProductStart != ptrProductEnd; ptrProductStart++) { unsigned int k; Weather::Product & clsProduct = *(*ptrProductStart); for (k=0; k= clsProduct.m_clsRemoteFiles.size() ) continue; // // Build the remote file name using the common path of the host // std::string clsRemoteName; char * ptrRemoteName = clsProduct.m_clsRemoteFiles[k] + strlen(m_ptrName) + 1; if ( ptrRemoteName[0] != '/' && ptrRemoteName[0] != '\\' ) { if ( m_ptrCommonPath ) { clsRemoteName += m_ptrCommonPath; if ( m_ptrCommonPath[strlen(m_ptrCommonPath) - 1] != '/' && m_ptrCommonPath[strlen(m_ptrCommonPath) - 1] != '\\' ) { clsRemoteName += "/"; } } } clsRemoteName += ptrRemoteName; // // Check for symbolic date/forecast parts in the fully qualified remote file name // std::string::size_type uintIndex; std::vector clsIndexDate; for (uintIndex = clsRemoteName.find("YYYYMMDD", 0); uintIndex != std::string::npos; uintIndex = clsRemoteName.find("YYYYMMDD", uintIndex + 1)) { clsIndexDate.push_back(uintIndex); } std::vector clsIndexForecast; for (uintIndex = clsRemoteName.find("++", 0); uintIndex != std::string::npos; uintIndex = clsRemoteName.find("++", uintIndex + 1)) { clsIndexForecast.push_back(uintIndex); } std::pair stuTemp; std::vector > clsIndexInterval; for (uintIndex = clsRemoteName.find("*", 0); uintIndex != std::string::npos; uintIndex = clsRemoteName.find("*", uintIndex + 1)) { stuTemp.first = uintIndex; stuTemp.second = 1; clsRemoteName[uintIndex] = '0'; while ( ++uintIndex < clsRemoteName.size() && clsRemoteName[uintIndex] == '*' ) { clsRemoteName[uintIndex] = '0'; stuTemp.second++; } clsIndexInterval.push_back(stuTemp); } // // Initialize the forecast time to be one interval in the future // UTIL::Time stuForecastTime; time_t intTime = time(NULL); stuForecastTime.FromEpoch(intTime + ((clsProduct.m_intIntervals[0] * 3600) - (intTime % (clsProduct.m_intIntervals[0] * 3600)))); // // We will stop checking when the forecast time plus the forecast length does not exceed the current time // UTIL::Time stuCutoffTime; stuCutoffTime.FromEpoch(stuForecastTime.ToEpoch() - ((clsProduct.m_intIntervals[1] * (clsProduct.m_intIntervals[2] + 1)) * 3600)); // // Keep checking this product until either: // // - the forecast length of the product does not exceed the current time // - the existing downloaded time or another host's time is more recent // while ( stuForecastTime >= stuCutoffTime && stuForecastTime > clsProduct.m_stuTime ) { // // Fill symbolic date/forecast parts in the fully qualified remote file name // std::stringstream strBuffer(std::ios_base::out); strBuffer.fill('0'); strBuffer.width(4); strBuffer << stuForecastTime.ushtYear; strBuffer.width(2); strBuffer << stuForecastTime.ushtMonth; strBuffer << stuForecastTime.ushtDay; for (k=0; k clsProduct.m_stuTime || (stuForecastTime == clsProduct.m_stuTime && clsProduct.m_ptrHost != NULL && clsProduct.m_ptrHost->m_intAffinity < m_intAffinity) ) { for (k=0; k= clsProduct.m_clsRemoteFiles.size() ) continue; // // Build the fully qualified name of the file on the remote host // std::string clsRemoteName; char * ptrRemoteName = clsProduct.m_clsRemoteFiles[j] + strlen(m_ptrName) + 1; if ( ptrRemoteName[0] != '/' && ptrRemoteName[0] != '\\' ) { if ( m_ptrCommonPath ) { clsRemoteName += m_ptrCommonPath; if ( m_ptrCommonPath[strlen(m_ptrCommonPath) - 1] != '/' && m_ptrCommonPath[strlen(m_ptrCommonPath) - 1] != '\\' ) { clsRemoteName += '/'; } } } clsRemoteName += ptrRemoteName; UTIL::File clsFile; char * ptrFileFinal; Host::Error enmError = ERROR_NONE; do { // // Create a temporary file to hold the product file // if ( clsFile.OpenEx("w", ptrFileTemp) == false ) { p_clsLogErr.Printf("Could not open temporary file %s", ptrFileTemp); clsFile.Finish(); break; } Weather::Host::Error enmError = GetFile(clsRemoteName.c_str(), clsFile, p_clsLogStd, p_clsLogErr); clsFile.Close(); switch ( enmError ) { case Weather::Host::ERROR_NONE: p_clsLogStd.Printf("Downloaded %s from %s (%u of %u)", clsProduct.m_ptrFileLocal, m_ptrName, uintCount, p_clsList.size()); ptrFileFinal = UTIL::PrintfR(UTIL_CHECK_PATH(p_ptrPathFinal) ? "%s%s" : "%s/%s", p_ptrPathFinal, clsProduct.m_ptrFileLocal); clsProduct.m_ptrFileDownloaded = UTIL::Strdup(ptrFileFinal); if ( UTIL::FileMove(ptrFileTemp, ptrFileFinal) == false ) { p_clsLogErr.Printf("Could not move downloaded file from [%s] to [%s]", ptrFileTemp, p_ptrPathFinal); } free(ptrFileFinal); break; case Weather::Host::ERROR_NO_FILE_FOUND: p_clsLogErr.Printf("Could not download %s from %s (file not found?)", clsRemoteName.c_str(), m_ptrName); break; case Weather::Host::ERROR_HOST_TIMEOUT: case Weather::Host::ERROR_FAILED_NETWORK: case Weather::Host::ERROR_COULD_NOT_CONNECT: p_clsLogErr.Printf("Could not download %s from %s (host error %u/%u)", clsRemoteName.c_str(), m_ptrName, 1 + uintHostErrors++, m_uintAllowableErrors); Disconnect(); break; default: p_clsLogErr.Printf("Could not download %s from %s (unhandled error)", clsRemoteName.c_str(), m_ptrName); enmError = Weather::Host::ERROR_NO_FILE_FOUND; // This is done just to break out of the loop break; } } while ( enmError != Weather::Host::ERROR_NONE && enmError != Weather::Host::ERROR_NO_FILE_FOUND && uintHostErrors <= m_uintAllowableErrors ); // // Quit if the host has generated too many errors // if ( uintHostErrors >= m_uintAllowableErrors ) { p_clsLogErr.Printf("Host [%s] has exceeded the maximum allowable errors (%u)", m_ptrName, m_uintAllowableErrors); break; } } unlink(ptrFileTemp); free(ptrFileTemp); } int Weather::Host:: DownloadProductsThread(Weather::Host::ThreadObjects * p_ptrObjects) { int intReturn = p_ptrObjects->m_clsHost.DownloadProducts(p_ptrObjects->m_ptrTempPath, p_ptrObjects->m_clsLogStd, p_ptrObjects->m_clsLogStd); delete p_ptrObjects; return intReturn; } int Weather::Host:: DownloadProducts(const char * p_ptrTempPath, UTIL::Log & p_clsLogStd, UTIL::Log & p_clsLogErr) { m_enmStatus = STATUS_RUNNING; if ( Connect() == false ) { p_clsLogErr.Printf("Could not connect to host %s", m_ptrName); Disconnect(); m_enmStatus = STATUS_COMPLETED_THREAD; return -1; } std::list::iterator ptrEnd = m_clsProducts.end(); for (std::list::iterator ptrStart = m_clsProducts.begin(); ptrStart != ptrEnd; ptrStart++) { // // Download the product file // char * ptrRandomFileName = UTIL::FileRandom(); Weather::Host::Error enmError = Weather::Host::ERROR_UNKNOWN; Weather::Product & clsProduct = (*ptrStart).m_clsProduct; const char * ptrRemoteName = (*ptrStart).m_ptrRemoteName; std::vector > clsIndices; do { // // Create a temporary file to hold the product file // UTIL::File clsFile; if ( clsFile.Open("w", ( UTIL_CHECK_PATH(p_ptrTempPath) ) ? "%s%s" : "%s/%s", p_ptrTempPath, ptrRandomFileName) == false ) { p_clsLogErr.Printf(( UTIL_CHECK_PATH(p_ptrTempPath) ) ? "Could not open temporary file %s%s" : "Could not open temporary file %s/%s", p_ptrTempPath, ptrRandomFileName); clsFile.Finish(); break; } time_t intTime = time(NULL); p_clsLogStd.Printf(" Downloading %s from %s", clsProduct.m_ptrFileLocal, m_ptrName); if ( strstr(ptrRemoteName, "*") == NULL ) { p_clsLogStd.Level(true); enmError = GetFile(ptrRemoteName, clsFile, p_clsLogStd, p_clsLogErr); p_clsLogStd.Level(true); switch ( enmError ) { case Weather::Host::ERROR_NONE: p_clsLogStd.Printf(" Downloaded %s from %s (took %u seconds)", clsProduct.m_ptrFileLocal, m_ptrName, (unsigned int)(time(NULL) - intTime)); clsProduct.m_ptrFileDownloaded = UTIL::Strdup(clsFile.Filename()); break; case Weather::Host::ERROR_NO_FILE_FOUND: p_clsLogErr.Printf(" Could not download %s from %s (file not found?)", ptrRemoteName, m_ptrName); clsFile.Close(); unlink(clsFile.Filename()); break; case Weather::Host::ERROR_HOST_TIMEOUT: case Weather::Host::ERROR_FAILED_NETWORK: p_clsLogErr.Printf(" Could not download %s from %s (error %u/%u)", ptrRemoteName, m_ptrName, 1 + m_uintErrors++, m_uintAllowableErrors); Disconnect(); clsFile.Close(); unlink(clsFile.Filename()); break; default: p_clsLogErr.Printf(" Could not download %s from %s (unhandled error)", ptrRemoteName, m_ptrName); m_uintErrors = m_uintAllowableErrors + 1; clsFile.Close(); unlink(clsFile.Filename()); break; } } else { clsIndices.clear(); std::string::size_type uintIndex; std::string clsRemoteFile(ptrRemoteName); std::pair stuTemp; for (uintIndex = clsRemoteFile.find("*", 0); uintIndex != std::string::npos; uintIndex = clsRemoteFile.find("*", uintIndex + 1)) { stuTemp.first = uintIndex; stuTemp.second = 1; while ( ++uintIndex < clsRemoteFile.size() && clsRemoteFile[uintIndex] == '*' ) stuTemp.second++; clsIndices.push_back(stuTemp); } std::stringstream strBuffer; strBuffer.fill('0'); enmError = Weather::Host::ERROR_NONE; int intForecastTime = clsProduct.m_intIntervals[1]; int intIntervals = clsProduct.m_intIntervals[2]; for (int j=0; j m_uintAllowableErrors ) break; } Disconnect(); m_enmStatus = STATUS_COMPLETED_THREAD; return 0; } Weather::Host::Error Weather::Host:: GetFile(const char * p_ptrFileNameRemote, const char * p_ptrFileNameLocal, UTIL::Log & p_clsLogStd, UTIL::Log & p_clsLogErr) { UTIL::File clsFile; if ( !m_blnConnected && Connect() == false ) return ERROR_COULD_NOT_CONNECT; if ( clsFile.Open("w", "%s", p_ptrFileNameLocal) == false ) { clsFile.Finish(); return ERROR_LOCAL_FILE; } Weather::Host::Error enmError = GetFile(p_ptrFileNameRemote, clsFile, p_clsLogStd, p_clsLogErr); if ( enmError != Weather::Host::ERROR_NONE ) { clsFile.Close(); unlink(clsFile.Filename()); } clsFile.Finish(); return enmError; } bool Weather::Host:: Read(UTIL::Parser & p_clsData, Weather::HostList & p_clsHosts) { Weather::HostList clsTempList; while ( p_clsData.ToString("host", true, false) ) { p_clsData.ToNotCharacters(" \t\r\n"); char * ptrHostName = p_clsData.ReadString(NULL, 0, " \t\r\n"); if ( ptrHostName == NULL || p_clsData.ToCharacter('{') == false || p_clsData.Skip(1) == false ) { UTIL_DELETE_ARRAY(ptrHostName) return false; } UTIL::Config clsConfig; for (;;) { // // Read the name // p_clsData.ToNotCharacters(" \t\r\n"); char * ptrName = p_clsData.ReadString(NULL, 0, " \t\r\n"); if ( ptrName == NULL ) { delete [] ptrHostName; return false; } else if ( strcmp(ptrName, "}") == 0 ) { delete [] ptrName; break; } else if ( clsConfig[ptrName] != NULL || p_clsData.ToCharacter('=') == false || p_clsData.Skip(1) == false ) { delete [] ptrHostName; delete [] ptrName; return false; } // // Read the value // p_clsData.ToNotCharacters(" \t\r\n"); char * ptrValue = p_clsData.ReadString(NULL, 0, " \t\r\n"); if ( ptrValue == NULL ) { delete [] ptrHostName; delete [] ptrName; return false; } clsConfig.AddValue(ptrName, ptrValue, false, false); } if ( clsConfig["address"] == NULL || clsConfig["protocol"] == NULL ) return false; Host * ptrHost; if ( strcmpi(clsConfig["protocol"], "ftp") == 0 ) { ptrHost = new HostFtp((clsConfig["pasv"] && (strcmpi(clsConfig["pasv"], "yes") == 0 || strcmpi(clsConfig["pasv"], "1") == 0 || strcmpi(clsConfig["pasv"], "on") == 0) )); } else if ( strcmpi(clsConfig["protocol"], "http") == 0 ) ptrHost = new HostHttp(clsConfig["address"]); else { delete [] ptrHostName; return false; } ptrHost->m_ptrName = ptrHostName; ptrHost->m_ptrAddress = clsConfig.SetValue("address", NULL); ptrHost->m_ptrUsername = clsConfig.SetValue("username", NULL); ptrHost->m_ptrPassword = clsConfig.SetValue("password", NULL); ptrHost->m_ptrCommonPath = clsConfig.SetValue("common_path", NULL); ptrHost->m_intAffinity = ( clsConfig["affinity"] != NULL ) ? atoi(clsConfig["affinity"]) : 0; if ( clsConfig["local_port"] ) ptrHost->m_ushtPortLocal = (unsigned short)(atoi(clsConfig["local_port"])); else if ( clsConfig["remote_port"] ) ptrHost->m_ushtPortRemote = (unsigned short)(atoi(clsConfig["remote_port"])); clsTempList.push_front(ptrHost); } p_clsHosts.splice(p_clsHosts.end(), clsTempList); return true; } bool Weather::Host:: Read(const char * p_ptrFileName, Weather::HostList & p_clsHosts) { UTIL::File clsFile; return ( clsFile.Open("r", "%s", p_ptrFileName) ) ? Read(clsFile, p_clsHosts) : false; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// // HostFtp ////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// // Product ////////////////////////////////////////////////////////////////////////////////////////////////////////// Weather::Product:: Product() : m_ptrFileLocal(NULL), m_ptrFileLock(NULL), m_ptrFileProxy(NULL), m_ptrTypes(NULL), m_ptrHost(NULL), m_ptrCategory(NULL), m_ptrHostFile(NULL), m_ptrDescription(NULL), m_enmStatus(STATUS_UNKNOWN), m_ptrFileDownloaded(NULL) { memset(&m_stuTime, 0, sizeof(UTIL::Time)); m_clsLockFile.m_blnPrintNulls = false; } Weather::Product:: ~Product() { if ( m_ptrFileLock ) free(m_ptrFileLock); if ( m_ptrFileProxy ) free(m_ptrFileProxy); delete [] m_ptrTypes; delete [] m_ptrHostFile; delete [] m_ptrFileLocal; delete [] m_ptrFileDownloaded; for (unsigned int i=0; i= strlen(m_ptrFileLocal) && strncmp(ptrName, m_ptrFileLocal, strlen(m_ptrFileLocal))) || (strlen(ptrName) > 4 && strcmp(ptrName + (strlen(ptrName) - 4), ".grb")) ) { continue; } else if ( unlink(stuElement.chrName) ) { p_clsLogErr.Printf("Could not delete product file: [%s]", &(stuElement.chrName[0])); blnReturn = false; } } return blnReturn; } bool Weather::Product:: Init(const char * p_ptrDirectory, const bool p_blnCheckProductTime, Weather::ProductList & p_clsProducts, UTIL::Log & p_clsErrLog) { if ( m_ptrFileLocal == NULL ) { p_clsErrLog.Printf("No local file specified"); return false; } // // Set the lock and proxy files // m_ptrFileLock = UTIL::PrintfR("%s%s.lock", p_ptrDirectory, m_ptrFileLocal); m_ptrFileProxy = UTIL::PrintfR("%s%s.proxy", p_ptrDirectory, m_ptrFileLocal); // // Make sure no other products have the same local file name // bool blnReturn = true; Weather::ProductList::iterator ptrStart; Weather::ProductList::iterator ptrEnd = p_clsProducts.end(); for (ptrStart = p_clsProducts.begin(); ptrStart != ptrEnd; ptrStart++) { Weather::Product * ptrProduct = *ptrStart; if ( this != ptrProduct && ptrProduct->m_ptrFileLocal != NULL && strcmpi(m_ptrFileLocal, ptrProduct->m_ptrFileLocal) == 0 ) { p_clsErrLog.Printf("More than one product has the same local file (%s)", m_ptrFileLocal); blnReturn = false; break; } } // // Check the last downloaded time // if ( p_blnCheckProductTime ) { // // Delete the proxy file if it exists (it should not exist unless an error previously occurred) // if ( UTIL::FileExists(m_ptrFileProxy) ) { if ( unlink(m_ptrFileProxy) ) p_clsErrLog.Printf("Could not delete proxy file [%s]", m_ptrFileProxy); else p_clsErrLog.Printf("WARNING: Found and deleted proxy file [%s]", m_ptrFileProxy); } switch ( Lock(0, &m_stuTime, p_clsErrLog) ) { case Weather::Product::LOCK_FILE_MISSING: p_clsErrLog.Printf("WARNING: Lock file does not exist (%s.lock)", m_ptrFileLocal); memset(&m_stuTime, 0, sizeof(UTIL::Time)); break; case Weather::Product::LOCK_TIME_EXPIRED: p_clsErrLog.Printf("Timeout while locking file during initialization (%s.lock)", m_ptrFileLocal); blnReturn = false; break; case Weather::Product::LOCK_SUCCESS: if ( Unlock() == false ) { p_clsErrLog.Printf("Could not unlock file (%s.lock)", m_ptrFileLocal); blnReturn = false; } break; default: if ( UTIL::FileSize(m_ptrFileLock) != 0 ) { p_clsErrLog.Printf("Could not lock file (%s.lock)", m_ptrFileLocal); blnReturn = false; } else if ( unlink(m_ptrFileLock) ) { p_clsErrLog.Printf("Could not delete empty lock file (%s)", m_ptrFileLock); blnReturn = false; } else p_clsErrLog.Printf("WARNING: Found and deleted empty lock file (%s)", m_ptrFileLock); break; } } return blnReturn; } Weather::Product::LockResult Weather::Product:: Lock(const time_t p_intSecondsToWait, UTIL::Time * p_ptrTime, UTIL::Log & p_clsLog) { // // Make sure the downloader is not updating this product. This is // accomplished by a proxy file that is created when the downloader is // updating it, and removed when it is finished. So if the proxy file // exists, we should wait until it is gone. // time_t intTime = time(NULL); if ( p_ptrTime ) { bool blnWait = UTIL::FileExists(m_ptrFileProxy); if ( blnWait ) { p_clsLog.Printf(" Waiting for proxy file [%s]", m_ptrFileProxy); do { Sleep(1000); blnWait = UTIL::FileExists(m_ptrFileProxy); } while ( blnWait && p_intSecondsToWait >= (time(NULL) - intTime) ); if ( blnWait ) return Weather::Product::LOCK_TIME_EXPIRED; } } else { if ( UTIL::FileExists(m_ptrFileProxy) || UTIL::FileTouch(m_ptrFileProxy) == false ) { return Weather::Product::LOCK_ERROR; } } // // Open the lock file // if ( m_clsLockFile.OpenEx(( p_ptrTime != NULL ) ? "re" : "w", m_ptrFileLock) == false ) { if ( p_ptrTime == NULL ) unlink(m_ptrFileProxy); return Weather::Product::LOCK_FILE_MISSING; } // // Attempt to lock the file // UTIL::File::LockResult enmResult; do { enmResult = m_clsLockFile.Lock(false); if ( enmResult == UTIL::File::LOCK_RESULT_SUCCESS ) break; else if ( enmResult == UTIL::File::LOCK_RESULT_WAIT ) Sleep(1000); else { if ( p_ptrTime != NULL ) unlink(m_ptrFileProxy); return Weather::Product::LOCK_ERROR; } } while ( p_intSecondsToWait >= (time(NULL) - intTime) ); if ( enmResult == UTIL::File::LOCK_RESULT_WAIT ) { m_clsLockFile.Finish(); if ( p_ptrTime != NULL ) unlink(m_ptrFileProxy); return Weather::Product::LOCK_TIME_EXPIRED; } if ( p_ptrTime ) { // // Read the last downloaded time from the lock file // int intValues[4]; if ( m_clsLockFile.ReadIntegers(&(intValues[0]), 4) == false ) { m_clsLockFile.Unlock(); m_clsLockFile.Finish(); unlink(m_ptrFileProxy); return Weather::Product::LOCK_ERROR; } p_ptrTime->ushtYear = (unsigned short)(intValues[0]); p_ptrTime->ushtMonth = (unsigned short)(intValues[1]); p_ptrTime->ushtDay = (unsigned short)(intValues[2]); p_ptrTime->ushtHour = (unsigned short)(intValues[3]); p_ptrTime->ushtMinute = p_ptrTime->ushtSecond = 0; } return Weather::Product::LOCK_SUCCESS; } bool Weather::Product:: Read(UTIL::Parser & p_clsData) { // // Skip to the start of the template // if ( p_clsData.ToCharacter('{') == false ) return false; // // Read all the properties // p_clsData.Skip(1); for (;;) { // // Read the property name // char chrName[64]; p_clsData.ToNotCharacters(" \t\r\n"); if ( p_clsData.Peek() == '#' ) { p_clsData.ToCharacter('\n'); continue; } if ( p_clsData.ReadString(chrName, 64, " \t\r\n=") == NULL ) { return false; } else if ( strcmp(chrName, "}") == 0 ) break; else if ( p_clsData.ToCharacter('=') == false || p_clsData.Skip(1) == false || p_clsData.ToNotCharacters(" \t\r\n") == false ) { return false; } // // Read the property value // char * ptrValue = p_clsData.ReadString(NULL, 0, " \t\r\n"); if ( ptrValue == NULL ) return false; if ( strcmpi(chrName, "remote_name") == 0 ) m_clsRemoteFiles.push_back(ptrValue); else if ( strcmpi(chrName, "local_name") == 0 ) { if ( m_ptrFileLocal ) { delete [] ptrValue; return false; } m_ptrFileLocal = ptrValue; } else if ( strcmpi(chrName, "corners") == 0 ) { if ( UTIL::String::ReadFloats(ptrValue, m_stuCorners, 4) == false ) { delete [] ptrValue; return false; } delete [] ptrValue; m_stuCorners.AdjustW(); } else if ( strcmpi(chrName, "intervals") == 0 ) { if ( UTIL::String::ReadIntegers(ptrValue, &(m_intIntervals[0]), 3) == false ) { delete [] ptrValue; return false; } delete [] ptrValue; } else if ( strcmpi(chrName, "used_types") == 0 ) { if ( m_ptrTypes ) return false; int intValues[256]; int intCount = 0; UTIL::String clsTypes(ptrValue); while ( intCount < 256 && clsTypes.ReadIntegers(&(intValues[intCount++]), 1) ); delete [] ptrValue; int i; m_ptrTypes = new unsigned char[intCount]; for (i=0; i<(intCount - 1); i++) { if ( intValues[i] < 0 || intValues[i] >= 256 ) return false; m_ptrTypes[i] = (unsigned char)(intValues[i]); } m_ptrTypes[i] = 0; } else if ( strcmpi(chrName, "available_types") == 0 ) delete [] ptrValue; else { delete [] ptrValue; return false; } } return true; } bool Weather::Product:: ReadText(UTIL::Parser & p_clsData) { // // Skip to the start of the template // if ( p_clsData.ToCharacter('{') == false ) return false; // // Read all the properties // p_clsData.Skip(1); for (;;) { // // Read the property name // char chrName[64]; p_clsData.ToNotCharacters(" \t\r\n"); if ( p_clsData.Peek() == '#' ) { p_clsData.ToCharacter('\n'); continue; } if ( p_clsData.ReadString(chrName, 64, " \t\r\n=") == NULL ) { return false; } else if ( strcmp(chrName, "}") == 0 ) break; else if ( p_clsData.ToCharacter('=') == false || p_clsData.Skip(1) == false || p_clsData.ToNotCharacters(" \t\r\n") == false ) { return false; } // // Read the property value // char * ptrValue = p_clsData.ReadString(NULL, 0, " \t\r\n"); if ( ptrValue == NULL ) return false; else if ( strcmpi(chrName, "remotefile") == 0 ) m_clsRemoteFiles.push_back(ptrValue); else if ( strcmpi(chrName, "category") == 0 ) { if ( m_ptrCategory ) { delete [] ptrValue; return false; } m_ptrCategory = ptrValue; } else if ( strcmpi(chrName, "description") == 0 ) { if ( m_ptrDescription ) { delete [] ptrValue; return false; } m_ptrDescription = ptrValue; } else if ( strcmpi(chrName, "localfile") == 0 ) { if ( m_ptrFileLocal ) { delete [] ptrValue; return false; } m_ptrFileLocal = ptrValue; } else { delete [] ptrValue; return false; } } return true; } bool Weather::Product:: Unlock(UTIL::Time * p_ptrTime, const bool p_blnDeleteProxy) { // // If the product was locked for writing, print the downloaded time // bool blnReturn = true; if ( p_ptrTime && m_clsLockFile.Printf("%04i:%02i:%02i:%02i", (int)(p_ptrTime->ushtYear), (int)(p_ptrTime->ushtMonth), (int)(p_ptrTime->ushtDay), (int)(p_ptrTime->ushtHour)) == false ) { blnReturn = false; } if ( m_clsLockFile.Unlock() == false ) blnReturn = false; m_clsLockFile.Finish(); if ( p_blnDeleteProxy && unlink(m_ptrFileProxy) ) blnReturn = false; return blnReturn; }