Refactor program info log out of ProgramBinary and in to Program.

Tested by setting breakpoint in esLoadProgram with the broken program.
Review URL: https://codereview.appspot.com/6305114

git-svn-id: https://angleproject.googlecode.com/svn/trunk@1164 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/Program.cpp b/src/libGLESv2/Program.cpp
index 184a02c..f28a9d8 100644
--- a/src/libGLESv2/Program.cpp
+++ b/src/libGLESv2/Program.cpp
@@ -20,6 +20,8 @@
 
 namespace gl
 {
+const char * const g_fakepath = "C:\\fakepath";
+
 unsigned int Program::mCurrentSerial = 1;
 
 AttributeBindings::AttributeBindings()
@@ -30,6 +32,112 @@
 {
 }
 
+InfoLog::InfoLog() : mInfoLog(NULL)
+{
+}
+
+InfoLog::~InfoLog()
+{
+    delete[] mInfoLog;
+}
+
+
+int InfoLog::getLength() const
+{
+    if (!mInfoLog)
+    {
+        return 0;
+    }
+    else
+    {
+       return strlen(mInfoLog) + 1;
+    }
+}
+
+void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
+{
+    int index = 0;
+
+    if (bufSize > 0)
+    {
+        if (mInfoLog)
+        {
+            index = std::min(bufSize - 1, (int)strlen(mInfoLog));
+            memcpy(infoLog, mInfoLog, index);
+        }
+
+        infoLog[index] = '\0';
+    }
+
+    if (length)
+    {
+        *length = index;
+    }
+}
+
+// append a santized message to the program info log.
+// The D3D compiler includes a fake file path in some of the warning or error 
+// messages, so lets remove all occurrences of this fake file path from the log.
+void InfoLog::appendSanitized(const char *message)
+{
+    std::string msg(message);
+
+    size_t found;
+    do
+    {
+        found = msg.find(g_fakepath);
+        if (found != std::string::npos)
+        {
+            msg.erase(found, strlen(g_fakepath));
+        }
+    }
+    while (found != std::string::npos);
+
+    append("%s\n", msg.c_str());
+}
+
+void InfoLog::append(const char *format, ...)
+{
+    if (!format)
+    {
+        return;
+    }
+
+    char info[1024];
+
+    va_list vararg;
+    va_start(vararg, format);
+    vsnprintf(info, sizeof(info), format, vararg);
+    va_end(vararg);
+
+    size_t infoLength = strlen(info);
+
+    if (!mInfoLog)
+    {
+        mInfoLog = new char[infoLength + 1];
+        strcpy(mInfoLog, info);
+    }
+    else
+    {
+        size_t logLength = strlen(mInfoLog);
+        char *newLog = new char[logLength + infoLength + 1];
+        strcpy(newLog, mInfoLog);
+        strcpy(newLog + logLength, info);
+
+        delete[] mInfoLog;
+        mInfoLog = newLog;
+    }
+}
+
+void InfoLog::reset()
+{
+    if (mInfoLog)
+    {
+        delete [] mInfoLog;
+        mInfoLog = NULL;
+    }
+}
+
 Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle), mSerial(issueSerial())
 {
     mFragmentShader = NULL;
@@ -138,8 +246,10 @@
 {
     unlink(false);
 
+    mInfoLog.reset();
+
     mProgramBinary = new ProgramBinary;
-    if (!mProgramBinary->link(mAttributeBindings, mFragmentShader, mVertexShader))
+    if (!mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader))
     {
         unlink(false);
     }
@@ -226,34 +336,12 @@
 
 int Program::getInfoLogLength() const
 {
-    if (mProgramBinary)
-    {
-        return mProgramBinary->getInfoLogLength();
-    }
-    else
-    {
-       return 0;
-    }
+    return mInfoLog.getLength();
 }
 
 void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
 {
-    if (mProgramBinary)
-    {
-        return mProgramBinary->getInfoLog(bufSize, length, infoLog);
-    }
-    else
-    {
-        if (bufSize > 0)
-        {
-            infoLog[0] = '\0';
-        }
-
-        if (length)
-        {
-            *length = 0;
-        }
-    }
+    return mInfoLog.getLog(bufSize, length, infoLog);
 }
 
 void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
@@ -390,6 +478,20 @@
     return mDeleteStatus;
 }
 
+void Program::validate()
+{
+    mInfoLog.reset();
+
+    if (mProgramBinary)
+    {
+        mProgramBinary->validate(mInfoLog);
+    }
+    else
+    {
+        mInfoLog.append("Program has not been successfully linked.");
+    }
+}
+
 bool Program::isValidated() const
 {
     if (mProgramBinary)