remove the starfield URL loading code, closes #1497

This commit is contained in:
Stephen Birarda 2014-01-10 15:33:43 -08:00
parent f0460bac5f
commit 1c3259c8cf
6 changed files with 0 additions and 670 deletions

View file

@ -39,8 +39,3 @@ include_directories(${ROOT_DIR}/externals/civetweb/include)
if (UNIX)
target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS})
endif (UNIX)
# link curl for synchronous script downloads
find_package(CURL REQUIRED)
include_directories(${CURL_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${CURL_LIBRARY})

View file

@ -36,7 +36,6 @@
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/matrix_access.hpp>
#include "UrlReader.h"
#include "AngleUtil.h"
#include "Radix2InplaceSort.h"
#include "Radix2IntegerScanner.h"

View file

@ -1,183 +0,0 @@
//
// starfield/Loader.h
// interface
//
// Created by Tobias Schwinger on 3/29/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__starfield__Loader__
#define __interface__starfield__Loader__
#ifndef __interface__Starfield_impl__
#error "This is an implementation file - not intended for direct inclusion."
#endif
#include <locale.h>
#include "Config.h"
#include "starfield/data/InputVertex.h"
#include "starfield/data/BrightnessLevel.h"
namespace starfield {
class Loader : UrlReader {
public:
bool loadVertices(
InputVertices& destination, char const* url, char const* cacheFile, unsigned limit)
{
_vertices = & destination;
_limit = limit;
#if STARFIELD_SAVE_MEMORY
if (_limit == 0 || _limit > 60000u)
_limit = 60000u;
#endif
_urlStr = url; // in case we fail early
if (! UrlReader::readUrl(url, *this, cacheFile))
{
qDebug("%s:%d: %s\n",
_urlStr, _lineNo, getError());
return false;
}
qDebug("Loaded %u stars.\n", _recordsRead);
return true;
}
protected:
friend class UrlReader;
void begin(char const* url,
char const* type,
int64_t size,
int64_t stardate) {
_lineNo = 0u;
_urlStr = url; // new value in http redirect
_recordsRead = 0u;
_vertices->clear();
_vertices->reserve(_limit);
// qDebug("Stars.cpp: loader begin %s\n", url);
}
size_t transfer(char* input, size_t bytes) {
size_t consumed = 0u;
char const* end = input + bytes;
char* line, * next = input;
for (;;) {
// advance to next line
for (; next != end && isspace(*next); ++next);
consumed = next - input;
line = next;
++_lineNo;
for (; next != end && *next != '\n' && *next != '\r'; ++next);
if (next == end)
return consumed;
*next++ = '\0';
// skip comments
if (*line == '\\' || *line == '/' || *line == ';')
continue;
// parse
float azi, alt;
unsigned c;
setlocale(LC_NUMERIC, "C");
if (sscanf(line, " %f %f #%x", & azi, & alt, & c) == 3) {
if (spaceFor( getBrightness(c) )) {
storeVertex(azi, alt, c);
}
++_recordsRead;
} else {
qDebug("Stars.cpp:%d: Bad input from %s\n",
_lineNo, _urlStr);
}
}
return consumed;
}
void end(bool ok)
{ }
private:
bool atLimit() { return _limit > 0u && _recordsRead >= _limit; }
bool spaceFor(BrightnessLevel b) {
if (! atLimit()) {
return true;
}
// just reached the limit? -> establish a minimum heap and
// remember the brightness at its top
if (_recordsRead == _limit) {
// qDebug("Stars.cpp: vertex limit reached -> heap mode\n");
make_heap(
_vertices->begin(), _vertices->end(),
GreaterBrightness() );
_minBrightness = getBrightness(
_vertices->begin()->getColor() );
}
// not interested? say so
if (_minBrightness >= b)
return false;
// otherwise free up space for the new vertex
pop_heap(
_vertices->begin(), _vertices->end(),
GreaterBrightness() );
_vertices->pop_back();
return true;
}
void storeVertex(float azi, float alt, unsigned color) {
_vertices->push_back(InputVertex(azi, alt, color));
if (atLimit()) {
push_heap(
_vertices->begin(), _vertices->end(),
GreaterBrightness() );
_minBrightness = getBrightness(
_vertices->begin()->getColor() );
}
}
// variables
InputVertices* _vertices;
unsigned _limit;
unsigned _lineNo;
char const* _urlStr;
unsigned _recordsRead;
BrightnessLevel _minBrightness;
};
} // anonymous namespace
#endif

View file

@ -24,10 +24,6 @@ set(EXTERNAL_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external)
if (WIN32)
# include headers for external libraries and InterfaceConfig.
include_directories(${EXTERNAL_ROOT_DIR})
else (WIN32)
find_package(CURL REQUIRED)
include_directories(${CURL_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${CURL_LIBRARY})
endif (WIN32)
# link required libraries on UNIX

View file

@ -1,172 +0,0 @@
//
// UrlReader.cpp
// hifi
//
// Created by Tobias Schwinger on 3/21/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include <new>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
// (Windows port is incomplete and the build files do not support CURL, yet)
#include <curl/curl.h>
#include "UrlReader.h"
//
// ATTENTION: A certain part of the implementation lives in inlined code
// (see the bottom of the header file).
//
// Why? Because it allows stream parsing without having to call around a
// lot (one static and one dynamic call per character if the parser just
// reads one character at a time).
//
// Here is an overview of the code structure:
//
// readUrl
// -> transferBegin (sets up state)
// -> perform (starts CURL transfer)
// -> (specialized, type-erased) callback_template
// -> getInfo (fetches HTTP header, eventually initiates caching)
// -> stream.begin (client code - called once)
// -> feedBuffered (the buffering logic)
// -> stream.transfer (client code - called repeatedly)
// -> stream.end (client code - called when the transfer is done)
// -> transferEnd (closes cache file, if used)
//
// "->" means "calls or inlines", here
//
size_t const UrlReader::max_read_ahead = CURL_MAX_WRITE_SIZE;
char const* const UrlReader::success = "UrlReader: Success!";
char const* const UrlReader::success_cached = "UrlReader: Using local file.";
char const* const UrlReader::error_init_failed = "UrlReader: Initialization failed.";
char const* const UrlReader::error_aborted = "UrlReader: Processing error.";
char const* const UrlReader::error_buffer_overflow = "UrlReader: Buffer overflow.";
char const* const UrlReader::error_leftover_input = "UrlReader: Incomplete processing.";
#define _curlPtr static_cast<CURL*>(_curlHandle)
UrlReader::UrlReader()
: _curlHandle(0l), _xtraBuffer(0l), _errorStr(0l), _cacheReadBuffer(0l) {
_xtraBuffer = new(std::nothrow) char[max_read_ahead];
if (! _xtraBuffer) { _errorStr = error_init_failed; return; }
_curlHandle = curl_easy_init();
if (! _curlHandle) { _errorStr = error_init_failed; return; }
curl_easy_setopt(_curlPtr, CURLOPT_NOSIGNAL, 1l);
curl_easy_setopt(_curlPtr, CURLOPT_FAILONERROR, 1l);
curl_easy_setopt(_curlPtr, CURLOPT_FILETIME, 1l);
curl_easy_setopt(_curlPtr, CURLOPT_ENCODING, "");
}
UrlReader::~UrlReader() {
delete[] _xtraBuffer;
delete[] _cacheReadBuffer;
if (! _curlHandle) {
return;
}
curl_easy_cleanup(_curlPtr);
}
void UrlReader::perform(char const* url, transfer_callback* cb) {
curl_easy_setopt(_curlPtr, CURLOPT_URL, url);
curl_easy_setopt(_curlPtr, CURLOPT_WRITEFUNCTION, cb);
curl_easy_setopt(_curlPtr, CURLOPT_WRITEDATA, this);
CURLcode rc = curl_easy_perform(_curlPtr);
if (rc == CURLE_OK)
{
while (_xtraSize > 0 && _errorStr == success)
cb(0l, 0, 0, this);
}
else if (_errorStr == success)
_errorStr = curl_easy_strerror(rc);
}
void UrlReader::transferBegin(void* stream, char const* cacheFile) {
_errorStr = success;
_streamPtr = stream;
_cacheFileName = cacheFile;
_cacheFile = 0l;
_cacheMode = no_cache;
_xtraSize = ~size_t(0);
}
void UrlReader::getInfo(char const*& url,
char const*& type, int64_t& length, int64_t& stardate) {
// fetch information from HTTP header
double clen;
long time;
curl_easy_getinfo(_curlPtr, CURLINFO_FILETIME, & time);
curl_easy_getinfo(_curlPtr, CURLINFO_EFFECTIVE_URL, & url);
curl_easy_getinfo(_curlPtr, CURLINFO_CONTENT_TYPE, & type);
curl_easy_getinfo(_curlPtr, CURLINFO_CONTENT_LENGTH_DOWNLOAD, & clen);
length = static_cast<int64_t>(clen);
curl_easy_getinfo(_curlPtr, CURLINFO_FILETIME, & time);
stardate = time;
// printLog("UrlReader: Ready to transfer from URL '%s'\n", url);
// check caching file time whether we actually want to download anything
if (_cacheFileName != 0l) {
struct stat s;
stat(_cacheFileName, & s);
if (time > s.st_mtime) {
// file on server is newer -> update cache file
_cacheFile = fopen(_cacheFileName, "wb");
// printLog("UrlReader: Also writing content to cache file '%s'\n", _cacheFileName);
if (_cacheFile != 0l) {
_cacheMode = cache_write;
}
} else {
// file on server is older -> use cache file
if (! _cacheReadBuffer) {
_cacheReadBuffer = new (std::nothrow) char[max_read_ahead];
if (! _cacheReadBuffer) {
// out of memory, no caching, have CURL catch it
return;
}
}
_cacheFile = fopen(_cacheFileName, "rb");
// printLog("UrlReader: Delivering cached content from file '%s'\n", _cacheFileName);
if (_cacheFile != 0l) {
_cacheMode = cache_read;
}
// override error code returned by CURL when we abort the download
_errorStr = success_cached;
}
}
}
void UrlReader::transferEnd() {
if (_cacheFile != 0l) {
fclose(_cacheFile);
}
}
#else // no-op version for incomplete Windows build:
UrlReader::UrlReader() : _curlHandle(0l) { }
UrlReader::~UrlReader() { }
void UrlReader::perform(char const* url, transfer_callback* cb) { }
void UrlReader::transferBegin(void* stream, char const* cacheFile) { }
void UrlReader::getInfo(char const*& url, char const*& type,
int64_t& length, int64_t& stardate) { }
void UrlReader::transferEnd() { }
#endif

View file

@ -1,305 +0,0 @@
//
// UrlReader.h
// hifi
//
// Created by Tobias Schwinger on 3/21/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __hifi__UrlReader__
#define __hifi__UrlReader__
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
//
// UrlReader class that encapsulates a context for sequential data retrieval
// via URLs. Use one per thread.
//
class UrlReader {
public:
//
// Constructor - performs initialization, never throws.
//
UrlReader();
//
// Destructor - frees resources, never throws.
//
~UrlReader();
//
// Reads data from an URL and forwards it to the instance of a class
// fulfilling the ContentStream concept.
//
// The call protocol on the ContentStream is detailed as follows:
//
// 1. begin(char const* url,
// char const* content_type, uint64_t bytes, uint64_t stardate)
//
// All information except 'url' is optional; 'content_type' can
// be a null pointer - 'bytes' and 'stardate' can be equal to
// to 'unavailable'.
//
// 2. transfer(char* buffer, size_t bytes)
//
// Called until all data has been received. The number of bytes
// actually processed should be returned.
// Unprocessed data is stored in an extra buffer whose size is
// given by the constant UrlReader::max_read_ahead - it can be
// assumed to be reasonably large for on-the-fly parsing.
//
// 3. end(bool ok)
//
// Called at the end of the transfer.
//
// Returns the same success code
//
template< class ContentStream >
bool readUrl(char const* url, ContentStream& s, char const* cacheFile = 0l);
//
// Returns a pointer to a static C-string that describes the error
// condition.
//
inline char const* getError() const;
//
// Can be called by the stream to set a user-defined error string.
//
inline void setError(char const* static_c_string);
//
// Pointer to the C-string returned by a call to 'readUrl' when no
// error occurred.
//
static char const* const success;
//
// Pointer to the C-string returned by a call to 'readUrl' when no
// error occurred and a local file has been read instead of the
// network stream.
//
static char const* const success_cached;
//
// Pointer to the C-string returned by a call to 'readUrl' when the
// initialization has failed.
//
static char const* const error_init_failed;
//
// Pointer to the C-string returned by a call to 'readUrl' when the
// transfer has been aborted by the client.
//
static char const* const error_aborted;
//
// Pointer to the C-string returned by a call to 'readUrl' when
// leftover input from incomplete processing caused a buffer
// overflow.
//
static char const* const error_buffer_overflow;
//
// Pointer to the C-string return by a call to 'readUrl' when the
// input provided was not completely consumed.
//
static char const* const error_leftover_input;
//
// Constant of the maximum number of bytes that are buffered
// between invocations of 'transfer'.
//
static size_t const max_read_ahead;
//
// Constant representing absent information in the call to the
// 'begin' member function of the target stream.
//
static int const unavailable = -1;
//
// Constant for requesting to abort the current transfer when
// returned by the 'transfer' member function of the target stream.
//
static size_t const abort = ~0u;
private:
// instances of this class shall not be copied
UrlReader(UrlReader const&); // = delete;
UrlReader& operator=(UrlReader const&); // = delete;
inline bool isSuccess();
// entrypoints to compiled code
typedef size_t transfer_callback(char*, size_t, size_t, void*);
enum CacheMode { no_cache, cache_write, cache_read };
void transferBegin(void* stream, char const* cacheFile);
void transferEnd();
void perform(char const* url, transfer_callback* transfer);
void getInfo(char const*& url,
char const*& type, int64_t& length, int64_t& stardate);
// synthesized callback
template< class Stream > static size_t callback_template(char *input, size_t size,
size_t nmemb, void* thiz);
template< class Stream > size_t feedBuffered(Stream* stream,
char* input, size_t size);
// state
void* _curlHandle;
char* _xtraBuffer;
char const* _errorStr;
void* _streamPtr;
char const* _cacheFileName;
FILE* _cacheFile;
char* _cacheReadBuffer;
CacheMode _cacheMode;
size_t _xtraSize;
};
// inline functions
inline char const* UrlReader::getError() const {
return _errorStr;
}
bool UrlReader::isSuccess() {
return _errorStr == success || _errorStr == success_cached;
}
template< class ContentStream >
bool UrlReader::readUrl(char const* url, ContentStream& s, char const* cacheFile) {
if (! _curlHandle) return false;
this->transferBegin(& s, cacheFile);
this->perform(url, & callback_template<ContentStream>);
this->transferEnd();
bool ok = isSuccess();
s.end(ok);
return ok;
}
inline void UrlReader::setError(char const* staticCstring) {
if (this->isSuccess())
this->_errorStr = staticCstring;
}
template< class Stream >
size_t UrlReader::feedBuffered(Stream* stream, char* input, size_t size) {
size_t inputOffset = 0u;
while (true) {
char* buffer = input + inputOffset;
size_t bytes = size - inputOffset;
// data in extra buffer?
if (_xtraSize > 0) {
// fill extra buffer with beginning of input
size_t fill = max_read_ahead - _xtraSize;
if (bytes < fill) fill = bytes;
memcpy(_xtraBuffer + _xtraSize, buffer, fill);
// use extra buffer for next transfer
buffer = _xtraBuffer;
bytes = _xtraSize + fill;
inputOffset += fill;
}
// call 'transfer'
size_t processed = stream->transfer(buffer, bytes);
if (processed == abort) {
setError(error_aborted);
return 0u;
} else if (! processed && ! input) {
setError(error_leftover_input);
return 0u;
}
size_t unprocessed = bytes - processed;
// can switch to input buffer, now?
if (buffer == _xtraBuffer && unprocessed <= inputOffset) {
_xtraSize = 0u;
inputOffset -= unprocessed;
} else { // no? unprocessed data -> extra buffer
if (unprocessed > max_read_ahead) {
setError(error_buffer_overflow);
return 0;
}
_xtraSize = unprocessed;
memmove(_xtraBuffer, buffer + processed, unprocessed);
if (inputOffset == size || buffer != _xtraBuffer) {
return size;
}
}
} // while
}
template< class Stream >
size_t UrlReader::callback_template(char *input, size_t size, size_t nmemb, void* thiz) {
size_t result = 0u;
UrlReader* me = static_cast<UrlReader*>(thiz);
Stream* stream = static_cast<Stream*>(me->_streamPtr);
size *= nmemb;
// first call?
if (me->_xtraSize == ~size_t(0)) {
me->_xtraSize = 0u;
// extract meta information and call 'begin'
char const* url, * type;
int64_t length, stardate;
me->getInfo(url, type, length, stardate);
if (me->_cacheMode != cache_read) {
stream->begin(url, type, length, stardate);
}
}
do {
// will have to repeat from here when reading a local file
// read from cache file?
if (me->_cacheMode == cache_read) {
// change input buffer and start
input = me->_cacheReadBuffer;
size = fread(input, 1, max_read_ahead, me->_cacheFile);
nmemb = 1;
} else if (me->_cacheMode == cache_write) {
fwrite(input, 1, size, me->_cacheFile);
}
result = me->feedBuffered(stream, input, size);
} while (me->_cacheMode == cache_read && result != 0 && ! feof(me->_cacheFile));
return me->_cacheMode != cache_read ? result : 0;
}
#endif /* defined(__hifi__UrlReader__) */