Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F126017
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
48 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/util/ftalleg.cpp b/util/ftalleg.cpp
index 639b4527..45756c78 100644
--- a/util/ftalleg.cpp
+++ b/util/ftalleg.cpp
@@ -1,740 +1,742 @@
/*
--------------
About
--------------
A Freetype wrapper for use with allegro
Feel free to do whatever you like with this, by all means enjoy!
Just add it to your project
--------------
Linking
--------------
on linux:
g++ `freetype-config --cflags` ftalleg.cpp myfiles.cpp `freetype-config --libs` `allegro-config --libs`
on windows (you may need to include the freetype dir location, ie -Ic:/mingw/include):
g++ ftalleg.cpp myfiles.cpp -lfreetype -lalleg
--------------
Disclaimer
--------------
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE
SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef FT_FONT_CPP
#define FT_FONT_CPP
#include "bitmap.h"
/*
#include <allegro.h>
#ifdef _WIN32
#include <winalleg.h>
#endif
*/
#include "ftalleg.h"
#include <iostream>
#include <sstream>
#include <cassert>
#include <exception>
#ifdef USE_ALLEGRO5
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#endif
namespace ftalleg{
Exception::Exception():
std::exception(){
}
Exception::Exception(const std::string reason):
std::exception(),
reason(reason){
}
Exception::~Exception() throw(){
}
// typedef void (*pixeler)( BITMAP * bitmap, int x, int y, int color );
static Graphics::Color fixColor(const unsigned char c, short grays){
// Safety checks
// assert(c != 0);
assert(grays != 1);
// invariant: c can be dereferenced safely
// invariant: (grays - 1) != 0, thus it can be used as divisor.
int red = c * 255 / (grays - 1);
int green = c * 255 / (grays - 1);
int blue = c * 255 / (grays - 1);
//alpha = *c * 255 / (grays - 1);
return Graphics::makeColor(red,green,blue);
}
// Static count of instances of fonts to track library
static int instances = 0;
static FT_Library ftLibrary = 0;
character::character() {
}
character::~character() {
if (line){
delete [] line;
}
}
fontSize::fontSize() {
width = height = italics = angle = 0;
}
fontSize::fontSize(int width, int height):
width(width),
height(height),
italics(0),
angle(0){
}
fontSize::~fontSize() {
}
bool fontSize::operator<(const fontSize &fs) const {
return (width<fs.width || height<fs.height || italics<fs.italics);
}
/* im not sure this is a very unique key.. */
int fontSize::createKey() const {
return ((width+10) * (height+20) * (italics+250));
}
#ifdef USE_ALLEGRO5
freetype::freetype(const Filesystem::AbsolutePath & path, const int x, const int y):
alive(5, 5),
path(path),
width(x),
height(y),
original_size(x){
if (instances == 0){
al_init_font_addon();
al_init_ttf_addon();
}
instances += 1;
int flags = al_get_new_bitmap_flags();
/* memory fonts must live in memory */
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
fonts[width].memory = al_load_font(path.path().c_str(), width, 0);
al_set_new_bitmap_flags(flags);
fonts[width].video = al_load_font(path.path().c_str(), width, 0);
}
freetype::~freetype(){
for (std::map<int, FontUse>::iterator it = fonts.begin(); it != fonts.end(); it++){
FontUse & font = it->second;
al_destroy_font(font.memory);
al_destroy_font(font.video);
}
instances -= 1;
if (instances == 0){
al_shutdown_font_addon();
}
}
ALLEGRO_FONT * freetype::currentMemoryFont() const {
std::map<int, FontUse>::const_iterator find = fonts.find(width);
if (find == fonts.end()){
throw Exception("inconsistency error");
}
return find->second.memory;
}
ALLEGRO_FONT * freetype::currentVideoFont() const {
std::map<int, FontUse>::const_iterator find = fonts.find(width);
if (find == fonts.end()){
throw Exception("inconsistency error");
}
return find->second.video;
}
int freetype::getHeight(const std::string & str) const {
Util::Thread::ScopedLock locked(lock);
/* sort of a hack but we need to set the display to the screen. with
* allegro5 the screen buffer will be the actual screen so no allocation
* will occur.
*/
// al_set_target_bitmap(alive.getData().getBitmap());
ALLEGRO_BITMAP * target = al_get_target_bitmap();
al_set_target_bitmap(NULL);
int height = al_get_font_line_height(currentMemoryFont());
al_set_target_bitmap(target);
return height;
}
int freetype::getLength(const std::string & text) const {
Util::Thread::ScopedLock locked(lock);
// al_set_target_bitmap(alive.getData().getBitmap());
ALLEGRO_BITMAP * target = al_get_target_bitmap();
al_set_target_bitmap(NULL);
int width = al_get_text_width(currentMemoryFont(), text.c_str());
al_set_target_bitmap(target);
return width;
}
void freetype::setSize(unsigned int w, unsigned int h){
Util::Thread::ScopedLock locked(lock);
width = w;
height = h;
if (fonts.find(width) == fonts.end()){
fonts[width].memory = al_load_font(path.path().c_str(), width, 0);
fonts[width].video = al_load_font(path.path().c_str(), width, 0);
}
}
void freetype::getSize(int * w, int * h) const {
Util::Thread::ScopedLock locked(lock);
*w = width;
*h = height;
}
void freetype::render(int x, int y, const Graphics::Color & color, const Graphics::Bitmap & bmp, ftAlign alignment, const std::string & text, int marker, ...){
Util::Thread::ScopedLock locked(lock);
std::ostringstream str;
/* use vsnprintf/Util::limitPrintf here? */
// Get extra arguments
va_list ap;
va_start(ap, marker);
for(unsigned int i = 0; i<text.length();++i) {
if (text[i] == '%') {
if(text[i+1]=='s') {
str << va_arg(ap, char *);
++i;
} else if(text[i+1]=='d'||text[i+1]=='i') {
str << va_arg(ap, signed int);
++i;
} else if(text[i+1]=='c') {
str << (char)va_arg(ap, int);
++i;
} else str << text[i];
} else {
str << text[i];
}
}
va_end(ap);
std::string fixedText(str.str());
al_set_target_bitmap(bmp.getData()->getBitmap());
al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
/* for setting the blend state and whatnot */
bmp.startDrawing();
al_draw_text(currentVideoFont(), bmp.blendColor(color), x, y, 0, fixedText.c_str());
bmp.endDrawing();
}
#else
//! Constructor
freetype::freetype(const Filesystem::AbsolutePath & str, const int x, const int y ):
face(NULL){
//Load library
if (!ftLibrary){
FT_Init_FreeType(&ftLibrary);
}
instances += 1;
faceLoaded = kerning = false;
currentIndex = 0;
currentFilename = "";
faceName = "";
// currentChar = new character;
systemName = "";
internalFix = false;
this->load(str, 0, x, y );
}
//! Destructor
freetype::~freetype(){
//if(face!=NULL)FT_Done_Face(face);
if (faceLoaded && face != NULL){
FT_Done_Face(face);
face = NULL;
}
instances -= 1;
if (instances == 0){
FT_Done_FreeType(ftLibrary);
ftLibrary = NULL;
}
destroyGlyphIndex();
/*
if ( currentChar ){
delete currentChar;
}
*/
}
void freetype::destroyGlyphIndex(){
for (std::map<int, std::map<signed long, character*> >::iterator i1 = fontTable.begin(); i1 != fontTable.end(); i1++){
std::map<signed long, character*> & characters = (*i1).second;
for (std::map<signed long, character*>::iterator i2 = characters.begin(); i2 != characters.end(); i2++){
character * character = (*i2).second;
delete character;
}
}
}
// Extract glyph
character * freetype::extractGlyph(signed long unicode){
int w, h, ew;
character * tempChar = new character();
// Translate it according to the given italics
double italics = (double)(size.italics)*GLYPH_PI/180;
FT_Matrix matrix;
matrix.xx = 0x10000L;
matrix.xy = (FT_Fixed)( sin( italics ) * (GLYPH_SQRT2*0x10000L) );
matrix.yx = 0;
matrix.yy = 0x10000L;
FT_Set_Transform( face, &matrix, 0 );
FT_Load_Char(face, unicode, FT_LOAD_TARGET_NORMAL | FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT);
w = face->glyph->bitmap.width;
h = face->glyph->bitmap.rows;
ew = 0;
if (!w)ew = 1;
if (!h)h = 1;
tempChar->width = (w + ew);
tempChar->height = h;
tempChar->rows = face->glyph->bitmap.rows;
tempChar->grays = face->glyph->bitmap.num_grays;
tempChar->pitch = face->glyph->bitmap.pitch;
tempChar->line = new unsigned char[tempChar->rows * tempChar->pitch];
memcpy(tempChar->line, face->glyph->bitmap.buffer, tempChar->rows * tempChar->pitch);
tempChar->left = face->glyph->bitmap_left;
tempChar->top = face->glyph->bitmap_top;
tempChar->right = face->glyph->advance.x >> 6;
tempChar->unicode = unicode;
tempChar->length = ((w + ew)+face->glyph->advance.x) >> 6;
return tempChar;
}
// Create single index
void freetype::createIndex(){
std::map<int, std::map<signed long, character*> >::iterator p;
p = fontTable.find(size.createKey());
if (p == fontTable.end()){
FT_Set_Pixel_Sizes(face, size.width, size.height);
FT_UInt glyphIndex;
FT_ULong unicode = FT_Get_First_Char(face, &glyphIndex);
std::map<signed long, character*> tempMap;
while (glyphIndex != 0){
tempMap.insert(std::make_pair(unicode, extractGlyph(unicode)));
unicode = FT_Get_Next_Char(face, unicode, &glyphIndex);
}
fontTable.insert(std::make_pair(size.createKey(), tempMap));
}
if (fontTable.find(size.createKey()) == fontTable.end()){
printf("ftalleg: inconsistency error\n");
throw std::exception();
}
}
/*
pixeler getPutPixel(){
switch( get_color_depth() ){
case 8 : return _putpixel;
case 15 : return _putpixel15;
case 16 : return _putpixel16;
case 24 : return _putpixel24;
case 32 : return _putpixel32;
default : return putpixel;
}
}
*/
void drawOneCharacter(const character * tempChar, int & x1, int & y1, FT_UInt sizeHeight, const Graphics::Bitmap & bitmap, const Graphics::Color & color){
unsigned char * line = tempChar->line;
int colorRed = Graphics::getRed(color);
int colorGreen = Graphics::getGreen(color);
int colorBlue = Graphics::getBlue(color);
/* cache the last color, there is a good chance it will be reused */
unsigned char lastData = -1;
short lastGrays = -1;
Graphics::Color black = Graphics::makeColor(0, 0, 0);
Graphics::Color lastColor = black;
for (int y = 0; y < tempChar->rows; y++){
unsigned char * buffer = line;
for (int x = 0; x < tempChar->width; x++){
Graphics::Color finalColor = black;
unsigned char current = *buffer;
buffer++;
if (current == lastData && lastGrays == tempChar->grays){
finalColor = lastColor;
} else {
Graphics::Color col = fixColor(current, tempChar->grays);
int red = Graphics::getRed(col);
int green = Graphics::getGreen(col);
int blue = Graphics::getBlue(col);
if ((red < 50) ||
(green < 50) ||
(blue < 50)){
continue;
}
red = red * colorRed / 255;
green = green * colorGreen / 255;
blue = blue * colorBlue / 255;
finalColor = Graphics::makeColor(red, green, blue);
lastData = current;
lastColor = finalColor;
lastGrays = tempChar->grays;
}
//col.alpha= col.alpha * color.alpha / 255;
// putpixel(bitmap,x1+tempChar.left+x,y1 - tempChar.top+y + size.height,makecol(red,blue,green));
/* dangerous! putter is probably one of the _putpixel* routines so if x or y are off the bitmap
* you will get a segfault
*/
// putter(bitmap,x1+tempChar.left+x,y1 - tempChar.top+y + size.height,makecol(red,blue,green));
// putter = 0;
int finalX = x1+tempChar->left+x;
int finalY = y1 - tempChar->top + y + sizeHeight;
bitmap.putPixelNormal(finalX, finalY, finalColor);
}
line += tempChar->pitch;
}
x1 += tempChar->right;
}
// Render a character from the lookup table
void freetype::drawCharacter(signed long unicode, int &x1, int &y1, const Graphics::Bitmap & bitmap, const Graphics::Color &color){
// pixeler putter = getPutPixel();
std::map<int, std::map<signed long, character*> >::iterator ft;
ft = fontTable.find(size.createKey());
if (ft != fontTable.end()){
std::map<signed long, character*>::iterator p;
p = (ft->second).find(unicode);
if (p != ft->second.end()){
const character * tempChar = p->second;
drawOneCharacter(tempChar, x1, y1, size.height, bitmap, color);
}
}
}
//! Load font from memory
bool freetype::load(const unsigned char *memoryFont, unsigned int length, int index, unsigned int width, unsigned int height) {
if(!FT_New_Memory_Face(ftLibrary,memoryFont, length,index,&face)) {
currentFilename = "memoryFont";
currentIndex = index;
faceLoaded = true;
size.italics = 0;
setSize(width, height);
if (FT_HAS_GLYPH_NAMES(face)){
char buff[1024];
if(!FT_Get_Glyph_Name(face, currentIndex,buff, sizeof(buff))){
faceName = currentFilename;
}
else faceName = std::string(buff);
} else {
faceName = currentFilename;
}
if(FT_HAS_KERNING(face))kerning=true;
else kerning = false;
} else {
faceLoaded=false;
std::cout << "Load system font failed\n";
}
return faceLoaded;
}
//! Load font from file
bool freetype::load(const Filesystem::AbsolutePath & filename, int index, unsigned int width, unsigned int height){
FT_Error error = FT_New_Face(ftLibrary, filename.path().c_str(), index, &face);
if (error == 0){
currentFilename = filename.path();
currentIndex = index;
faceLoaded = true;
size.italics = 0;
setSize(width, height);
if (FT_HAS_GLYPH_NAMES(face)){
char buff[1024];
if (!FT_Get_Glyph_Name(face, currentIndex, buff, sizeof(buff))) {
faceName = currentFilename;
} else {
faceName = std::string(buff);
}
} else {
faceName = currentFilename;
}
kerning = FT_HAS_KERNING(face);
} else {
faceLoaded = false;
std::ostringstream fail;
- fail << "Could not load freetype font " << filename.path();
+ fail << "Could not load freetype font " << filename.path() << " error code " << error;
throw Exception(fail.str());
}
return faceLoaded;
}
- /* utf8 decoding */
+ /* utf8 decoding
+ * FIXME: handle the case when `position' runs out of bytes
+ */
static long decodeUnicode(const std::string & input, unsigned int * position){
unsigned char byte1 = (unsigned char) input[*position];
/* one byte - ascii */
if (byte1 >> 7 == 0){
return byte1;
}
if (byte1 >> 5 == 6){
*position += 1;
unsigned char byte2 = (unsigned char) input[*position];
int top = byte1 & 31;
int bottom = byte2 & 63;
return (top << 6) + bottom;
}
if (byte1 >> 4 == 14){
*position += 1;
unsigned char byte2 = (unsigned char) input[*position];
*position += 1;
unsigned char byte3 = (unsigned char) input[*position];
int top4 = byte1 & 15;
int middle6 = byte2 & 63;
int bottom6 = byte3 & 63;
return (top4 << (6+6)) + (middle6 << 6) + bottom6;
}
if (byte1 >> 3 == 30){
*position += 1;
unsigned char byte2 = (unsigned char) input[*position];
*position += 1;
unsigned char byte3 = (unsigned char) input[*position];
*position += 1;
unsigned char byte4 = (unsigned char) input[*position];
int unit1 = byte1 & 7;
int unit2 = byte2 & 63;
int unit3 = byte3 & 63;
int unit4 = byte4 & 63;
return (unit1 << 18) + (unit2 << 12) + (unit3 << 6) + unit4;
}
return 0;
}
//! Get text length
int freetype::getLength(const std::string & text) {
Util::Thread::ScopedLock locked(lock);
int length=0;
std::map<int, std::map<signed long, character*> >::iterator ft;
ft = fontTable.find(size.createKey());
if (ft != fontTable.end()){
for (unsigned int i = 0; i < text.length(); i++) {
std::map<signed long, character*>::iterator p;
signed long unicode = decodeUnicode(text, &i);
p = (ft->second).find(unicode);
if (p != (ft->second).end()){
if (p != fontTable[size.createKey()].end()){
length += (p->second)->length;
}
}
}
}
return length;
}
//! Render font to a bitmap
void freetype::render(int x, int y, const Graphics::Color & color, const Graphics::Bitmap & bmp, ftAlign alignment, const std::string & text, int marker ...) {
if (faceLoaded){
int rend_x = 0;
int rend_y = 0;
std::ostringstream str;
/* use vsnprintf/Util::limitPrintf here? */
// Get extra arguments
va_list ap;
va_start(ap, marker);
for(unsigned int i = 0; i<text.length();++i) {
if (text[i] == '%') {
if(text[i+1]=='s') {
str << va_arg(ap, char *);
++i;
} else if(text[i+1]=='d'||text[i+1]=='i') {
str << va_arg(ap, signed int);
++i;
} else if(text[i+1]=='c') {
str << (char)va_arg(ap, int);
++i;
} else str << text[i];
} else {
str << text[i];
}
}
va_end(ap);
std::string fixedText(str.str());
switch (alignment) {
case ftLeft:
rend_x = x;
rend_y = y;
break;
case ftCenter:
rend_x = x - getLength(fixedText)/2;
rend_y = y;
break;
case ftRight:
rend_x = x - getLength(fixedText);
rend_y = y;
break;
default:
rend_x = x;
rend_y = y;
break;
}
int previous = 0;
int next = 0;
for (unsigned int i = 0; i<fixedText.length(); i++){
long unicode = decodeUnicode(fixedText, &i);
if (kerning && previous && next){
next = FT_Get_Char_Index(face, unicode);
FT_Vector delta;
FT_Get_Kerning(face, previous, next, FT_KERNING_DEFAULT, &delta);
rend_x += delta.x >> 6;
previous = next;
}
drawCharacter(unicode, rend_x, rend_y, bmp, color);
}
}
}
int freetype::calculateMaximumHeight(){
Util::Thread::ScopedLock locked(lock);
/* uhh, comment out the printf's ?? */
std::map<int, std::map<signed long, character*> >::iterator ft;
ft = fontTable.find(size.createKey());
int top = 0;
long code = 0;
if ( ft != fontTable.end() ){
std::map<signed long, character*>::iterator p;
std::map< signed long, character* > & map = ft->second;
for ( p = map.begin(); p != map.end(); p++ ){
const character * ch = p->second;
printf( "%c( %ld ). top = %d. rows = %d. total = %d\n", (char) ch->unicode, ch->unicode, ch->top, ch->rows, ch->top + ch->rows );
if ( ch->top + ch->rows > top ){
code = ch->unicode;
top = ch->top + ch->rows;
}
}
}
printf( "Largest letter = %ld\n", code );
return top;
}
int freetype::height(long code) const {
Util::Thread::ScopedLock locked(lock);
std::map<int, std::map<signed long, character*> >::const_iterator ft;
ft = fontTable.find(size.createKey());
if (ft != fontTable.end()){
std::map<signed long, character*>::const_iterator p;
p = (ft->second).find( code );
if ( p != (ft->second).end() ){
const character * temp = p->second;
// printf( "%c top = %d rows = %d\n", (char) code, temp.top, temp.rows );
return temp->top + temp->rows;
}
} else {
throw Exception("Internal inconsistency");
}
return 0;
}
int freetype::calculateHeight(const std::string & str) const {
int max = 0;
for ( unsigned int i = 0; i < str.length(); i++ ){
int q = height(str[i]);
// printf( "Height of %c is %d\n", str[ i ], q );
if (q > max){
max = q;
}
}
return max;
}
//! Set size
void freetype::setSize( unsigned int w, unsigned int h){
Util::Thread::ScopedLock locked(lock);
if ( w != size.width || h != size.height ){
if (internalFix)return;
if (w<=0 || h<=0)return;
size.width = w;
size.height = h;
createIndex();
// maximumHeight = calculateMaximumHeight();
}
}
//! Set italics
void freetype::setItalics(int i){
Util::Thread::ScopedLock locked(lock);
if(internalFix)return;
if(i<-45)i=(-45);
else if(i>45)i=45;
size.italics = i;
createIndex();
}
void freetype::getSize(int * w, int * h) const {
*w = size.width;
*h = size.height;
}
//! Get Width
int freetype::getWidth() const {
return size.width;
}
//! Get Height
int freetype::getHeight( const std::string & str ) const {
// return size.height;
return calculateHeight(str);
}
//! Get Italics
int freetype::getItalics(){
return size.italics;
}
#endif
}
#endif /* FONT_BASE_CPP */
diff --git a/util/nacl/network-system.cpp b/util/nacl/network-system.cpp
index b4569058..b55c8da5 100644
--- a/util/nacl/network-system.cpp
+++ b/util/nacl/network-system.cpp
@@ -1,823 +1,825 @@
#ifdef NACL
/* documentation for ppapi
* http://code.google.com/chrome/nativeclient/docs/reference/peppercpp/inherits.html
*/
/* issues with getting data
* 1. the function that starts the game is called from the main chrome thread
* which starts from a javascript call to module.PostMessage('run').
* ...
*
*/
#include <unistd.h>
#include <errno.h>
#include "network-system.h"
#include "../funcs.h"
#include "../debug.h"
#include <ppapi/c/pp_errors.h>
#include <ppapi/cpp/url_loader.h>
#include <ppapi/cpp/url_request_info.h>
#include <ppapi/cpp/url_response_info.h>
#include <ppapi/c/ppb_url_request_info.h>
#include <ppapi/cpp/completion_callback.h>
using std::string;
using std::map;
namespace Nacl{
static const char * CONTEXT = "nacl";
typedef Path::AbsolutePath AbsolutePath;
typedef Path::RelativePath RelativePath;
enum RequestType{
Exists
};
struct Request{
RequestType type;
AbsolutePath absolute;
RelativePath relative;
bool complete;
bool success;
};
Request operation;
struct NaclRequest{
virtual ~NaclRequest(){
}
virtual void start() = 0;
};
struct NaclRequestOpen: public NaclRequest {
NaclRequestOpen(pp::Instance * instance, const string & url, Manager * manager):
request(instance),
loader(instance),
url(url),
manager(manager){
request.SetURL(url);
request.SetMethod("GET");
// request.SetProperty(PP_URLREQUESTPROPERTY_RECORDDOWNLOADPROGRESS, pp::Var((bool) PP_TRUE));
}
void start(){
Global::debug(1) << "Request open for url " << url << std::endl;
pp::CompletionCallback callback(&NaclRequestOpen::onFinish, this);
int32_t ok = loader.Open(request, callback);
Global::debug(1) << "Open " << ok << std::endl;
if (ok != PP_OK_COMPLETIONPENDING){
// Global::debug(0) << "Call on main thread" << std::endl;
// core->CallOnMainThread(0, callback, ok);
callback.Run(ok);
}
- Global::debug(1) << "Callback running" << std::endl;
+ // Global::debug(1) << "Callback running" << std::endl;
}
static void onFinish(void * me, int32_t result){
NaclRequestOpen * self = (NaclRequestOpen*) me;
self->finish(result);
}
void finish(int32_t result);
pp::URLRequestInfo request;
pp::URLLoader loader;
string url;
Manager * manager;
};
struct NaclRequestRead: public NaclRequest {
NaclRequestRead(pp::URLLoader & loader, Manager * manager, void * buffer, int read):
loader(loader),
manager(manager),
buffer(buffer),
read(read){
}
void start(){
pp::CompletionCallback callback(&NaclRequestRead::onFinish, this);
int32_t ok = loader.ReadResponseBody(buffer, read, callback);
Global::debug(1) << "Read " << ok << std::endl;
if (ok != PP_OK_COMPLETIONPENDING){
// Global::debug(0) << "Call on main thread" << std::endl;
// core->CallOnMainThread(0, callback, ok);
callback.Run(ok);
}
Global::debug(1) << "Callback running" << std::endl;
}
static void onFinish(void * me, int32_t result){
NaclRequestRead * self = (NaclRequestRead*) me;
self->finish(result);
}
void finish(int32_t result);
pp::URLLoader loader;
Manager * manager;
void * buffer;
int read;
};
class FileHandle{
public:
FileHandle(const Util::ReferenceCount<NaclRequestOpen> & open):
open(open),
buffer(NULL){
}
~FileHandle(){
delete[] buffer;
}
pp::URLLoader & getLoader(){
return open->loader;
}
class Reader{
public:
static const int PAGE_SIZE = 1024 * 32;
struct Page{
Page():
buffer(NULL),
size(0),
next(NULL){
buffer = new char[PAGE_SIZE];
}
char * buffer;
int size;
Page * next;
~Page(){
delete[] buffer;
delete next;
}
};
Reader(pp::CompletionCallback finish, pp::URLLoader & loader, FileHandle * handle, pp::Core * core):
finish(finish),
loader(loader),
handle(handle),
core(core),
tries(0){
current = &page;
}
int getSize(){
Page * use = &page;
int total = 0;
while (use != NULL){
total += use->size;
use = use->next;
}
return total;
}
void copy(char * buffer){
Page * use = &page;
while (use != NULL){
memcpy(buffer, use->buffer, use->size);
buffer += use->size;
use = use->next;
}
}
void read(){
pp::CompletionCallback callback(&Reader::onRead, this);
if (current->size == PAGE_SIZE){
Page * next = new Page();
current->next = next;
current = next;
}
int32_t ok = loader.ReadResponseBody(current->buffer + current->size, PAGE_SIZE - current->size, callback);
if (ok != PP_OK_COMPLETIONPENDING){
callback.Run(ok);
}
}
static void onRead(void * self, int32_t result){
Reader * reader = (Reader*) self;
reader->didRead(result);
}
void didRead(int32_t result){
Global::debug(1) << "Read " << result << " bytes" << std::endl;
current->size += result;
if (result > 0){
tries = 0;
read();
} else {
if (tries >= 2){
handle->readDone(this);
} else {
tries += 1;
pp::CompletionCallback callback(&Reader::doRead, this);
core->CallOnMainThread(50, callback, 0);
}
}
}
static void doRead(void * self, int32_t result){
Reader * reader = (Reader*) self;
reader->read();
}
pp::CompletionCallback finish;
pp::URLLoader & loader;
Page page;
Page * current;
FileHandle * handle;
pp::Core * core;
int tries;
};
void readAll(pp::CompletionCallback finish, pp::Core * core){
reader = new Reader(finish, open->loader, this, core);
reader->read();
}
void readDone(Reader * reader){
length = reader->getSize();
Global::debug(1) << "Done reading, got " << length << " bytes" << std::endl;
position = 0;
buffer = new char[length];
reader->copy(buffer);
reader->finish.Run(0);
}
int read(void * buffer, size_t count){
size_t bytes = position + count < length ? count : (length - position);
memcpy(buffer, this->buffer + position, bytes);
position += bytes;
return bytes;
}
off_t seek(off_t offset, int whence){
switch (whence){
case SEEK_SET: {
position = offset;
break;
}
case SEEK_CUR: {
position += offset;
break;
}
case SEEK_END: {
- position = length - offset - 1;
+ position = length - offset;
break;
}
}
return position;
}
Util::ReferenceCount<NaclRequestOpen> open;
off_t position;
off_t length;
char * buffer;
Util::ReferenceCount<Reader> reader;
};
class Manager{
public:
Manager(pp::Instance * instance, pp::Core * core):
instance(instance),
core(core),
factory(this){
next = 2;
}
pp::Instance * instance;
pp::Core * core;
Util::ReferenceCount<NaclRequest> request;
pp::CompletionCallbackFactory<Manager> factory;
map<int, Util::ReferenceCount<FileHandle> > fileTable;
int next;
struct OpenFileData{
const char * path;
int file;
};
struct ReadFileData{
int file;
void * buffer;
/* how much to read */
int count;
/* how much was read */
int read;
};
struct CloseFileData{
int fd;
};
OpenFileData openFileData;
ReadFileData readFileData;
CloseFileData closeFileData;
Util::Thread::LockObject lock;
volatile bool done;
int openFile(const char * path){
Global::debug(1, CONTEXT) << "open " << path << std::endl;
Util::Thread::ScopedLock scoped(lock);
done = false;
openFileData.path = path;
openFileData.file = -1;
pp::CompletionCallback callback(&Manager::doOpenFile, this);
core->CallOnMainThread(0, callback, 0);
lock.wait(done);
return openFileData.file;
}
bool exists(const string & path){
Global::debug(1, CONTEXT) << "exists " << path << std::endl;
Util::Thread::ScopedLock scoped(lock);
done = false;
openFileData.path = path.c_str();
openFileData.file = -1;
pp::CompletionCallback callback(&Manager::doOpenFile, this);
core->CallOnMainThread(0, callback, 0);
lock.wait(done);
return openFileData.file != -1;
}
off_t lseek(int fd, off_t offset, int whence){
Global::debug(2, CONTEXT) << "seek fd " << fd << " offset " << offset << " whence " << whence << std::endl;
Util::Thread::ScopedLock scoped(lock);
if (fileTable.find(fd) == fileTable.end()){
return -1;
}
Util::ReferenceCount<FileHandle> handle = fileTable[fd];
return handle->seek(offset, whence);
}
int close(int fd){
Util::Thread::ScopedLock scoped(lock);
if (fileTable.find(fd) == fileTable.end()){
return -1;
/* set errno to EBADF */
}
done = false;
closeFileData.fd = fd;
pp::CompletionCallback callback(&Manager::doCloseFile, this);
core->CallOnMainThread(0, callback, 0);
lock.wait(done);
return 0;
}
static void doCloseFile(void * self, int32_t result){
Manager * manager = (Manager*) self;
manager->continueCloseFile();
}
/* the destructor for the NaclRequestOpen has to occur in the main thread */
void continueCloseFile(){
fileTable.erase(fileTable.find(closeFileData.fd));
requestComplete();
}
ssize_t readFile(int fd, void * buffer, size_t count){
Util::Thread::ScopedLock scoped(lock);
if (fileTable.find(fd) == fileTable.end()){
return EBADF;
}
/* dont need to sleep on a condition variable because we are
* in the game thread.
*/
Util::ReferenceCount<FileHandle> handle = fileTable[fd];
return handle->read(buffer, count);
/*
done = false;
readFileData.file = fd;
readFileData.buffer = buffer;
readFileData.count = count;
readFileData.read = 0;
pp::CompletionCallback callback(&Manager::doReadFile, this);
core->CallOnMainThread(0, callback, 0);
lock.wait(done);
return readFileData.read;
*/
}
static void doReadFile(void * self, int32_t result){
Manager * manager = (Manager*) self;
manager->continueReadFile();
}
void continueReadFile(){
/* hack to get the open request.. */
Util::ReferenceCount<FileHandle> open = fileTable[readFileData.file];
request = new NaclRequestRead(open->getLoader(), this, readFileData.buffer, readFileData.count);
request->start();
}
/* called by the main thread */
static void doOpenFile(void * self, int32_t result){
Manager * manager = (Manager*) self;
manager->continueOpenFile();
}
void continueOpenFile(){
request = new NaclRequestOpen(instance, openFileData.path, this);
request->start();
}
int nextFileDescriptor(){
int n = next;
next += 1;
return n;
}
void requestComplete(){
/* delete the reference counted request object in the main thread */
request = NULL;
lock.lockAndSignal(done, true);
}
void success(NaclRequestOpen & open){
pp::URLResponseInfo info = open.loader.GetResponseInfo();
if (info.GetStatusCode() == 200){
+ Global::debug(1) << "Opened file" << std::endl;
/*
int64_t received = 0;
int64_t total = 0;
if (open.loader.GetDownloadProgress(&received, &total)){
Global::debug(0) << "Downloaded " << received << " total " << total << std::endl;
}
*/
openFileData.file = nextFileDescriptor();
fileTable[openFileData.file] = new FileHandle(request.convert<NaclRequestOpen>());
readEntireFile(fileTable[openFileData.file]);
} else {
+ Global::debug(1) << "Could not open file" << std::endl;
openFileData.file = -1;
requestComplete();
}
}
void readEntireFile(Util::ReferenceCount<FileHandle> & file){
pp::CompletionCallback callback(&Manager::completeRead, this);
file->readAll(callback, core);
}
static void completeRead(void * self, int32_t result){
Manager * manager = (Manager*) self;
manager->requestComplete();
}
void failure(NaclRequestOpen & open){
openFileData.file = -1;
requestComplete();
}
void success(NaclRequestRead & request, int read){
readFileData.read = read;
requestComplete();
}
};
void NaclRequestOpen::finish(int32_t result){
if (result == 0){
manager->success(*this);
} else {
manager->failure(*this);
}
}
void NaclRequestRead::finish(int32_t result){
manager->success(*this, result);
}
NetworkSystem::NetworkSystem(const string & serverPath, pp::Instance * instance, pp::Core * core):
instance(instance),
serverPath(serverPath),
manager(new Manager(instance, core)){
}
/* TODO */
NetworkSystem::~NetworkSystem(){
}
/* TODO */
AbsolutePath NetworkSystem::find(const RelativePath & path){
return Util::getDataPath2().join(path);
}
/* TODO */
RelativePath NetworkSystem::cleanse(const AbsolutePath & path){
return RelativePath();
}
bool NetworkSystem::exists(const RelativePath & path){
try{
AbsolutePath absolute = find(path);
return true;
} catch (const Storage::NotFound & found){
return false;
}
}
/*
class Handler{
public:
Handler(pp::Instance * instance, const AbsolutePath & path, NetworkSystem * system):
request(instance),
loader(instance),
factory(this),
http(false),
system(system){
request.SetURL(path.path());
request.SetMethod("GET");
}
virtual void start(){
pp::CompletionCallback callback = factory.NewCallback(&Handler::OnOpen);
int32_t ok = loader.Open(request, callback);
Global::debug(0) << "Open " << ok << std::endl;
if (ok != PP_OK_COMPLETIONPENDING){
callback.Run(ok);
}
Global::debug(0) << "Callback running" << std::endl;
}
virtual void OnOpen(int32_t ok){
Global::debug(0) << "Opened! " << ok << std::endl;
system->run2();
}
pp::URLRequestInfo request;
pp::URLLoader loader;
pp::CompletionCallbackFactory<Handler> factory;
volatile bool http;
NetworkSystem * system;
};
*/
/*
void NetworkSystem::run(){
// manager->run();
Util::Thread::Id thread;
Util::Thread::createThread(&thread, NULL, &Manager::run, manager);
// manager->run();
}
*/
bool NetworkSystem::exists(const AbsolutePath & path){
/*
Global::debug(0) << "Checking for " << path.path() << std::endl;
pp::CompletionCallback::Block blocking;
pp::CompletionCallback callback(blocking);
pp::URLRequestInfo request(instance);
pp::URLLoader loader(instance);
string url = serverPath + path.path();
Global::debug(0) << "Url: " << url << std::endl;
// request.SetURL(serverPath + path.path());
request.SetURL("/" + path.path());
request.SetMethod("GT");
int32_t ok = loader.Open(request, callback);
Global::debug(0) << "Ok: " << ok << std::endl;
if (ok == PP_OK){
return true;
} else {
return false;
}
*/
return manager->exists(path.path());
#if 0
Global::debug(0) << "Getting portal lock" << std::endl;
if (portal.acquire() != 0){
Global::debug(0) << "Lock failed!" << std::endl;
}
/*
Global::debug(0) << "Getting portal lock again" << std::endl;
if (portal.acquire() != 0){
Global::debug(0) << "Lock failed again!" << std::endl;
}
Global::debug(0) << "Somehow got the portal lock twice??" << std::endl;
*/
operation.type = Exists;
operation.absolute = path;
operation.complete = false;
operation.success = false;
Global::debug(0) << "Request open" << std::endl;
run();
// portal.signal();
Global::debug(0) << "Waiting on portal" << std::endl;
portal.wait(operation.complete);
portal.release();
Global::debug(0) << "Request open complete" << std::endl;
return operation.success;
/*
Handler handler(instance, path);
handler.start();
handler.wait();
return false;
*/
#endif
}
/* TODO */
std::vector<AbsolutePath> NetworkSystem::getFilesRecursive(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive){
std::vector<AbsolutePath> paths;
return paths;
}
/* TODO */
std::vector<AbsolutePath> NetworkSystem::getFiles(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive){
std::vector<AbsolutePath> paths;
return paths;
}
/* TODO */
AbsolutePath NetworkSystem::configFile(){
return AbsolutePath("paintownrc");
}
/* TODO */
AbsolutePath NetworkSystem::userDirectory(){
return AbsolutePath("paintownrc");
}
/* TODO */
std::vector<AbsolutePath> NetworkSystem::findDirectories(const RelativePath & path){
return std::vector<AbsolutePath>();
}
/* TODO */
AbsolutePath NetworkSystem::findInsensitive(const RelativePath & path){
return AbsolutePath();
}
/* TODO */
AbsolutePath NetworkSystem::lookupInsensitive(const AbsolutePath & directory, const RelativePath & path){
return AbsolutePath();
}
int NetworkSystem::libcOpen(const char * path, int mode, int params){
return manager->openFile(path);
}
ssize_t NetworkSystem::libcRead(int fd, void * buf, size_t count){
return manager->readFile(fd, buf, count);
}
int NetworkSystem::libcClose(int fd){
return manager->close(fd);
}
off_t NetworkSystem::libcLseek(int fd, off_t offset, int whence){
return manager->lseek(fd, offset, whence);
}
}
/* NOTE FIXME Missing I/O in Native Client */
Nacl::NetworkSystem & getSystem(){
return (Nacl::NetworkSystem&) Storage::instance();
}
extern "C" {
/* http://sourceware.org/binutils/docs-2.21/ld/Options.html#index-g_t_002d_002dwrap_003d_0040var_007bsymbol_007d-261
* --wrap=symbol
* Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to __wrap_symbol. Any undefined reference to __real_symbol will be resolved to symbol.
*/
int __wrap_open(const char * path, int mode, int params){
return getSystem().libcOpen(path, mode, params);
}
ssize_t __wrap_read(int fd, void * buf, size_t count){
return getSystem().libcRead(fd, buf, count);
}
extern int __real_close(int fd);
int __wrap_close(int fd){
/* we may be given a file descriptor that we do not own, probably
* because some file descriptors are really tied to sockets so
* if we don't own the fd then pass it to the real close function.
*/
int ok = getSystem().libcClose(fd);
if (ok == -1){
return __real_close(fd);
}
return ok;
}
off_t __wrap_lseek(int fd, off_t offset, int whence){
return getSystem().libcLseek(fd, offset, whence);
}
int pipe (int filedes[2]){
return -1;
}
int mkdir (const char *filename, mode_t mode){
return -1;
}
int access(const char *filename, int how){
return -1;
}
char * getcwd (char *buffer, size_t size){
return NULL;
}
int lstat (const char *path, struct stat *buf){
return -1;
}
int rmdir (const char *filename){
return -1;
}
int chdir (const char *filename){
return -1;
}
int setuid (uid_t newuid){
return 0;
}
int seteuid (uid_t uid){
return 0;
}
uid_t geteuid (void){
return NULL;
}
int setgid (gid_t gid){
return 0;
}
gid_t getgid (void){
return NULL;
}
int setegid (gid_t gid){
return 0;
}
gid_t getegid (void){
return NULL;
}
char * getlogin (void){
return NULL;
}
uid_t getuid(void){
return NULL;
}
struct passwd * getpwuid (uid_t uid){
return NULL;
}
struct passwd * getpwnam (const char *name){
return NULL;
}
struct group * getgrnam(const char *name){
return NULL;
}
struct group * getgrgid(gid_t gid){
return NULL;
}
int link (const char *oldname, const char *newname){
return -1;
}
int unlink (const char *filename){
return -1;
}
int kill(pid_t pid, int sig){
return -1;
}
}
#endif
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jun 11, 10:24 AM (3 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
68389
Default Alt Text
(48 KB)
Attached To
Mode
R75 R-Tech1
Attached
Detach File
Event Timeline